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.

+3


source to share


2 answers


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;

      

+2


source


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

+1


source







All Articles