繁体   English   中英

Three.js / WebGL和2D Canvas —将getImageData()数组传递给Three.DataTexture()

[英]Three.js/WebGL and 2D Canvas — Passing getImageData() array into Three.DataTexture()

我是WebGL(和一般3D图形)的新手,正在使用three.js。 我想做的是从2D画布创建多个纹理,然后使用它们渲染多个网格,每个网格具有不同的纹理。

如果我只是将画布传递给新的THREE.Texture()原型,则纹理将更改为当前的画布。 因此,我所有的对象都具有相同的纹理。 我的解决方案是使用getImageData()存储每个画布数组,并通过将数据传递到新的THREE.DataTexture()原型来创建新纹理。 但是,chrome会不断抛出错误,当我在Firefox上运行它时,纹理会倒置显示。

userName = $nameInput.val();
ctx2d.fillText( userName, 256, 128); 
var canvasData = ctx2d.getImageData(0,0,512,256);

texture = new THREE.DataTexture(canvasData.data, 512, 256, THREE.RGBAFormat);
texture.needsUpdate = true;

material = new THREE.MeshBasicMaterial({ map: texture });
geometry = new THREE.PlaneGeometry(20,10);
textMesh = new THREE.Mesh( geometry, material);

scene.add(textMesh);

Chrome和Safari记录以下错误:WebGL:INVALID_OPERATION:texImage2D:键入UNSIGNED_BYTE,但ArrayBufferView不是Uint8Array。 尽管纹理是颠倒的,但是无论是Firefox还是使用它。

根据Mozilla文档,数据是Uint8ClampedArray。 因此,假设这是问题所在,我可以按照以下方法通过创建一个新的Uint8Array()并将数据传递给它来解决上述错误:

var data = new Uint8Array(canvasData.data);

texture = new THREE.DataTexture(data, 512, 256, THREE.RGBAFormat);

但是它仍然显示颠倒。 这是怎么回事?

Three.js延迟地进行初始化,因此从理论上讲,您可以通过调用renderer.render来初始化纹理

 "use strict"; var camera; var scene; var renderer; var group; init(); animate(); function init() { renderer = new THREE.WebGLRenderer({canvas: document.querySelector("canvas")}); camera = new THREE.PerspectiveCamera(70, 1, 1, 1000); camera.position.z = 300; scene = new THREE.Scene(); group = new THREE.Object3D(); scene.add(group); var geometry = new THREE.BoxGeometry(50, 50, 50); var ctx = document.createElement("canvas").getContext("2d"); ctx.canvas.width = 128; ctx.canvas.height = 128; for (var y = 0; y < 3; ++y) { for (var x = 0; x < 3; ++x) { ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillStyle = "rgb(" + (x * 127) + ",192," + (y * 127) + ")" ; ctx.fillRect(0, 0, 128, 128); ctx.fillStyle = "white"; ctx.font = "60px sans-serif"; ctx.fillText(x + "x" + y, 64, 64); var texture = new THREE.Texture(ctx.canvas); texture.needsUpdate = true; texture.flipY = true; var material = new THREE.MeshBasicMaterial({ map: texture, }); var mesh = new THREE.Mesh(geometry, material); group.add(mesh); mesh.position.x = (x - 1) * 100; mesh.position.y = (y - 1) * 100; // render to force three to init the texture renderer.render(scene, camera); } } } function resize() { var width = renderer.domElement.clientWidth; var height = renderer.domElement.clientHeight; if (renderer.domElement.width !== width || renderer.domElement.height !== height) { renderer.setSize(width, height, false); camera.aspect = width / height; camera.updateProjectionMatrix(); } } function animate() { resize(); group.rotation.x += 0.005; group.rotation.y += 0.01; renderer.render(scene, camera); requestAnimationFrame(animate); } 
 body { margin: 0; } canvas { width: 100vw; height: 100vh; display: block; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.min.js"></script> <canvas></canvas> 

您还可以调用renderer.setTexture(texture, slot) ,该方法可以工作,但是基于函数的名称,文档和签名可以说是错误的做法,因此无法保证将来会成功。

 "use strict"; var camera; var scene; var renderer; var group; init(); animate(); function init() { renderer = new THREE.WebGLRenderer({canvas: document.querySelector("canvas")}); camera = new THREE.PerspectiveCamera(70, 1, 1, 1000); camera.position.z = 300; scene = new THREE.Scene(); group = new THREE.Object3D(); scene.add(group); var geometry = new THREE.BoxGeometry(50, 50, 50); var ctx = document.createElement("canvas").getContext("2d"); ctx.canvas.width = 128; ctx.canvas.height = 128; for (var y = 0; y < 3; ++y) { for (var x = 0; x < 3; ++x) { ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillStyle = "rgb(" + (x * 127) + ",192," + (y * 127) + ")" ; ctx.fillRect(0, 0, 128, 128); ctx.fillStyle = "white"; ctx.font = "60px sans-serif"; ctx.fillText(x + "x" + y, 64, 64); var texture = new THREE.Texture(ctx.canvas); texture.needsUpdate = true; texture.flipY = true; var material = new THREE.MeshBasicMaterial({ map: texture, }); var mesh = new THREE.Mesh(geometry, material); group.add(mesh); mesh.position.x = (x - 1) * 100; mesh.position.y = (y - 1) * 100; // make three init the texture var slot = 0; // doesn't matter what slot as we're not renderer.setTexture(texture, slot); } } } function resize() { var width = renderer.domElement.clientWidth; var height = renderer.domElement.clientHeight; if (renderer.domElement.width !== width || renderer.domElement.height !== height) { renderer.setSize(width, height, false); camera.aspect = width / height; camera.updateProjectionMatrix(); } } function animate() { resize(); group.rotation.x += 0.005; group.rotation.y += 0.01; renderer.render(scene, camera); requestAnimationFrame(animate); } 
 body { margin: 0; } canvas { width: 100vw; height: 100vh; display: block; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.min.js"></script> <canvas></canvas> 

至于翻转,请使用texture.flipY = true;

暂无
暂无

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

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