c++openglshaderfragment-shaderopenscenegraph

OpenGL OSG::Texture multiplication only shows one color


My goal is to "multiplicate" two OSG::Textures, where one is a Light-Distribution (RGBA picture) the other a black and white filter Image/Texture, that I generate myself. For now both Textures have the same size, even though it would be nice, if its possible that they don't. You can imagine, that I'm trying to remove the black areas on the filter texture from the light texture.

Currently my code works as far as making the whole screen one color, no matter what. I think that something around the gl_MultiTexCoord0 or gl_TexCoord[0] is not correct. I had a look at multiple online sources, but could not get anything else to work.

Sadly I have to use an old version of glew (2.1.0) [-> ? OpenGL #version 120] and OSG (3.0.1) due to framework restrictions.

Because nothing is working correctly, I'll try for now just to show the filterTexture (because if I show the lightTexture, everything is black)... Inside init and update I have multiple "checkError" in place, to see whats going on, but atm there are no errors. Here are my shaders:

// vertex shader
const char* shader_combine_vertex = "\n\
#version 120                                    \n\
                                                \n\
void main()                                     \n\
{                                               \n\
    // homogeneous vertex position              \n\
    gl_Position = ftransform();                 \n\
    //Texture coordinate of texture unit 0 and 1\n\
    gl_TexCoord[0] = gl_MultiTexCoord0;         \n\
    gl_TexCoord[1] = gl_MultiTexCoord1;         \n\
}                                               \n";


// fragment shader
const char* shader_combine_fragment = "                                     \n\
#version 120                                                                \n\
// input                                                                    \n\
uniform sampler2D lightTexture;                                             \n\
uniform sampler2D filterTexture;                                            \n\
//varying vec2 lightTexCoord;                                               \n\
//varying vec2 filterTexCoord;                                              \n\
                                                                            \n\
void main()                                                                 \n\
{                                                                           \n\
    gl_FragColor = texture2D(filterTexture, gl_TexCoord[1].st);             \n\
                                                                            \n\
    // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); //works and shows red       \n\
                                                                            \n\
    // gl_FragColor = texture2D(filterTexture, filterTexCoord);             \n\
                                                                            \n\
    // vec4 texel = texture2D(lightTexture, gl_TexCoord[0].st);             \n\
    // gl_FragColor = texel * texture2D(filterTexture, gl_TexCoord[1].st);  \n\
}\n";

And the global Variables and the init and update functions with valid OpenGL context:

    /** textures for each lightSourceID **/
    std::map<int, GLuint> vp_ShaderCombine;
    std::map<int, GLuint> fp_ShaderCombine;
    /** Program linking shaders **/
    std::map<int, GLhandleARB> combineProgram;

    // TODO: maybe generate all texture IDs at once, but works for now
    std::map<int, unsigned int> g_uiSceneTex[2]; // for every sensor - 2 texture IDs (Light | Filter)

---------

bool initShaders(int id, int width, int height, char* texture)
{
    // Shaders compilation
    vp_ShaderCombine.insert(std::pair<int, GLuint>(id, glCreateShaderObjectARB(GL_VERTEX_SHADER)));
    fp_ShaderCombine.insert(std::pair<int, GLuint>(id, glCreateShaderObjectARB(GL_FRAGMENT_SHADER)));

    glShaderSource(vp_ShaderCombine.at(id), 1, &shader_combine_vertex, NULL);
    glShaderSource(fp_ShaderCombine.at(id), 1, &shader_combine_fragment, NULL);

    glCompileShader(vp_ShaderCombine.at(id));
    checkShaderCompileError(vp_ShaderCombine.at(id), "vertex");
    glCompileShader(fp_ShaderCombine.at(id));
    checkShaderCompileError(fp_ShaderCombine.at(id), "fragment");

    combineProgram[id] = glCreateProgram();
    glAttachShader(combineProgram[id], vp_ShaderCombine[id]);
    glAttachShader(combineProgram[id], fp_ShaderCombine[id]);

    glLinkProgram(combineProgram.at(id));
    glValidateProgram(combineProgram.at(id));

    // Check result and display errors if any
    ...
    return ...;
}

void update()
{
    for (... every light source id ...)
    {
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_LIGHTING);
        // ------------  NECESSARY? ----------------
        glDisable(GL_DEPTH_TEST);
        glDisable(GL_CULL_FACE);
        glDisable(GL_BLEND);
        // ----------- LIGHT----------------
        // mainly the same as filter just on g_uiSceneTex[id][0]
        // ----------- FILTER ----------------
        glUseProgramObjectARB(combineProgram[id]); // call before each glActiveTexture (according to some SO post)
        glActiveTexture(GL_TEXTURE0 + 1);
        // TODO: maybe generate all texture IDs at once, but works for now
        glGenTextures(1, &g_uiSceneTex[id][1]); // generate texture names
        glBindTexture(GL_TEXTURE_2D, g_uiSceneTex[id][1]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, itSHM->myOsgImg->s(), itSHM->myOsgImg->t(), 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, itSHM->myOsgImg);

        GLint filterTexUnitLoc = glGetUniformLocation(combineProgram[id], "filterTexture");
        glUniform1i(filterTexUnitLoc, 0);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

        // render
        // draw QUAD
        glBegin(GL_QUADS);
        glTexCoord2f(0, 0);
        glVertex3f(0, 1, -1);
        glTexCoord2f(0, ScreenHeight);
        glVertex3f(0, 0, -1);
        glTexCoord2f(ScreenWidth, ScreenHeight);
        glVertex3f(1, 0, -1);
        glTexCoord2f(ScreenWidth, 0);
        glVertex3f(1, 1, -1);
        glEnd();

        // Disable Shaders
        glUseProgramObjectARB(0);

        glDisable(GL_TEXTURE_2D);
        // NECESSARY?
        myShmImages[0].myOsgImg->dirty();
        myPhotometries[0].myOSGTexture->dirtyTextureObject();
    }
}

Now arise multiple Questions on my side:

  1. What is wrong with the shaders, that they only show one color? I think that they only ever evaluate on one pixel.
  2. Whats the difference between using these gl functions vs using OSG native functions to create a shader? Are there limitations, or is my setup possible? Is it "easier"? Any good reading on that topic, I did not find any?
  3. Update code looks very long and unnecessary, do I need to generate / create the texture every time in update, or can I init it only once?
  4. Currently the texture is Displayed full screen, but I want to display it at the Light position in the OSG tree. I have the viewing frustum of the light distribution, therefore I think, I just need to "map" the new filtered texture using that view/camera/frustum...

Solution

  • You are not supplying gl_Multitexcoord1 at all:

        glBegin(GL_QUADS);
        glTexCoord2f(0, 0);
        glVertex3f(0, 1, -1);
        [...]
        glEnd();
    

    This code only supplies data for gl_MultiTexCoord0. If you really need different texcoords for each texture, then you need to provide them per vertex via glMultiTexCoord:

        glBegin(GL_QUADS);
        glMultiTexCoord2f(GL_TEXTURE0, 0, 0);
        glMultiTexCoord2f(GL_TEXTURE1, ..., ...);
        glVertex3f(0, 1, -1);
        [...]
        glEnd();
    

    However, you can also use a single set of texture coords for both textures, if you don't really need different values (which is not clear from your question).

    Note that your code is horribly outdated, and deprecated in the GL since 2008. Even if you are limited to GL2.x (as your shaders target), you should never use the builtin attributes like gl_MultiTexCoord* etc. Use generic vertex attributes, and supply your data as vertex arrays in vertex buffer objects.