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:
- What is wrong with the shaders, that they only show one color? I think that they only ever evaluate on one pixel.
- 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?
- 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?
- 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...