【问题标题】:Why is the texture coordinate in my fragment shader always (0, 0)?为什么我的片段着色器中的纹理坐标总是 (0, 0)?
【发布时间】:2017-08-17 16:10:40
【问题描述】:

我正在使用 LWJGL 在屏幕上绘制“图块”或带纹理的 2D 方块。但是,纹理坐标始终为 (0, 0),因此纹理正方形仅使用第一个像素颜色来填充它。

这是我的顶点着色器:

#version 330 core

in vec4 in_Position;
in vec4 in_Color;
in vec2 in_TextureCoord;

out vec4 pass_Color;
out vec2 pass_TextureCoord;

void main(void) {
    gl_Position = in_Position;

    pass_Color = in_Color;
    pass_TextureCoord = in_TextureCoord;
} 

这是我的片段着色器:

#version 330 core

uniform sampler2D texture_diffuse;

in vec4 pass_Color;
in vec2 pass_TextureCoord;

out vec4 out_Color;

void main(void) {
    out_Color = pass_Color;
    // Override out_Color with our texture pixel
    out_Color = texture(texture_diffuse, pass_TextureCoord);
} 

这实际上是我用来绘制正方形的代码:

ARBShaderObjects.glUseProgramObjectARB(shaderProgram);  

glBindTexture(GL_TEXTURE_2D, sprite.getId());

glBegin(GL11.GL_QUADS); 
glVertex2d(screenMinX, screenMinY);
glTexCoord2d(0.0, 0.0);
glVertex2d(screenMaxX, screenMinY);
glTexCoord2d(1.0, 0.0);
glVertex2d(screenMaxX, screenMaxY);
glTexCoord2d(1.0, 1.0);
glVertex2d(screenMinX, screenMaxY);
glTexCoord2d(0.0, 1.0);
glEnd();

// release the shader
ARBShaderObjects.glUseProgramObjectARB(0);

我无法修复它,因为我不知道上面的代码是如何工作的。我没有告诉着色器in_Positionin_Colorin_TextureCoord 是什么,但前两个似乎工作得很好。它是in_TextureCoord,最终传递给片段着色器,它似乎有一个恒定值 (0, 0) - 我已经确定通过将片段着色器的输出颜色设置为具有等于的通道之一纹理坐标的 X 坐标。它在整个正方形中保持纯色,表明纹理坐标没有变化。

用上面的代码生成的正方形应该是有纹理的,而是涂成纯色 - 给定纹理的第一个像素。如何更改代码以使纹理坐标相应更改?如果我似乎对这一切如何组合在一起有一些误解,请纠正我。

This 是我用来完成上述任务的教程。

附言我知道 Java sn-p 正在使用deprecated immediate-mode,但我不知道如何使用 glDrawArrays 或任何其他常用的方法来完成相同的操作。你能帮我改一下吗?

【问题讨论】:

  • "这基本上就是我用来绘制正方形的代码:" 好吧,你从来没有设置任何纹理坐标,那么你为什么期望它们不是 0、0 呢?
  • @tkausl 如何为每个单独的像素设置纹理坐标?这让我很困惑,因为 OpenGL 似乎在内部处理像素。

标签: java opengl shader lwjgl


【解决方案1】:

我知道 Java sn-p 正在使用已弃用的立即模式,但我不知道如何使用 glDrawArrays 或任何其他通常建议的方法来完成相同的操作。你能帮我改一下吗?

由于您不再需要属性in_Color,您必须从顶点着色器中删除该属性(当然还有从顶点着色器和片段着色器中删除pass_Color)。
否则,您必须通过颜色属性在逻辑上扩展我的解决方案。

为顶点位置和纹理坐标设置一个数组:

float[] posData = {
    screenMinX, screenMinY, 0.0, 1.0,
    screenMaxX, screenMinY, 0.0, 1.0,
    screenMaxX, screenMaxY, 0.0, 1.0,
    screenMinX, screenMaxY, 0.0, 1.0 };

float[] texData = { 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0 };

生成一个顶点数组对象:

int  vaoObj = glGenVertexArrays();
glBindVertexArray(vaoObj);

为顶点和纹理坐标生成数组缓冲区,启用属性索引并将它们关联到属性索引的缓冲区:

FloatBuffer posBuffer = MemoryUtil.memAllocFloat(posData.length);
posBuffer.put(posData).flip();
FloatBuffer texBuffer = MemoryUtil.memAllocFloat(texData.length);
texBuffer.put(texData).flip();

int vboPosObj = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboPosObj);
glBufferData(GL_ARRAY_BUFFER, posBuffer, GL_STATIC_DRAW);

// index 0 to associate with "in_Position"            
glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, 0); 
glEnableVertexAttribArray(0); // 0 = attribute index of "in_Position"

int vboTexObj = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboTexObj);
glBufferData(GL_ARRAY_BUFFER, texBuffer, GL_STATIC_DRAW);

// index 0 to associate with "in_TextureCoord"
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(1); // 1 = attribute index of "in_TextureCoord"

释放顶点数组对象:

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);


您必须指定属性in_Positionin_TextureCoord 的属性索引。

要么在顶点着色器中使用显式布局规范:

layout (location = 0) in vec4 in_Position;
layout (location = 1) in vec2 in_TextureCoord;

或者您在着色器程序中指定属性索引,链接着色器程序之前(glLinkProgram)。

glBindAttribLocation(shaderProgramID, 0, "in_Position");
glBindAttribLocation(shaderProgramID, 1, "in_TextureCoord");


如果要绘制对象,绑定顶点数组对象就足够了:

glBindVertexArray(vaoObj);
glDrawArrays(GL_QUADS, 0, 4); // 4 = number of vertices 
glBindVertexArray(0);

注意,如果缓冲区对象或顶点数组对象没有被进一步使用,则必须将其删除,以防止内存泄漏。缓冲区对象被glDeleteBuffers 删除,顶点数组对象被glDeleteVertexArrays 删除。 缓冲区对象不是“在”顶点数组对象下“创建”的,仅删除顶点数组对象是不够的(参见OpenGL Vertex Array/Buffer Objects

【讨论】:

  • 感谢您的回复。我以前试过这个,但没有任何改变。现在也是这样。
  • 非常感谢。这解决了我的问题,尽管我必须删除大代码块中的两个 glBindVertexArray(0) 实例(将一个移动到 glDrawArrays 调用下方)以防止 glDrawArrays 上的 EXCEPTION_ACCESS_VIOLATION。我还必须将 GL_TRIANGLES 更改为 GL_QUADS 才能让它像原来一样绘制正方形。我认为这个答案将是我未来渲染的首选资源。
  • 你可以看看这个Book - OpenGL Programming Guide 8th Edition。它详细描述了OpenGL。此外,您正在尝试做的事情将在第一章中直接讨论。
  • @Rabbid76 我认为您应该在答案中包含一些内容:如果在循环中执行此操作,则有必要使用glDeleteVertexArrays 和(可能)glDeleteBuffers 以防止非常严重的内存泄漏。
【解决方案2】:

如果您使用需要使用框来显示一些适合整个框区域的纹理图像,您可以使用两个三角形,并使用以下参数用于 -1,-1 到 1,1 区域(可以与适当的着色器显示)。

顶点(两个三角形坐标):

-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f

然后使用可以使用以下纹理坐标进行全尺寸:

0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-03
    • 1970-01-01
    • 1970-01-01
    • 2013-09-17
    • 2015-03-26
    • 2015-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多