为什么我必须切换纹理单元才能让我的片段着色器识别要使用的纹理?
我有这个程序用于简单的测试目的。该程序创建两个一维纹理并将它们传递给着色器。片段着色器非常简单。它只是拉出第一个纹理索引 4 处的纹素,并使该纹素成为颜色片段:
#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;
}
我正在绘制一个正方形,第一个纹理中索引为 4 的纹素包含 <1.0, 0.0, 0.0, 1.0>,其中颜色为红色。因此,上面的着色器的结果是一个红色的方块。当我创建第二个一维纹理并将其传递给着色器时,问题就出现了。由于某种未知的原因,着色器不喜欢它,并且它不再工作,并且绘制了黑色方块而不是红色方块。这是 C++ 代码:(函数“makeGLTexture”内的代码如下)。
// =========================================
// 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 );
纹理绑定是通过函数“makeGLTexture”完成的。这是里面的代码。
// 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;
奇怪的是,如果我在创建第二个纹理后立即将活动纹理单元切换到第一个纹理的纹理单元,那么程序会再次工作,并绘制一个红色方块。
/* =========================================
* Set up the second one-dimensional texture.
* =========================================*/
...
**glActiveTexture(GL_TEXTURE0);**
然后,程序将再次运行。
我的问题是为什么会发生这种情况?着色器不是独立于纹理单元的吗?我们不是只需要将纹理单元传递给采样器变量就可以了吗?在这种情况下,为什么我必须将纹理单元更改回纹理单元零才能使着色器再次运行?到底是怎么回事?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我有点担心你的索引代码。 IIRC 如果你想要纹理元素的精确值,你必须将其击中中心,而不是左边缘。您基本上是在像素边界上采样。您想做的事情更像是
我假设 max_index 是纹理中的最高有效索引,而不是计数。
您正在使用 GL_NEAREST,但您现在正在纹素 3 和纹素 4 的边界上采样。所以它可能会选择 texel 3。
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
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.