简体   繁体   中英

How to create the texture in three.js and then render by shader?

Now i have the array: Uint8ClampedArray(size:512*512*4) , i want to convert this array to the texture in three.js ,and then use the Three.ShaderMaterial to render the object.

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

the shader as follows:

<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>

One possibility is to use Three.DataTexture .
The data buffer which is provided to Three.DataTexture , has to be of type Uint8Array rather than Uint8ClampedArray . This is mentioned in the documentation.
The buffer has to consist of byte values in range [0, 255]:

eg

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;
    }
}

Further more, the property .needsUpdate has to be set true , on the newly created texture object.

var texture = new THREE.DataTexture( t_data, t_cx, t_cy, THREE.RGBAFormat );
texture.needsUpdate = true;

It is also possible to create a temporary 2D canvas and image object. This can be load by THREE.TextureLoader as usual:

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();

See the example:

 (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> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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