Switching between Texture and Material (in FragmentShader)

hi, i have a little question about IF statements in fragment shaders:
do they have a negative effect on performance or so ??

for now, my fragment shader is very simple:


#version 450


in VS_FS_INTERFACE
{
	vec2 texcoords;
	vec3 normal;
	vec4 IDcolor;
} vs_out;


uniform vec3 Kd;      // not used
uniform sampler2D texture_Kd;


layout (location = 0) out vec4 FragmentColor0;
layout (location = 1) out vec4 FragmentColor1;


void main(void)
{
	FragmentColor0 = texture(texture_Kd, vs_out.texcoords);
	FragmentColor1 = vs_out.IDcolor;
}


but i have a bunch of .obj models and not all of their materials use textures
i want to know if there is a better way to switch on/off the texture than this:


void main(void)
{
	if (use_texture_Kd)       // also a uniform variable:  texture_Kd != 0
		FragmentColor0 = texture(texture_Kd, vs_out.texcoords);
	else
		FragmentColor0 = vec4(Kd, 1);
	FragmentColor1 = vs_out.IDcolor;
}

Yes, your code will be fine. Even ignoring the fact that your fragment shader is trivial.

I quoted that declaration because it’s important to my answer. Any hardware which can implement GL 4.5 is capable of making uniform branches with little performance loss. Some earlier hardware could do that too, but with 4.x capable hardware, it’s a certianty.

It’s non-uniform branching where you have issues. Older performance texts will generally say to never do branching in shaders. But on modern hardware, so long as the branches are dynamically uniform, you’re fine performance-wise.

Well yes, testing the branch will take up some time, so you don’t want to go nuts with the branching logic. But modern graphics engines tend to use uber-shaders, with configurations specified by uniforms. So it’s clearly not something you should worry too much about.

That’s fine, so long as use_texture_Kd is dynamically uniform (which all uniforms are). If it were not dynamically uniform, you’d run into more than just performance problems. You’d break your implicit derivatives.

Not necessarily better, but an alternative is to always use a texture; untextured models can just use a 1x1 white texture (or a white region within a texture atlas, but watch out for issues with mipmapping).

One reason for using that approach rather than a uniform is that it might allow you to coalesce several meshes into a single draw call.

[QUOTE=GClements;1282791]Not necessarily better, but an alternative is to always use a texture; untextured models can just use a 1x1 white texture (or a white region within a texture atlas, but watch out for issues with mipmapping). One reason for using that approach rather than a uniform is that it might allow you to coalesce several meshes into a single draw call.[/QUOTE] This is the approach I’d prefer. It’s often (not always, but often) the case that branching or a shader change can be avoided by using a 1x1 white (or black) texture, or setting a single uniform to 1 (or 0), then ploughing through the same code as otherwise.

thanks for all your replies

hmm, something like a “null” / default texture … i’ll give it a shot
but wouldn’t there be a problem if the material has no texture but constant ambient/diffuse/specular values ?
or should i just add both the constant and the texture sample and use the result of both ?

Why would that be a problem? The default texture would be 1.0. 1.0 multiplied by any of those material factors won’t change their values.

well, you’re right ! thx 4 that suggestion, that means i have to make sure that those const Ka/Kd/Ks are 1 IF the corresponding map_Ka/map_Kd/map_Ks is available, and if not, i bind the “null” texture (white), … i’ll try that :slight_smile:

IT WORKS!!! thank very much again :smiley: