1

Is it possible to pass a texture from a vertex to a fragment shader in WebGL? If so, how can one achieve this behavior?

I tried to pass a Sampler2D to the frag shader and got an error:

sampler2Ds must be uniform

I'd be grateful for any help others can offer on this question!

3
  • Please show as much of your vs and fs source code as possible to help us help you Commented Jul 24, 2018 at 20:06
  • @DacreDenny are you saying it's possible to pass a texture from a vertex shader to a frag shader? I didn't post code because the error seems to assert a sampler2D must be a uniform, rather than a varying. Anyway I'll update the question... Commented Jul 24, 2018 at 20:09
  • See the answer below Commented Jul 24, 2018 at 20:10

1 Answer 1

4

Why would you pass a texture from the vertex shader to the fragment shader? Just declare the same sampler in both shader?

vertex shader

...
uniform sampler2D foo;
....

fragment shader

...
uniform sampler2D foo;
...

Otherwise the answer is no, you can't pass a texture between shaders. You can pass some value to select sampler results

vertex shader

varying float textureSelector;
...
textureSelector = ???

fragment shader

vec4 color1 = texture2D(foo, ...);
vec4 color2 = texture2D(bar, ...);
vec4 color = mix(color1, color2, textureSelector);

Note: Updated based on comments from Nicol, According to the spec textures break if used in inside conditional code. From the spec, Appendix A.6

Texture Accesses

Accessing mip-mapped textures within the body of a non-uniform conditional block gives an undefined value. A non-uniform conditional block is a block whose execution cannot be determined at compile time

In other words code like this might not work

varying float textureSelector;
uniform sampler2D foo;
uniform sampler2D bar;

...

if (textureSelector > ???) {
  ... use foo ...
} else {
  ... use bar ...
}

so I guess it's best to sample all the textures in a non-conditional part of your shader and then either use math like mix above or use conditionals after you've gotten the values out of the textures. An example of accessing N textures but choosing only 1.

#define NUM_TEXTURES 6
uniform sampler2D u_textures[NUM_TEXTURES];
varying float textureSelector;  // 0 to NUM_TEXTURES - 1
void main() {
  vec4 color = vec4(0);
  for (int i = 0; i < NUM_TEXTURES; ++i) {
    float id = float(i);
    float mult = step(id - .5, textureSelector) * step(textureSelector, id + .5);
    vec4 texColor = texture2D(u_textures[i], someTexCoord);
    color = mix(color, texColor, mult); 
  }
  ... use color ...
}

Of course for most use cases you should probably be using a texture atlas and using texture coordinates to select parts of it. The normal reasons to use multiple textures are things like normal maps, opacity maps, reflectivity maps, ambient occlusion, lighting and or smooth mixes like dirt/grass/snow in which cases you wouldn't need conditionals. To re-iterate, it's not common to select from multiple textures in a shader.

Sign up to request clarification or add additional context in comments.

11 Comments

thanks I thought that was the case. Do you know if there exists a list of all possible varying data types? The use case was avoiding a large texture lookup tree in the fragment shader (I have multiple textures, and if I could find the appropriate one for a fragment in the vertex shader I thought that would be optimal). Can you say more about what you mean when you say "You can pass some value to select shaders" -- can I define one frag shader for each texture then just variabilize the fragment shader used for a given point?
"if (textureSelector > ???)" There are a ton of caveats that come along with doing that. Does WebGL support the dFdx/y functions and textureGrad? If not, then such a selector will introduce problems. At least, if the actual texture fetch is done in the condition. If you do both fetches before and ignore one of the in the condition, that would work.
There's a list of possible varyings in the WebGL Reference Sheet and of course the spec which the reference sheet shows the sections in the spec for each topic.
Thanks @gman. I'm casting my texture index to an int then using that to perform the lookup -- does that resolve the troubles you mentioned, NicolBolas?
I know of no non-obvious issues with selecting textures based on varyings. Of course they are varyings so they vary. Casting to int won't stop them from varying. Passing the same value for every vertex of a triangle will. I really depends on what you want to do with them. Of course you can also mix. GLSL is just a programming language. It's up to you to write the correct math given the inputs.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.