【问题标题】:OpenGL/GLSL - Writing A Smart Texture ShaderOpenGL/GLSL - 编写智能纹理着色器
【发布时间】:2011-10-08 19:53:01
【问题描述】:

假设我的纹理是 256x256 像素。它包含 16 个 64x64 像素的子纹理。子纹理将被渲染为四边形。为了提高性能,我想将离散值传递给每个顶点纹理坐标编码的着色器。例如值 0、1、2、3 应该对应于每个顶点纹理坐标的 (0,64)、(64,64)、(64,0)、(0,0) 等。

这是我目前所拥有的。

我加载并绑定了一个 mipmap 纹理:

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() )。

【问题讨论】:

    标签: opengl glsl textures shader


    【解决方案1】:

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

    其次,您需要point-sample 到间接纹理中,以找出从实际纹理中采样的位置。假设您的四边形有 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'转换为'out 4-component vector of float'。
    • 您必须使用 gl_TexCoord[0].st。代码未经测试,但应该相当接近;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多