1
votes

I'd like to add a second crate texture to the shader using the shader/technique provided with this example:

https://threejs.org/examples/#webgl_buffergeometry_instancing_dynamic

I figured I could pass in another uniform to add a second map.

crateMaterial = new THREE.RawShaderMaterial( {
        uniforms: {
          map: { value: new THREE.TextureLoader().load( './img/textures/crate/crate.gif' ), 
          map2: { value: new THREE.TextureLoader().load( './img/textures/crate2/crate2.gif' ) }
};

However I'm struggling to figure out how to "tag" specific crates and then use the shader to draw vertices with the correct texture, as my experience and skill with GLSL are quite limited.

Could I just pass in another uniform consisting of (vertex) indices to specify where the shader should apply the second texture? ie:

crateMaterial.uniforms.cratesTexturemap = [];
for(i=0;i<cratesToRender;i++) {
/* set position */
...

this._instancePositions.push( position.x, position.y, position.z );

if (drawCrate2) {
crateMaterial.uniforms.cratesTexturemap.push(i); /* correlates to (vertex) position index */
crateMaterial.uniforms.cratesTexturemap.push(i+1);
crateMaterial.uniforms.cratesTexturemap.push(i+2);
}
...
}

Also performance/memory-wise, is it better to have a (dynamic) array of textures passed to the shader or is passing them one by one (a uniform value for every texture as above) more advantageous?

Example shader code for reference:

<script id="vertexShader" type="x-shader/x-vertex">
        precision highp float;
        uniform mat4 modelViewMatrix;
        uniform mat4 projectionMatrix;
        attribute vec3 position;
        attribute vec3 offset;
        attribute vec2 uv;
        attribute vec4 orientation;
        varying vec2 vUv;
        // http://www.geeks3d.com/20141201/how-to-rotate-a-vertex-by-a-quaternion-in-glsl/
        vec3 applyQuaternionToVector( vec4 q, vec3 v ){
            return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );
        }
        void main() {
            vec3 vPosition = applyQuaternionToVector( orientation, position );
            vUv = uv;
            gl_Position = projectionMatrix * modelViewMatrix * vec4( offset + vPosition, 1.0 );
        }
    </script>

    <script id="fragmentShader" type="x-shader/x-fragment">
        precision highp float;
        uniform sampler2D map;
        varying vec2 vUv;
        void main() {
            gl_FragColor = texture2D( map, vUv );
        }
    </script>
1
Use an additional instanced buffer attribute with indices for which texture you want to use for specific crates.prisoner849

1 Answers

1
votes

Can't you just pass an array of textures and choose which to apply using an index passed by a int uniform? So for every crate you could do

crate.material.uniforms.index = 2

to choose the 3rd texture in the array