3

I want to render a texture to a plane using custom shaders. This texture has an 'offset' property set, that works correctly when I use a standard threejs material. However, I cannot figure out how to access these offsets in my custom fragment shader. It simply renders the whole texture over the whole plane:

shaders:

<script id="vertex_shader" type="x-shader/x-vertex">
    varying vec2 vUv;

    void main() {
        vUv = uv;
        gl_Position = projectionMatrix *
            modelViewMatrix *
            vec4(position,1.0);
    }

    </script>

    <script id="fragment_shader" type="x-shader/x-fragment">

    uniform sampler2D texture1;
    varying vec2 vUv;

    void main()
    {
        gl_FragColor = texture2D(texture1, vUv); 
    }

    </script>

if I could somehow say something like:

gl_FragColor = texture2D(texture1, vUv + texture1.offset); 

? Maybe that would work. But obviously that throws an error.

UPDATE: so I sent the texture offset in as a uniform and that works. Dont know why I didn't think of that.

korrbit
  • 37
  • 1
  • 5

1 Answers1

3

If I understand your question correctly, then the answer should be to add and use the uniform mat3 uvTransform; uniform to your fragment shader.

THREE will look for and populate that uniform with the texture transformation (which includes texture1.offset), when rendering the texture onto your geometry.

You should be able to access and extract the data supplied to texture1.offset to offset your texture sampling as follows:

<script id="vertex_shader" type="x-shader/x-vertex">
varying vec2 vUv;

void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}

</script>

<script id="fragment_shader" type="x-shader/x-fragment">

    // [UPDATE] The uv offset uniform we defined below
    uniform vec2 uvOffset;
    // [UPDATE] The texture uniform we defined below
    uniform sampler2D texture;

    varying vec2 vUv;

    void main()
    {
        // [UPDATE] Apply offset to texture lookup
        gl_FragColor = texture2D(texture, vUv + uvOffset); 
    }

</script>

You would then accompany the vertex and fragment shaders above, with the following THREE.ShaderMaterial:

<script>
  var material = new THREE.ShaderMaterial({
  uniforms: THREE.UniformsUtils.merge([
    {
      //Declare texture uniform in shader
      texture: { type: 't', value: null }, 
      //Declare texture offset in shader
      uvOffset : { type : 'v', value : new THREE.Vector2(0,0) } 
    }
  ]),
  vertexShader: 
  document.getElementById('vertexshader').textContent,
  fragmentShader: 
  document.getElementById('fragmentshader').textContent
});

// Shader uniforms can be updated like so
material.uniforms.map.value = yourTexture;
material.uniforms.uvOffset.value = yourTextureOffsetVector2;
</script>
Dacre Denny
  • 29,664
  • 5
  • 45
  • 65
  • That looks great! it doesnt work for me though, it has no effect. I cant find any documentation on this "uvTransform" that automatically gets passed to the shaders. Is there a standard way to apply the matrix to the texture? – korrbit Sep 05 '18 at 04:28
  • How are you loading the shader? via THREE.Shader, or THREE.RawShader ? – Dacre Denny Sep 05 '18 at 04:33
  • var material = new THREE.ShaderMaterial. If there is a better, more standard way to acheive a simple UV mapped custom shader, id love to find an example somewhere – korrbit Sep 05 '18 at 05:08
  • You might have to apply the actual offset to the uniform something like `myMaterial.uniforms.uvOffset.value = myTexture.transformMatrix` or whatever it's called This would be a mat3 so you have to multiply it, for the offset alone you could probably do a `uniform vec2 uOffset` `myMateria.uniforms.uOffset.value = myTexture.offset` – pailhead Sep 05 '18 at 17:07
  • @korrbit have just updated answer - hope this helps! – Dacre Denny Sep 05 '18 at 20:42