为啥我必须切换纹理单元才能让我的片段着色器识别要使用的纹理?

Posted

技术标签:

【中文标题】为啥我必须切换纹理单元才能让我的片段着色器识别要使用的纹理?【英文标题】:Why do I have to switch Texture Unit in order for my Fragment Shader to recognize which texture to use?为什么我必须切换纹理单元才能让我的片段着色器识别要使用的纹理? 【发布时间】:2011-12-22 16:26:39 【问题描述】:

我有这个程序用于简单的测试目的。该程序创建两个 1-D 纹理并将它们传递给着色器。片段着色器非常简单。它只是在第一个纹理的索引 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 的纹素包含 ,即红色。因此,上面着色器的结果是一个红色方块。当我创建第二个一维纹理并将其传递给着色器时,问题就出现了。由于某种未知的原因,着色器不喜欢它,它不再起作用,并且绘制了一个黑色方块而不是红色方块。这是 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);**

然后,程序将再次运行。

我的问题是为什么会这样?着色器不是独立于纹理单元吗?难道我们只需要将纹理单元传递给采样器变量,就是这样吗?在这种情况下,为什么我必须将纹理单元更改回纹理单元零才能让着色器再次运行?怎么回事?

【问题讨论】:

我可能应该补充一点,这只有在我对两个相同尺寸的纹理(均为一维)执行多重纹理时才会发生。 3-D 和 1-D 纹理似乎工作正常。我不知道二维纹理。 听起来像是某种驱动程序错误。您使用的是什么硬件和驱动程序版本? 【参考方案1】:

我有点担心您的索引代码。 IIRC 如果你想要纹素的确切值,你必须在中心而不是左边缘击中它。您基本上是在像素边界上采样。你想做更多类似的事情

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

我假设 max_index 是纹理的最高有效索引,而不是计数。

您正在使用 GL_NEAREST,但您现在正在采样 texel 3 和 texel 4 的边界。所以它可能会选择 texel 3。

【讨论】:

以上是关于为啥我必须切换纹理单元才能让我的片段着色器识别要使用的纹理?的主要内容,如果未能解决你的问题,请参考以下文章

为啥片段着色器比渲染纹理更快?

为啥我的着色器中的 GLSL 纹理坐标不是线性的?

如何在着色器之后读取像素?

片段着色器究竟如何用于纹理?

在片段着色器中,为啥我不能使用平面输入整数来索引 sampler2D 的统一数组?

纹理中的 OpenGL 片段着色器