OpenGL/GLSL - 编写智能纹理着色器

4
假设我的纹理是256x256像素。它包含16个64x64像素的子纹理。这些子纹理将被渲染到四边形中。为了提高性能,我想向着色器传递离散的值,用于编码每个顶点的纹理坐标。例如,值0、1、2、3应该对应于(0,64)、(64,64)、(64,0)、(0,0)等每个顶点的纹理坐标。
以下是我的方案。
我加载并绑定了一个多级纹理:
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D,3,TextureImage[0]->w,TextureImage[0]->h,GL_RGB,GL_UNSIGNED_BYTE,TextureImage[0]->pixels);

接下来我加载我的数据:

glGenVertexArrays(1, &VecArrObj);
glBindVertexArray(VecArrObj);

glGenBuffers(1, &VertexBO);
glBindBuffer(GL_ARRAY_BUFFER, VertexBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertAndTex), VertAndTex, GL_STREAM_DRAW);

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_SHORT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 1, GL_SHORT, GL_FALSE, 0, (void*)TexOffset);

glGenBuffers(1, &IndexBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indx), Indx, GL_STREAM_DRAW);

在这里,使用glBindAttribLocation将属性正确地分配给了myProgram。这是我展示四边形的方式:

glUseProgram(myProgram);
glBindVertexArray(VecArrObj);
glDrawElements(GL_QUADS, 4, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
glUseProgram(0);

现在mipmap纹理已经常规绑定,从着色器中可以访问。到目前为止,我的着色器看起来如下。

顶点着色器:

#version 130

in vec4 posit;  //attr=0
in short textu; //attr=1
uniform mat4 trafoMat;

void main()
{
gl_Position = trafoMat * posit;
gl_TexCoord[0] = gl_MultiTexCoord0;
}

片元着色器:

#version 130

uniform sampler2D tex;
out vec4 outColor;

void main()
{
outColor = texture2D(tex,gl_TexCoord[0].st);
}

当tex设置为零时,这些着色器甚至不会获取整个纹理,而只会从纹理中将整个四边形设置为一个颜色(我认为是左上角像素)。很明显,我对着色器没有太多经验。基本上,我的问题是:我应该如何修改我的着色器以满足开始描述的目的?(我能够计算每个顶点的纹理坐标 - 我主要需要的是如何处理着色器中的纹理的提示。请注意:我的硬件不支持glGenSamplers())。

1个回答

3

首先,除非您使用简单的映射(即f(x) -> (u,v),其中f是一些简单函数),否则您应该创建一个执行映射的间接纹理。在您的情况下,它将是一个1D纹理,并且有16个(双组件)条目。

其次,您需要对间接纹理进行点采样,以找出从实际纹理中采样的位置。假设您的四边形具有0..1 UV坐标,则生成的着色器将如下所示:

// gl_TexCoord[0].st is 0..1, per quad
void main ()
{
    gl_Position = trafoMat * posit;
    // 0..1 UV coordinate
    gl_TexCoord[0] = gl_MultiTexCoord0;
    // Rescale into sub-tile
    gl_TexCoord[0] *= (1/4.0);
    // Add the offset, if your hardware does not support
    // texture fetches in the vertex shader, move this into the
    // fragment shader.
    // gl_MultiTexCoord1 is the 1D offset into the indirection
    // texture
    gl_TexCoord[0] += texture2D(offsetTexture,gl_MultiTexCoord1);
}

// This is the fragment shader!
void main ()
{
    outColor = texture2D(tex,gl_TexCoord[0]);
}

tex纹理最好使用线性滤波,而offsetTexture则需要使用点滤波--你可以通过使用glTexParameter手动设置它们,而不必使用采样器。


我尝试了你的代码。一开始没有子纹理,只是为了看看能否将整个纹理映射到四边形上。如果我在片段着色器中使用outColor = texture2D(tex,gl_TexCoord[0]);我会得到编译失败的结果:'texture2D':找不到匹配的重载函数 'assign':无法将“const float”转换为“float”的4分量向量。 - Fejwin
你必须使用 gl_TexCoord[0].st。代码未经测试,但应该相当接近 ;) - Anteru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接