简体   繁体   English

THREE.JS | GLSL 如何将 canvas 纹理拆分到多个平面

[英]THREE.JS | GLSL How to split canvas texture to multiple planes

I have a small demo, there I have multiple planes stacked together inside 1024x1024 area.我有一个小演示,在 1024x1024 区域内我有多个平面堆叠在一起。 The task it to evenly split 1024x1024 animated canvas texture, so I would get the following result:它均匀分割 1024x1024 动画 canvas 纹理的任务,所以我会得到以下结果:

在此处输入图像描述

Not this:不是这个:

在此处输入图像描述

So, I have somehow to pass to their shaders material which part from canvas texture I need to crop.所以,我必须以某种方式传递给他们的着色器材料,这些材料来自我需要裁剪的 canvas 纹理。 And I don't know how to do it.而且我不知道该怎么做。

The current code is attached here.当前代码附在此处。

The following answer is great, but I have to use glsl for these planes, so this solution could fit other tasks, not mine.以下答案很好,但我必须对这些飞机使用 glsl,所以这个解决方案可以适合其他任务,而不是我的。

 var renderer, scene, camera, controls, glslMaterial, uniforms, canvas, ctx, markupTexture, t = 0.0; inits(); function inits(){ canvas = document.createElement("canvas") canvas.width = 1024 * 2; canvas.height = 1024 * 2; ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#00FFFF"; ctx.fillRect(0, 0, canvas.width, canvas.height); markupTexture = new THREE.CanvasTexture(canvas); //markupTexture.flipX = false; //markupTexture.flipY = false; renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setClearColor(0x000000); document.body.appendChild( renderer.domElement ); scene = new THREE.Scene(); var light = new THREE.HemisphereLight( 0xFFFFFF, 0x080820, 2.0 ); scene.add( light ); camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 5120 ); camera.position.set(-200, 400, 400); controls = new THREE.OrbitControls(camera, renderer.domElement); var markupGeometry = new THREE.PlaneGeometry(1024, 1024, 64, 64); var markupPlane = new THREE.Mesh(markupGeometry, new THREE.MeshBasicMaterial({ color: 0xFFFFFF, map: markupTexture, side: THREE.DoubleSide })); markupPlane.rotation.set(-Math.PI / 2, 0, 0); markupPlane.position.set(0, 1, 0); //scene.add(markupPlane); var uniforms = { markup: { type: 't', value: markupTexture } }; glslMaterial = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: document.getElementById('vertexShader').textContent, fragmentShader: document.getElementById('fragmentShader').textContent //side: new THREE.DoubleSide }); var geometry = new THREE.PlaneGeometry(512, 512, 64, 64); var plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane0"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(256, 0, -256) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane1"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(384, 0, 128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane2"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(128, 0, 128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane3"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(128, 0, 384) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane4"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(384, 0, 384) scene.add(plane); geometry = new THREE.PlaneGeometry(512, 512, 64, 64); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane5"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-256, 0, 256) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane6"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-384, 0, -128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane7"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-128, 0, -128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane8"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-128, 0, -384) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane9"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-384, 0, -384) scene.add(plane); window.addEventListener( "resize", onWindowResize, false ); animate(); } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); } function animate() { ctx.imageSmoothingEnabled = true; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#FFFF00"; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.beginPath(); ctx.arc(1024, 1024, 640, 0, 2 * Math.PI); ctx.strokeStyle = "#FF00FF"; ctx.lineWidth = 16.0; ctx.stroke(); ctx.beginPath(); ctx.moveTo(1024, 1024); ctx.arc(1024, 1024, 640, t - Math.PI / 8, t + Math.PI / 8, false); ctx.lineTo(1024, 1024); ctx.fillStyle = "#FF00FF"; ctx.fill(); controls.update(); requestAnimationFrame( animate ); renderer.render( scene, camera ); for(var i = 0; i < 10; i++){ scene.getObjectByName("plane" + i).material.uniforms.markup.needsUpdate = true; } //glslMaterial.uniforms.markup.needsUpdate = true; markupTexture.needsUpdate = true; t += 0.05; }
 body { margin: 0px; }
 <.DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4:01 Transitional//EN" "http.//www.w3.org/TR/html4/loose:dtd"> <html> <head> <title></title> <script src="https.//unpkg.com/three@0.85.0/build/three.min:js"></script> <script src="https.//unpkg.com/three@0.85.0/examples/js/controls/OrbitControls;js"></script> </head> <body> <script id="vertexShader" type="x-shader/x-vertex"> varying vec2 vUv; void main() { vUv = uv, gl_Position = projectionMatrix * modelViewMatrix * vec4(position.1;0); } </script> <script id="fragmentShader" type="x-shader/x-fragment"> uniform sampler2D markup; varying vec2 vUv, void main() { gl_FragColor = texture2D(markup; vUv); } </script> </body> </html>

You don't need a custom shader.您不需要自定义着色器。 You just need to set the texture coordinates for each plane.您只需要为每个平面设置纹理坐标。

Here's a function to scale and offset the texture coordinates这是一个 function 来缩放和偏移纹理坐标

function offsetUVs(geometry, offU, offV, scaleU, scaleV) {
  const off = new THREE.Vector2(offU, offV);
  const scale = new THREE.Vector2(scaleU, scaleV);
  for(const uvs of geometry.faceVertexUvs[0]) {
    for (const uv of uvs) {
      uv.multiply(scale);
      uv.add(off);
    }
  }
}

If you set the scale to 0.25, 0.25 then one 16th of the texture will appear on that plane (as in if the texture was divided into a 4x4 grid)如果将比例设置为 0.25、0.25,则该平面上将出现 16 分之一的纹理(就像纹理被划分为 4x4 网格一样)

The offset will move the texture where 1 is the full length of the texture, 0.5 is half the length, 0.25 is a quarter of the length偏移量将移动纹理,其中 1 是纹理的全长,0.5 是长度的一半,0.25 是长度的四分之一

 var renderer, scene, camera, controls, glslMaterial, uniforms, canvas, ctx, markupTexture, t = 0.0; inits(); function inits(){ canvas = document.createElement("canvas") canvas.width = 1024 * 2; canvas.height = 1024 * 2; ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#00FFFF"; ctx.fillRect(0, 0, canvas.width, canvas.height); markupTexture = new THREE.CanvasTexture(canvas); //markupTexture.flipX = false; //markupTexture.flipY = false; renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setClearColor(0x000000); document.body.appendChild( renderer.domElement ); scene = new THREE.Scene(); var light = new THREE.HemisphereLight( 0xFFFFFF, 0x080820, 2.0 ); scene.add( light ); camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 5120 ); camera.position.set(-200, 400, 400); controls = new THREE.OrbitControls(camera, renderer.domElement); var markupGeometry = new THREE.PlaneGeometry(1024, 1024, 64, 64); var markupPlane = new THREE.Mesh(markupGeometry, new THREE.MeshBasicMaterial({ color: 0xFFFFFF, map: markupTexture, side: THREE.DoubleSide })); markupPlane.rotation.set(-Math.PI / 2, 0, 0); markupPlane.position.set(0, 1, 0); //scene.add(markupPlane); /*glslMaterial = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: document.getElementById('vertexShader').textContent, fragmentShader: document.getElementById('fragmentShader').textContent //side: new THREE.DoubleSide }); */ const simple = new THREE.MeshBasicMaterial({ color: 0xFFFFFF, map: markupTexture, side: THREE.DoubleSide }); var geometry = new THREE.PlaneGeometry(512, 512, 64, 64); offsetUVs(geometry, 0.5, 0.5, 0.5, 0.5); var plane = new THREE.Mesh(geometry, simple); plane.name = "plane0"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(256, 0, -256) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.75, 0.25, 0.25, 0.25); plane = new THREE.Mesh(geometry, simple); plane.name = "plane1"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(384, 0, 128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.5, 0.25, 0.25, 0.25); plane = new THREE.Mesh(geometry, simple); plane.name = "plane2"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(128, 0, 128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.5, 0, 0.25, 0.25); plane = new THREE.Mesh(geometry, simple); plane.name = "plane3"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(128, 0, 384) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.75, 0, 0.25, 0.25); plane = new THREE.Mesh(geometry, simple); plane.name = "plane4"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(384, 0, 384) scene.add(plane); geometry = new THREE.PlaneGeometry(512, 512, 64, 64); offsetUVs(geometry, 0, 0, 0.5, 0.5); plane = new THREE.Mesh(geometry, simple); plane.name = "plane5"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-256, 0, 256) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.0, 0.5, 0.25, 0.25); plane = new THREE.Mesh(geometry, simple); plane.name = "plane6"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-384, 0, -128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.25, 0.5, 0.25, 0.25); plane = new THREE.Mesh(geometry, simple); plane.name = "plane7"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-128, 0, -128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.25, 0.75, 0.25, 0.25); plane = new THREE.Mesh(geometry, simple); plane.name = "plane8"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-128, 0, -384) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.0, 0.75, 0.25, 0.25); plane = new THREE.Mesh(geometry, simple); plane.name = "plane9"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-384, 0, -384) scene.add(plane); window.addEventListener( "resize", onWindowResize, false ); animate(); } function offsetUVs(geometry, offU, offV, scaleU, scaleV) { const off = new THREE.Vector2(offU, offV); const scale = new THREE.Vector2(scaleU, scaleV); for(const uvs of geometry.faceVertexUvs[0]) { for (const uv of uvs) { uv.multiply(scale); uv.add(off); } } } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); } function animate() { ctx.imageSmoothingEnabled = true; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#FFFF00"; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.beginPath(); ctx.arc(1024, 1024, 940, 0, 2 * Math.PI); ctx.strokeStyle = "#FF00FF"; ctx.lineWidth = 16.0; ctx.stroke(); ctx.beginPath(); ctx.moveTo(1024, 1024); ctx.arc(1024, 1024, 940, t - Math.PI / 8, t + Math.PI / 8, false); ctx.lineTo(1024, 1024); ctx.fillStyle = "#FF00FF"; ctx.fill(); markupTexture.needsUpdate = true; controls.update(); requestAnimationFrame( animate ); renderer.render( scene, camera ); t += 0.05; }
 body { margin: 0px; }
 <.DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4:01 Transitional//EN" "http.//www.w3.org/TR/html4/loose:dtd"> <html> <head> <title></title> <script src="https.//unpkg.com/three@0.85.0/build/three.min:js"></script> <script src="https.//unpkg.com/three@0.85.0/examples/js/controls/OrbitControls.js"></script> </head> <body> </body> </html>

Ps: I made the circle bigger so it touched all the planes otherwise 2 corners were solid yellow so it was hard to see if they were correct. Ps:我把圆圈变大了,所以它接触了所有的平面,否则 2 个角是纯黄色的,所以很难看出它们是否正确。

See this article as a reference for the structure of geometry这篇文章作为几何结构的参考

The same solution will work just fine with your custom shader as well同样的解决方案也适用于您的自定义着色器

 var renderer, scene, camera, controls, glslMaterial, uniforms, canvas, ctx, markupTexture, t = 0.0; inits(); function inits(){ canvas = document.createElement("canvas") canvas.width = 1024 * 2; canvas.height = 1024 * 2; ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#00FFFF"; ctx.fillRect(0, 0, canvas.width, canvas.height); markupTexture = new THREE.CanvasTexture(canvas); //markupTexture.flipX = false; //markupTexture.flipY = false; renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setClearColor(0x000000); document.body.appendChild( renderer.domElement ); scene = new THREE.Scene(); var light = new THREE.HemisphereLight( 0xFFFFFF, 0x080820, 2.0 ); scene.add( light ); camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 5120 ); camera.position.set(-200, 400, 400); controls = new THREE.OrbitControls(camera, renderer.domElement); var markupGeometry = new THREE.PlaneGeometry(1024, 1024, 64, 64); var markupPlane = new THREE.Mesh(markupGeometry, new THREE.MeshBasicMaterial({ color: 0xFFFFFF, map: markupTexture, side: THREE.DoubleSide })); markupPlane.rotation.set(-Math.PI / 2, 0, 0); markupPlane.position.set(0, 1, 0); //scene.add(markupPlane); var uniforms = { markup: { type: 't', value: markupTexture } }; glslMaterial = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: document.getElementById('vertexShader').textContent, fragmentShader: document.getElementById('fragmentShader').textContent //side: new THREE.DoubleSide }); var geometry = new THREE.PlaneGeometry(512, 512, 64, 64); offsetUVs(geometry, 0.5, 0.5, 0.5, 0.5); var plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane0"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(256, 0, -256) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.75, 0.25, 0.25, 0.25); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane1"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(384, 0, 128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.5, 0.25, 0.25, 0.25); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane2"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(128, 0, 128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.5, 0, 0.25, 0.25); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane3"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(128, 0, 384) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.75, 0, 0.25, 0.25); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane4"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(384, 0, 384) scene.add(plane); geometry = new THREE.PlaneGeometry(512, 512, 64, 64); offsetUVs(geometry, 0, 0, 0.5, 0.5); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane5"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-256, 0, 256) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.0, 0.5, 0.25, 0.25); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane6"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-384, 0, -128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.25, 0.5, 0.25, 0.25); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane7"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-128, 0, -128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.25, 0.75, 0.25, 0.25); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane8"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-128, 0, -384) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); offsetUVs(geometry, 0.0, 0.75, 0.25, 0.25); plane = new THREE.Mesh(geometry, glslMaterial); plane.name = "plane9"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-384, 0, -384) scene.add(plane); window.addEventListener( "resize", onWindowResize, false ); animate(); } function offsetUVs(geometry, offU, offV, scaleU, scaleV) { const off = new THREE.Vector2(offU, offV); const scale = new THREE.Vector2(scaleU, scaleV); for(const uvs of geometry.faceVertexUvs[0]) { for (const uv of uvs) { uv.multiply(scale); uv.add(off); } } } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); } function animate() { ctx.imageSmoothingEnabled = true; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#FFFF00"; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.beginPath(); ctx.arc(1024, 1024, 940, 0, 2 * Math.PI); ctx.strokeStyle = "#FF00FF"; ctx.lineWidth = 16.0; ctx.stroke(); ctx.beginPath(); ctx.moveTo(1024, 1024); ctx.arc(1024, 1024, 940, t - Math.PI / 8, t + Math.PI / 8, false); ctx.lineTo(1024, 1024); ctx.fillStyle = "#FF00FF"; ctx.fill(); markupTexture.needsUpdate = true; controls.update(); requestAnimationFrame( animate ); renderer.render( scene, camera ); t += 0.05; }
 body { margin: 0px; }
 <.DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4:01 Transitional//EN" "http.//www.w3.org/TR/html4/loose:dtd"> <html> <head> <title></title> <script src="https.//unpkg.com/three@0.85.0/build/three.min:js"></script> <script src="https.//unpkg.com/three@0.85.0/examples/js/controls/OrbitControls;js"></script> <script id="vertexShader" type="x-shader/x-vertex"> varying vec2 vUv; void main() { vUv = uv, gl_Position = projectionMatrix * modelViewMatrix * vec4(position.1;0); } </script> <script id="fragmentShader" type="x-shader/x-fragment"> uniform sampler2D markup; varying vec2 vUv, void main() { gl_FragColor = texture2D(markup; vUv); } </script> </head> <body> </body> </html>

you can also do the same uv manipulation in the shader but you'll need to create a new material for each plane so you can pass in a different offset and scale for each one.您也可以在着色器中进行相同的 uv 操作,但您需要为每个平面创建一个新材质,以便您可以为每个平面传递不同的偏移和缩放。

 var renderer, scene, camera, controls, glslMaterial, uniforms, canvas, ctx, markupTexture, t = 0.0; inits(); function inits(){ canvas = document.createElement("canvas") canvas.width = 1024 * 2; canvas.height = 1024 * 2; ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#00FFFF"; ctx.fillRect(0, 0, canvas.width, canvas.height); markupTexture = new THREE.CanvasTexture(canvas); //markupTexture.flipX = false; //markupTexture.flipY = false; renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setClearColor(0x000000); document.body.appendChild( renderer.domElement ); scene = new THREE.Scene(); var light = new THREE.HemisphereLight( 0xFFFFFF, 0x080820, 2.0 ); scene.add( light ); camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 5120 ); camera.position.set(-200, 400, 400); controls = new THREE.OrbitControls(camera, renderer.domElement); var markupGeometry = new THREE.PlaneGeometry(1024, 1024, 64, 64); var markupPlane = new THREE.Mesh(markupGeometry, new THREE.MeshBasicMaterial({ color: 0xFFFFFF, map: markupTexture, side: THREE.DoubleSide })); markupPlane.rotation.set(-Math.PI / 2, 0, 0); markupPlane.position.set(0, 1, 0); //scene.add(markupPlane); function createMaterial(offX, offY, scaleX, scaleY) { var uniforms = { uvOffset: { value: new THREE.Vector2(offX, offY) }, uvScale: { value: new THREE.Vector2(scaleX, scaleY) }, markup: { type: 't', value: markupTexture } }; return new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: document.getElementById('vertexShader').textContent, fragmentShader: document.getElementById('fragmentShader').textContent //side: new THREE.DoubleSide }); } var geometry = new THREE.PlaneGeometry(512, 512, 64, 64); var plane = new THREE.Mesh(geometry, createMaterial(0.5, 0.5, 0.5, 0.5)); plane.name = "plane0"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(256, 0, -256) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, createMaterial(0.75, 0.25, 0.25, 0.25)); plane.name = "plane1"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(384, 0, 128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, createMaterial(0.5, 0.25, 0.25, 0.25)); plane.name = "plane2"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(128, 0, 128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, createMaterial(0.5, 0, 0.25, 0.25)); plane.name = "plane3"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(128, 0, 384) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, createMaterial(0.75, 0, 0.25, 0.25)); plane.name = "plane4"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(384, 0, 384) scene.add(plane); geometry = new THREE.PlaneGeometry(512, 512, 64, 64); plane = new THREE.Mesh(geometry, createMaterial(0, 0, 0.5, 0.5)); plane.name = "plane5"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-256, 0, 256) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, createMaterial(0.0, 0.5, 0.25, 0.25)); plane.name = "plane6"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-384, 0, -128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, createMaterial(0.25, 0.5, 0.25, 0.25)); plane.name = "plane7"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-128, 0, -128) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, createMaterial(0.25, 0.75, 0.25, 0.25)); plane.name = "plane8"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-128, 0, -384) scene.add(plane); geometry = new THREE.PlaneGeometry(256, 256, 32, 32); plane = new THREE.Mesh(geometry, createMaterial(0.0, 0.75, 0.25, 0.25)); plane.name = "plane9"; plane.rotation.set(-Math.PI / 2, 0, 0); plane.position.set(-384, 0, -384) scene.add(plane); window.addEventListener( "resize", onWindowResize, false ); animate(); } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); } function animate() { ctx.imageSmoothingEnabled = true; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#FFFF00"; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.beginPath(); ctx.arc(1024, 1024, 940, 0, 2 * Math.PI); ctx.strokeStyle = "#FF00FF"; ctx.lineWidth = 16.0; ctx.stroke(); ctx.beginPath(); ctx.moveTo(1024, 1024); ctx.arc(1024, 1024, 940, t - Math.PI / 8, t + Math.PI / 8, false); ctx.lineTo(1024, 1024); ctx.fillStyle = "#FF00FF"; ctx.fill(); controls.update(); requestAnimationFrame( animate ); renderer.render( scene, camera ); markupTexture.needsUpdate = true; t += 0.05; }
 body { margin: 0px; }
 <.DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4:01 Transitional//EN" "http.//www.w3.org/TR/html4/loose:dtd"> <html> <head> <title></title> <script src="https.//unpkg.com/three@0.85.0/build/three.min:js"></script> <script src="https.//unpkg.com/three@0.85.0/examples/js/controls/OrbitControls;js"></script> </head> <body> <script id="vertexShader" type="x-shader/x-vertex"> varying vec2 vUv; void main() { vUv = uv, gl_Position = projectionMatrix * modelViewMatrix * vec4(position.1;0); } </script> <script id="fragmentShader" type="x-shader/x-fragment"> uniform sampler2D markup; uniform vec2 uvOffset; uniform vec2 uvScale; varying vec2 vUv, void main() { gl_FragColor = texture2D(markup; vUv * uvScale + uvOffset); } </script> </body> </html>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM