PDA

View Full Version : Loading 2 textures in 2 shaders - 1 doesn't work?



Jossos
11-27-2014, 12:26 AM
Hi all. Firstly, just a brief look at my code:

I have like 5 shaders in my program currently, and for some reason the order in which I load them seems to change results. Specifically, I'm having trouble with these 2:


skinShader = new SHADER("Shaders/SkinningShader.vs", "Shaders/ShadingShader.fs");
tileShader = new SHADER("Shaders/StandardShader.vs", "Shaders/TileShader.fs");

glUniform1i(glGetUniformLocation(skinShader->GetProgramID(), "texture0"), 0);
glUniform1i(glGetUniformLocation(skinShader->GetProgramID(), "texture1"), 1);
glUniform1i(glGetUniformLocation(tileShader->GetProgramID(), "texture0"), 0);
glUniform1i(glGetUniformLocation(tileShader->GetProgramID(), "texture1"), 1);

because they each use 2 textures:


uniform sampler2D texture0;
uniform sampler2D texture1;

assume SHADER as just a wrapper class that loads the vertex/fragment files and does the glAttachShader glUseProgram stuff correctly. Also:


void SHADER::Bind() { glUseProgram(m_program); }
void SHADER::Unbind() { glUseProgram(0); };

and my texture functions:


void TEXTURE::Bind(GLenum TextureUnit)
{
if (isValid)
{
glActiveTexture(TextureUnit);
glBindTexture(GL_TEXTURE_2D, m_textureID);
}
}

void TEXTURE::Unbind(GLenum TextureUnit)
{
if (isValid)
{
glActiveTexture(TextureUnit);
glBindTexture(GL_TEXTURE_2D, 0);
}
}

And you can assume 'isValid' is always true, and m_textureID is a proper "glGenTextures()" number (not 0).

Texture Variables:


TEXTURE unitTex;
TEXTURE unitColorTex;
TEXTURE fogTexture;
// And the other one in the MAP object

Render function:


tileShader->Bind();
pipeline.CalcMatrices(tileShader->GetProgramID());

for (int i = 0; i < map->GetAreasAcross(); i++)
for (int j = 0; j < map->GetAreasAcross(); j++)
{
fogTexture.Bind(GL_TEXTURE0);
map->BindAreaTexture(i, j, GL_TEXTURE1); // Contains a working texture bound with GL_TEXTURE1
map->RenderArea(i, j);
fogTexture.Unbind(GL_TEXTURE0);
map->UnBindAreaTexture(i, j, GL_TEXTURE1);
}
tileShader->Unbind();

unitTex.Bind(GL_TEXTURE0);
unitColorTex.Bind(GL_TEXTURE1);

skinShader->Bind();
VECTOR3f tCol;
player->FillRBG(tCol.x, tCol.y, tCol.z);
glUniform3f(glGetUniformLocation(skinShader->GetProgramID(), "teamColor"), tCol.x, tCol.y, tCol.z);

DrawAUnit(pipeline, skinShader, false);
skinShader->Unbind();

unitTex.Unbind(GL_TEXTURE0);
unitColorTex.Unbind(GL_TEXTURE1);



THE PROBLEM:

So one of these textures will work as expected, and the other one will load the same texture for both texture0 and texture1 in the shader. And this is completely dependant on which order I call their "= new SHADER("

-- tileShader works properly and skinShader doesn't if done like this --

skinShader = new SHADER("Shaders/SkinningShader.vs", "Shaders/ShadingShader.fs");
tileShader = new SHADER("Shaders/StandardShader.vs", "Shaders/TileShader.fs");

-- skinShader works properly and tileShader uses same texture in both --

tileShader = new SHADER("Shaders/StandardShader.vs", "Shaders/TileShader.fs");
skinShader = new SHADER("Shaders/SkinningShader.vs", "Shaders/ShadingShader.fs");

Literally just swapping these two lines will make one shader work, and the other not work.

If you need to know the loading:


SHADER::SHADER(const char* pVertexShaderSource, const char* pFragmentShaderSource)
{
m_program = glCreateProgram();

m_vs = CreateShader(LoadFile(pVertexShaderSource), GL_VERTEX_SHADER);
m_fs = CreateShader(LoadFile(pFragmentShaderSource), GL_FRAGMENT_SHADER);

glAttachShader(m_program, m_vs);
glAttachShader(m_program, m_fs);

glLinkProgram(m_program);
CheckShaderError(m_program, GL_LINK_STATUS, true, "Error: Program linking failed: ");

glUseProgram(m_program);
CheckShaderError(m_program, GL_VALIDATE_STATUS, true, "Error: Program is invalid: ");
}

uint SHADER::CreateShader(const std::string& pSource, GLenum pShaderType)
{
GLuint shaderID = glCreateShader(pShaderType);

if(shaderID == 0)
std::cerr << "Error: Shader creation failed!\n";

const GLchar* csource[1] = { pSource.c_str() };

glShaderSource(shaderID, 1, csource, NULL);
glCompileShader(shaderID);

char error[1000];
glGetShaderInfoLog(shaderID, 1000, NULL, error);
std::cout << "Shader compile status: " << error << "\n";

CheckShaderError(shaderID, GL_COMPILE_STATUS, false, "Error: Shader compilation failed: ");

return shaderID;
}

If I'm missing anything please let me know. I am kind of assuming you can derive purpose of certain functions from their names, but I mean, the real problem is that the loading order of the shaders gives different results.

help is greatly appreciated.

GClements
11-27-2014, 02:07 AM
skinShader = new SHADER("Shaders/SkinningShader.vs", "Shaders/ShadingShader.fs");
tileShader = new SHADER("Shaders/StandardShader.vs", "Shaders/TileShader.fs");

glUniform1i(glGetUniformLocation(skinShader->GetProgramID(), "texture0"), 0);
glUniform1i(glGetUniformLocation(skinShader->GetProgramID(), "texture1"), 1);
glUniform1i(glGetUniformLocation(tileShader->GetProgramID(), "texture0"), 0);
glUniform1i(glGetUniformLocation(tileShader->GetProgramID(), "texture1"), 1);
[/CODE]
glUniform() sets a uniform value for the current program. Unless the GetProgramID() method calls glUseProgram() with that ID before returning, only one of those two programs is going to be current, and all 4 glUniform() calls will operate upon that program.

Given the symptoms you describe, I assume that it doesn't. Instead, the SHADER constructor makes the new program current. So in the above code, tileShader (being the last one constructed) will be the current program for all 4 glUniform() calls. skinShader will have all of its uniforms at their default values, meaning that both texture0 and texture1 refer to texture unit zero.

If you swap the order of the constructors, skinShader will be current for all 4 glUniform() calls and tileShader will have its uniforms at their default values.

Jossos
11-27-2014, 04:17 AM
glUniform() sets a uniform value for the current program. Unless the GetProgramID() method calls glUseProgram() with that ID before returning, only one of those two programs is going to be current, and all 4 glUniform() calls will operate upon that program.

Given the symptoms you describe, I assume that it doesn't. Instead, the SHADER constructor makes the new program current. So in the above code, tileShader (being the last one constructed) will be the current program for all 4 glUniform() calls. skinShader will have all of its uniforms at their default values, meaning that both texture0 and texture1 refer to texture unit zero.

If you swap the order of the constructors, skinShader will be current for all 4 glUniform() calls and tileShader will have its uniforms at their default values.

Dude thanks so much! Hours of headache and it's something simple (of course). You've made me a very happy human!