如何在three.js中创建纹理并通过着色器渲染?

3

现在我有一个数组:Uint8ClampedArray(size:512*512*4),我想将此数组转换为Three.js中的纹理,并使用Three.ShaderMaterial来渲染对象。

new THREE.ShaderMaterial( {
    vertexShader: document.querySelector( '#blendModel-vert').textContent.trim(),
    fragmentShader: document.querySelector( '#blendModel-frag' ).textContent.trim(),
    uniforms: {
        buffer:  { value: texture },
    }
});

以下是着色器代码:
<script id="blendModel-vert" type="x-shader/x-vertex">
    varying vec2 vUv;
    varying vec4 gPosition;
    void main() {
        vUv = uv;
        gPosition=gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
</script>
<script id="blendModel-frag" type="x-shader/x-fragment">
    varying vec2 vUv;
    uniform sampler2D buffer;
    varying vec4 gPosition;
    void main() {
        gl_FragColor.rgb = texture2D(buffer, vUv).rgb;
        gl_FragColor.a = 1.0;
    }
</script>

Uint8ClampedArray(size:5125124) 是函数 tf.toPixels() 的输出。 - 陆一凡
你可以绘制一个HTML画布,然后像处理纹理一样进行操作。 - Martin
还有THREE.DataTexture() - prisoner849
但是未能呈现 - 陆一凡
你是否像这样做过 var texture = new THREE.DataTexture( Your_data_array, 512, 512, THREE.RGBFormat ); 如果不起作用,请尝试 var texture = new THREE.DataTexture( new Uint8Array(Your_data_array), 512, 512, THREE.RGBFormat ) - evgeni fotia
显示剩余2条评论
1个回答

4
一种可能的方法是使用Three.DataTexture
提供给Three.DataTexture的数据缓冲区必须是Uint8Array类型,而不是Uint8ClampedArray类型。文档中已经提到这一点。
缓冲区必须由范围在[0,255]之间的字节值组成:

例如:

let t_cx = 512;
let t_cy = 512;
let t_data = new Uint8Array(4 * t_cx * t_cy);

for ( let i = 0; i < t_cx; i ++ ) {
    for ( let j = 0; j < t_cy; j ++ ) {

        let id = j*t_cx*4 + i*4;

        let r = i / (t_cx-1);
        let g = j / (t_cx-1);
        let b = (1-r)*(1-g);

        t_data[id + 0] = r * 255;
        t_data[id + 1] = g * 255;
        t_data[id + 2] = b * 255;
        t_data[id + 3] = 255;
    }
}

此外,需将属性.needsUpdate设置为true,以便在新创建的纹理对象上更新。最初的回答已完成。
var texture = new THREE.DataTexture( t_data, t_cx, t_cy, THREE.RGBAFormat );
texture.needsUpdate = true;

还可以创建一个临时的2D画布和图像对象。这可以像往常一样由THREE.TextureLoader加载:

最初的回答:

let canvas = document.createElement( 'canvas' );
let ctx = canvas.getContext('2d');
canvas.width = t_cx;
canvas.height = t_cy;
let idata = ctx.createImageData( t_cx, t_cy );
idata.data.set( t_data );
ctx.putImageData( idata, 0, 0 );
let dataUri = canvas.toDataURL();

var texture = new THREE.TextureLoader().load( dataUri );

canvas.remove();

"最初的回答",请看下面的例子:

(function onLoad() {
  var loader, camera, scene, renderer, orbitControls;
  
  init();
  animate();

  function init() {
    renderer = new THREE.WebGLRenderer({
      antialias: true,
      alpha: true
    });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    document.body.appendChild(renderer.domElement);

    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 100);
    camera.position.set(0, 1, -2);
    //camera.lookAt( -1, 0, 0 );

    loader = new THREE.TextureLoader();
    loader.setCrossOrigin("");

    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xffffff);
    scene.add(camera);
    window.onresize = resize;
    
    var ambientLight = new THREE.AmbientLight(0x404040);
    scene.add(ambientLight);

    var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
    directionalLight.position.set(1,2,1.5);
    scene.add( directionalLight );

    orbitControls = new THREE.OrbitControls(camera);
    
    addGridHelper();
    createModel();

  }

  function createModel() {

    let t_cx = 512;
    let t_cy = 512;
    let t_data = new Uint8Array(4 * t_cx * t_cy);

    for ( let i = 0; i < t_cx; i ++ ) {
        for ( let j = 0; j < t_cy; j ++ ) {
            
            let id = j*t_cx*4 + i*4;

            let r = i / (t_cx-1);
            let g = j / (t_cx-1);
            let b = (1-r)*(1-g);

            t_data[id + 0] = r * 255;
            t_data[id + 1] = g * 255;
            t_data[id + 2] = b * 255;
            t_data[id + 3] = 255;
        }
    }

    var testMode = 1
    var texture;

    if ( testMode == 1 ) {
        let canvas = document.createElement( 'canvas' );
        let ctx = canvas.getContext('2d');
        canvas.width = t_cx;
        canvas.height = t_cy;
        let idata = ctx.createImageData( t_cx, t_cy );
        idata.data.set( t_data );
        ctx.putImageData( idata, 0, 0 );
        let dataUri = canvas.toDataURL();
        
        texture = new THREE.TextureLoader().load( dataUri );

        canvas.remove();
    } else {
        texture = new THREE.DataTexture( t_data, t_cx, t_cy, THREE.RGBAFormat );
        texture.needsUpdate = true;
    }
    

    var material = new THREE.ShaderMaterial({  
          vertexShader: document.getElementById('vertex-shader').textContent,
          fragmentShader: document.getElementById('fragment-shader').textContent,
          uniforms : {
              buffer: {type: 't', value: texture}
          }
    });

    var geometry = new THREE.BoxGeometry( 1, 1, 1 );
    var mesh = new THREE.Mesh(geometry, material);

    scene.add(mesh);
  }

  function addGridHelper() {
    
    var helper = new THREE.GridHelper(100, 100);
    helper.material.opacity = 0.25;
    helper.material.transparent = true;
    scene.add(helper);

    var axis = new THREE.AxesHelper(1000);
    scene.add(axis);
  }

  function resize() {
    
    var aspect = window.innerWidth / window.innerHeight;
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = aspect;
    camera.updateProjectionMatrix();
  }

  function animate() {
    requestAnimationFrame(animate);
    orbitControls.update();
    render();
  }

  function render() {
    renderer.render(scene, camera);
  }
})();
<script type='x-shader/x-vertex' id='vertex-shader'>
varying vec2 vUv;
void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script type='x-shader/x-fragment' id='fragment-shader'>
precision highp float;
uniform sampler2D buffer;
varying vec2 vUv;
void main(){
    gl_FragColor = texture2D(buffer, vUv);
}
</script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/100/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接