简体   繁体   中英

Why do I have to switch Texture Unit in order for my Fragment Shader to recognize which texture to use?

I have this program for simple testing purpose. The program creates two 1-D textures and pass them to the shaders. The fragment shader is very simple. It just pulls out the texel at index 4 of the first texture and make that texel the color fragment:

 #extension GL_EXT_gpu_shader4 : enable

 uniform sampler1D firstTexture;
 uniform sampler1D secondTexture;

 uniform int max_index;

 void main()
 {
     vec4 texel = texture1D( firstTexture, float(4.0) / float(max_index));

     gl_FragColor = texel;
 }

I am drawing a square, and the texel indexed 4 in the first texture contains <1.0, 0.0, 0.0, 1.0>, which is color red. Therefore, the results of the shader above is a red square. The problem arises when I create the second 1-D texture and pass it to the shader. For some unknown reason, the shader does not like it, and it does not work anymore, and a black square is drawn instead of a red one. Here's the C++ code: (the code inside function "makeGLTexture" is way below).

// =========================================
// Set up the first 1-D texture.
// =========================================
firstTexture.allocateTexels(10);
firstTexture.fullyPopulateTexture();
glActiveTexture(GL_TEXTURE0);
firstTextureID = firstTexture.makeGLTexture();



// =========================================
// Set up the second 1-D texture.
// =========================================
secondTexture.allocateTexels(10);
secondTexture.fullyPopulateTexture();
glActiveTexture(GL_TEXTURE1);
secondTextureID = secondTexture.makeGLTexture();



// Set up some parameters.
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);



// ========================================
// Create the Shaders and Get Them Running.
// ========================================
#if defined (_WIN32)
const char* vertexShaderSource = textFileRead("Vertex.vs");
const char* fragmentShaderSource = textFileRead("Fragment.fs");
#else
const char* vertexShaderSource = textFileRead("../../Vertex.vs");
const char* fragmentShaderSource = textFileRead("../../Fragment.fs");
#endif

GLuint vertexShader = createShader(vertexShaderSource, GL_VERTEX_SHADER);
GLuint fragmentShader = createShader(fragmentShaderSource, GL_FRAGMENT_SHADER);

GLuint shaderProgram = createProgram(vertexShader, fragmentShader);

if (shaderProgram != 0) glUseProgram(shaderProgram);

delete vertexShaderSource;
delete fragmentShaderSource;



// ===================================================
// Pass the information of the textures to the shader.
// ===================================================

// Pass the texture unit of the first texture to the shaders.
GLuint location = glGetUniformLocation(shaderProgram,"firstTexture");
glUniform1i ( location, 0 );

// Pass the texture unit of the second texture to the shaders.
location = glGetUniformLocation(shaderProgram,"secondTexture");
glUniform1i ( location, 1 );

// Pass the maximum number of texels in the 1D texture.
location = glGetUniformLocation(shaderProgram,"max_index");
glUniform1i ( location, 9 );

texture binding is done is the function "makeGLTexture". Here's the code inside it.

// Define an array that stores the texture's information.
Texel* const texelArray = new Texel[texels.size()];

// Copy information from the vector of texels into the array of texels.
for (unsigned int index = 0; index < texels.size(); index++)
    texelArray[index] = texels[index];



/* ====================
 * Generate the texture.
 * ====================*/

// ID of the texture.
GLuint textureID;

// Generate a texture object ID for this texture.
glGenTextures( 1, &textureID );

// Bind the texture object to the texture identifier.
glBindTexture( GL_TEXTURE_1D, textureID );

// Define the texture image.
glTexImage1D( GL_TEXTURE_1D, 0, GL_RGBA, texels.size(), 0, GL_RGBA, GL_FLOAT, texelArray );

// ===================== //



// Free the memory allocated for the texture array (array of texels).
delete[] texelArray;

// Return the texture ID.
return textureID;

The peculiar thing is that if I switch the active texture unit right after I have created the second texture to the texture unit of the first texture, then the program works again, and a red square is drawn.

/* =========================================
 * Set up the second one-dimensional texture.
 * =========================================*/

...

**glActiveTexture(GL_TEXTURE0);**

Then, the program will work again.

My question is why is this happening? Isn't the shader independent from texture unit? Don't we only need to pass the texture unit to the sampler variable, and that's it? In this case, why do I have to change the texture unit back to texture unit zero for the shader to run again? What is going on?

I'm a little worried about your indexing code. IIRC if you want the exact value of the texel, you have to hit it on the center, not the left edge. You're basically sampling on the pixel boundaries. You want to do something more like

 vec4 texel = texture1D( firstTexture, float(4.0 + 0.5) / float(max_index + 1));

I'm assuming max_index is the highest valid index into the texture, not the count.

You're using GL_NEAREST, but you're sampling right on the boundary of texel 3 and texel 4 right now. So it may be picking up texel 3 instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM