Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm currently building a shader that takes a 2D texture sampler and uses UV coordinates to map it. This works fine for all textured objects. However, I'm having a bit of a problem as I'm trying to render a Mesh with no texture and the shader objects just keeps sampling based on the parameters of the last object I rendered. What is a good way to make sure whenever no texture is available it will just treat it as a white texture or something?

One thing I've thought of was creating and binding a white 1x1 texture but that seems overkill.

Related question: I've been wondering about this and I've yet to find an answer: Is it best to make a multi-purpose shader or constantly change the shader program for different objects in the same render update? For instance, should I have just created a shader for non-textured objects?

share|improve this question
add comment

2 Answers

It sounds to me like you need another shader that doesn't do any texture sampling.

In general, shaders perform poorly when you give them conditional logic. This mainly includes if statements and for loops. So if you have some objects that you want to apply a single texture to, and some that you want to apply none to, it's best to use two different shaders.

Consider all the different functions you might perform in a shader. Different lighting (and different numbers of lights), texturing, coloring, bump/normal mapping... if you were to try to cram all of these things into one shader, you'd have a very messy bit of code, and it would be littered with performance-sucking conditional logic.

Some of these things, like the number of lights or the number of textures used, can be changed with a single line of code, by assuming that the shader compiler will make some optimizations for you. Consider the case of using multiple lights:

#define NUM_LIGHTS 8

void main() {
    // ...
    for ( int i=0; i<NUM_LIGHTS; i++ ) {
        // ....
    }
 }

In this case, the compiler should perform loop unwinding here and give you branchless code, but you still enjoy readable and maintainable code.

My game engine uses a variable substitution system where I can use shader code like above and replace it to support fixed number of lights very easily. For example, I might have:

#define NUM_LIGHTS {0}

When I load my shaders, I'll take this specific shader and replace that number numerous times to produce a shader that will handle a very specific number of lights.

share|improve this answer
    
I find it strange that we have to use multiple shaders considering that engines like unity3D have shaders that support multiple numbers of textures and manually setting them to nothing. –  Pedro Caetano Jun 5 '13 at 16:43
    
I'm not familiar with Unity3D, but it could very well be doing this kind of thing behind the scenes. Also, "have to" really isn't the right way to phrase it... modern hardware is so fast that you probably would get away with some pretty un-optimized shaders. –  stephelton Jun 5 '13 at 17:22
    
I've done some research and it seems like they use a special language to write their shaders which allows default values for the textures and such. Like so: _MainTex ("Base (RGB)", 2D) = "white" {} . I have no idea how this works internally, probably just a 1x1 coloured texture. Thanks for the help! –  Pedro Caetano Jun 5 '13 at 17:30
add comment

The way I do it is build one general-purpose shader program with optional parts sectioned off using preprocessor conditionals. For example, a simple fragment shader with optional texture mapping:

#ifdef TEXTURE_MAPPING
    uniform sampler2D uSampler;
#endif

void main()
{
    #ifdef TEXTURE_MAPPING
        vec4 fColor = texture(uSampler, vUV);
    #elif
        vec4 fColor = vec4(1.0);
    #endif
}

These flags such as TEXTURE_MAPPING or SPECULAR_SHADING are defined in the game code when the shader is compiled. In my system, the flags are mapped to a bitfield which is used to look up the desired shader progam object.

Therefore, your material is essentially a bitfield + a program identifier + uniform data. The bitfield governs which uniform data must be present.

share|improve this answer
    
This can really get out of hand as your shader becomes more complex. –  stephelton Jun 5 '13 at 17:50
    
It pays off in performance and pseudo-runtime flexibility, though, as well as removing the need to duplicate a lot of code. –  Boreal Jun 5 '13 at 17:53
    
I also implemented #include in my shader loading, so that helps avoid duplication of code. –  stephelton Jun 5 '13 at 18:12
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.