OpenGL片段着色器和原始贴图数据

3
所以我最近一直在学习OpenGL。一开始我使用SDL库来在屏幕上打印图像,但是我认为使用OpenGL实现类似的效果会更有趣,这样还能够应用着色器到我的图像上,实现像光照和昼夜变化等炫酷的效果。目前我所做的只是加载一张纹理,并将其应用于一个和纹理大小相同的矩形中,这个方法很有效。

现在我想要应用一些着色器。以下是一个顶点着色器和片段着色器的示例,我可以将其应用于我的纹理矩形之一:

in vec2 LVertexPos2D; 
void main()
 { 
      gl_Position = vec4( LVertexPos2D.x, LVertexPos2D.y, 0, 1); 
 }

如果我的片元着色器什么也没有做,那么它应该如下所示:

out vec4 LFragment;
void main()
{
LFragment = vec4(1.0, 1.0, 1.0, 1.0);
}

很明显,这只是将我所应用的纹理转变为白块,这并不是我想要的。无论如何,我需要检索当前的像素数据,以便修改它,而不仅仅是改变它。
我已经阅读了有关texture2D函数调用应返回当前像素数据的vec4的信息,但我还没有让它起作用。(很难找到一个关于函数输入及其工作原理的好解释)。此外,据说texture2D已经被废弃,但我也无法让它的替代品(texture())起作用。任何指引都将不胜感激!
编辑:我将加入一些有关我正在处理的内容的更多信息,这是加载我的纹理的函数:
texture makeTexture(std::string fileLocation)
{
    texture tempTexture;
    SDL_Surface *mySurface = IMG_Load(fileLocation.c_str());
    if (mySurface == NULL)
    {
        std::cout << "Error in loading image at: " << fileLocation << std::endl;
        return tempTexture;
    }

    GLuint myTexture;
    glGenTextures(1, &myTexture);
    glBindTexture(GL_TEXTURE_2D, myTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mySurface->w, mySurface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, mySurface->pixels);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);
    SDL_FreeSurface(mySurface);
    tempTexture.texture_id = myTexture;
    tempTexture.h = mySurface->h;
    tempTexture.w = mySurface->w;
    return tempTexture;
}

这是我的纹理结构体:

struct texture
{
    int w;
    int h;
    GLuint texture_id;
};

并且这个函数可以将任何纹理画到指定的x和y坐标:

void draw(int y, int x, texture &tempTexture)
{
    glBindTexture(GL_TEXTURE_2D, tempTexture.texture_id);
    glBegin(GL_QUADS);
    glTexCoord2f(0, 1);
    glVertex2f(-1 + ((float)(x) / SCREEN_WIDTH) * 2, 1 - ((float)(y + tempTexture.h) / SCREEN_HEIGHT) * 2); //Bottom left
    glTexCoord2f(1, 1);
    glVertex2f(-1 + ((float)(x + tempTexture.w)/SCREEN_WIDTH)*2, 1 - ((float)(y + tempTexture.h) / SCREEN_HEIGHT) * 2); //Bottom right?
    glTexCoord2f(1, 0);
    glVertex2f(-1 + ((float)(x + tempTexture.w) / SCREEN_WIDTH) * 2, 1.0 - ((float)y / SCREEN_HEIGHT) * 2); //top right
    glTexCoord2f(0, 0);
    glVertex2f(-1 + ((float)(x) / SCREEN_WIDTH) * 2, 1.0 - ((float)y / SCREEN_HEIGHT) * 2); //Top left (notification: Coordinates are (x,y), not (y,x).
    glEnd();
    glBindTexture(GL_TEXTURE_2D, 0);
}

然后在我的主渲染函数中,我现在正在执行以下操作:

draw(0, 0, myTexture);
glUseProgram(gProgramID);
glUniform1i(baseImageLoc, myTexture2.texture_id);
draw(100, 100, myTexture2);
glUseProgram(NULL);

其中,我的纹理是一个草地,而myTexture2是一个玩家角色,我想对其应用一些阴影效果。gProgramID是一个程序,它已经加载了我前面提到的两个着色器。


我还想补充一点,我看到其他人也有类似的问题(例如http://gamedev.stackexchange.com/questions/77751/how-to-change-pixel-color-of-texture-with-fragment-shader),但是应用那个解决方案只会使我的纹理变成透明的。 - user3932479
1个回答

3
为了在着色器中访问纹理数据,您需要执行以下操作:
  • 首先,您需要使用glActiveTexture更改活动纹理单元,并将纹理绑定到特定的纹理单元上。
  • 将纹理单元索引作为统一采样器传递给着色器。
  • 在着色器中访问纹理如下:

    // tex保存要使用的纹理单元的值(而非纹理) uniform sampler2D tex;

    void main() { vec4 color = texture(tex,texCoord); LFragment = color; }

您还需要将texCoords作为in顶点属性传递到着色器中。


好的,谢谢。当你说传递纹理单元时,你是指纹理ID吗?我正在尝试你所说的,但现在我的纹理只是一个黑色的正方形,所以我想我仍然做错了什么。在我的当前设置中,我甚至没有使用glActiveTexture。 - user3932479
啊,好的,我现在调用glActiveTexture(GL_TEXTURE0),然后我执行glBindTexture(GL_TEXTURE_2D, myTexture2.texture_ID),接着我执行glUseProgram(gProgramID),并尝试通过以下方式传递纹理单元:GLint baseImageLoc = glGetUniformLocation(gProgramID, "tex"),然后执行glUniform1i(baseImageLoc, GL_TEXTURE0);但是它仍然显示我的纹理只是一个黑色正方形。 - user3932479
搞定了,谢谢!你给了我正确的方向。 - user3932479
@user3932479пјҡиҝҷеҸҜиғҪжҳҜдҪ е·Із»ҸжғіеҲ°зҡ„пјҢдҪҶд»ҘйҳІдёҮдёҖгҖӮеңЁиҝҷз§Қжғ…еҶөдёӢпјҢжӮЁдј йҖ’з»ҷglUniform1i()зҡ„зә№зҗҶеҚ•е…ғзҡ„еҖјеә”иҜҘжҳҜ0пјҢиҖҢдёҚжҳҜGL_TEXTURE0гҖӮе®ғеҸӘжҳҜзә№зҗҶеҚ•е…ғзҡ„зҙўеј•пјҢиҖҢдёҚжҳҜжһҡдёҫеҖјгҖӮ - Reto Koradi

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