Threejs - Applying a simple texture to a shader material
Using Threejs (67) with a Webgl renderer, I cannot get the plane with the shader material to wear its texture. No matter what I do, the material will just stay black.
My code looks pretty simple at the moment:
var grassT = new Three.Texture(grass); // grass is an already loaded image.
grassT.wrapS = grassT.wrapT = Three.ClampToEdgeWrapping;
grassT.flipY = false;
grassT.minFilter = Three.NearestFilter;
grassT.magFilter = Three.NearestFilter;
grassT.needsUpdate = true;
var terrainUniforms = {
grassTexture : { type: "t", value: grassT},
}
Then I only have this part of the revelant in the vertexShader:
vUv = uv;
And on the FragmentShader side:
gl_FragColor = texture2D(grassTexture, vUv);
This leads to:
- Black material.
- Error in the console.
- The gl_FragColor value is always (0.0, 0.0, 0.0, 1.0).
What I have tried / tested:
- Everything works fine if I just apply custom simple colors.
- It's okay if I use vertexColors with normal colors.
- My texture width / height is really 2.
- The image is on the same server as the code.
- Tested another image with the same result.
- The image is actually loaded into the browser debugger.
- The UVS for the mesh are correct.
- Playable with wrapT, wrapS, minFilter, magFilter
- Adjusted the cell size so that the texture has a 1: 1 ratio.
- Preloaded the image using the imjs image plugin and created the texture from THREE.Texture () instead of using THREE.ImageUtils ();
- Played with needsUpdate: true;
- The attempt to add specifies ['USE_MAP'] during material creation.
- Tried adding material.dynamic = true.
- I have a correct render loop (terrain interraction works).
What else is interesting to me:
- It is a multiplayer game using a custom port with socket.io expression. Did I hit any Webgl security policy?
- I have no lights logic at the moment, is this a problem?
- Perhaps the shader material needs other "defines" upon instanciation?
I am guessing that I am missing something simpler, which is why I am asking ... Thanks.
source to share
I am applying different effects to the same shader. I have a custom API that integrates all the different forms of effects simply using Three.UniformsUtils.merge()
However, this function calls a method clone()
on the texture and this results in a reset needsUpdate
to false
before the texture reaches the renderer.
It looks like you should set the texture property to true when reaching the material level . At the texture level, if the uniform that you set is merged and therefore cloned later in the process, it will lose its property . needsUpdate
needsUpdate
The issue is also detailed here: https://github.com/mrdoob/three.js/issues/3393
In my case, the following didn't work ( grassT
is my texture):
grassT.needsUpdate = true
while the following following execution is done in code:
material.uniforms.grassTexture.value.needsUpdate = true;
source to share
Image loading is asynchronous. Chances are you are creating your scene before loading the texture image.
You must set the flag texture.needsUpdate
in true
after loading the image. Three.js has a utility to do this for you:
var texture = THREE.ImageUtils.loadTexture( "texture.jpg" );
After rendering, rendering returns the flag texture.needsUpdate
to false
.
three.js r.68
source to share