NDC 坐标而非屏幕坐标 (2D) 中的 OpenGL 转换
OpenGL transformation in NDC coordinates instead of screen coordinates (2D)
我无法弄清楚如何使用屏幕坐标在我的场景中定位 2D 对象。目前我有一些工作(下面的代码)但它想要 NDC 坐标,这不容易使用。我不知道哪里出了问题。我想我已经按应有的方式使用了所有东西,所以我想我忘记了什么。
下面是处理场景中对象绘制的代码:
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// RENDERING HERE
colorProgram.bind();
for (size_t t = 0; t < objectsWithGraphicsComponentInThisScene.size(); ++t)
{
// set texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, objectsWithGraphicsComponentInThisScene[t]->getComponent<GraphicsComponent>()->getTexture());
GLint texLocation = colorProgram.getUniformLocation("texSampler");
glUniform1i(texLocation, 0);
glm::mat4 trans;
trans = glm::translate(glm::mat4x4(1.0f), glm::vec3(objectsWithGraphicsComponentInThisScene[t]->getPosition().x, objectsWithGraphicsComponentInThisScene[t]->getPosition().y, 0));
GLint transMatLocation = colorProgram.getUniformLocation("transformMatrix");
glUniformMatrix4fv(transMatLocation, 1, GL_FALSE, glm::value_ptr(trans));
// set camera Matrix
GLint projMatLocation = colorProgram.getUniformLocation("projectionMatrix");
glm::mat4 cameraMatrix = camera->getCameraMatrix();
glUniformMatrix4fv(projMatLocation, 1, GL_FALSE, glm::value_ptr(cameraMatrix));
objectsWithGraphicsComponentInThisScene[t]->getComponent<GraphicsComponent>()->getSprite()->draw();
// unbind all
glBindTexture(GL_TEXTURE_2D, 0);
}
colorProgram.unbind();
其中 colorProgram 是我的精灵使用的着色器,getPosition()
只是 return 我设置的值。 (其中 x y 和 z 值应作为屏幕坐标给出)。因此,例如,getPosition 可能 return [100, 50, 0] 但这会将对象呈现在屏幕之外(屏幕为 1280x720)。
现在是渲染精灵的代码 (objectsWithGraphicsComponentInThisScene[t]->getComponent()->getSprite()->draw();):
void Sprite::draw()
{
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glEnableVertexAttribArray(0);
// position
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
//color
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color));
// uv
glVertexAttribPointer(2, 2, GL_FLOAT, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, uv));
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
这是着色器 (colorProgram) 中的代码:
顶点着色器:
#version 130
// per vertex
// input data from VBO
in vec2 vertexPosition;
in vec4 vertexColor;
in vec2 vertexUV;
// output to fragment shader
out vec4 fragmentColor;
out vec2 fragmentUV;
uniform mat4 projectionMatrix;
uniform mat4 transformMatrix;
void main()
{
mat4 resultMatrix = transformMatrix * projectionMatrix;
gl_Position.xy = (resultMatrix * vec4(vertexPosition, 0.0, 1.0)).xy;
gl_Position.z = 0.0;
// Indicate that the coordinates are normalized
gl_Position.w = 1.0;
fragmentColor = vertexColor;
fragmentUV = vec2(vertexUV.x, 1.0 - vertexUV.y);
}
片段着色器
#version 130
// per pixel
// input from vertex shader
in vec4 fragmentColor;
in vec2 fragmentUV;
out vec4 color;
uniform sampler2D texSampler;
void main()
{
vec4 textureColor = texture(texSampler, fragmentUV);
if (textureColor.a < 0.5) discard;
color = fragmentColor * textureColor;
}
如果您需要更多代码,我很乐意添加更多代码,尽管我认为这就是所需的一切。
顶点着色器中的这个序列
mat4 resultMatrix = transformMatrix * projectionMatrix;
gl_Position.xy = (resultMatrix * vec4(vertexPosition, 0.0, 1.0)).xy;
不太可能是您真正想要的。由于您使用 matrix * vector 约定,因此您最终会得到
position = transform * projection * v
= transform * (projection * v)
换句话说:在 投影之后应用变换。由于在投影之后,观看体积在 [-1,1]^3 范围内(在透视划分之后的欧几里德 NDC space 中。实际上,我们在这里工作在剪辑 space 中,其中它是 [-w,w]^3,但这在这种情况下并不重要,),将对象平移 100 个单位肯定会将其移出平截头体。
您应该只颠倒矩阵乘法的顺序。
我无法弄清楚如何使用屏幕坐标在我的场景中定位 2D 对象。目前我有一些工作(下面的代码)但它想要 NDC 坐标,这不容易使用。我不知道哪里出了问题。我想我已经按应有的方式使用了所有东西,所以我想我忘记了什么。
下面是处理场景中对象绘制的代码:
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// RENDERING HERE
colorProgram.bind();
for (size_t t = 0; t < objectsWithGraphicsComponentInThisScene.size(); ++t)
{
// set texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, objectsWithGraphicsComponentInThisScene[t]->getComponent<GraphicsComponent>()->getTexture());
GLint texLocation = colorProgram.getUniformLocation("texSampler");
glUniform1i(texLocation, 0);
glm::mat4 trans;
trans = glm::translate(glm::mat4x4(1.0f), glm::vec3(objectsWithGraphicsComponentInThisScene[t]->getPosition().x, objectsWithGraphicsComponentInThisScene[t]->getPosition().y, 0));
GLint transMatLocation = colorProgram.getUniformLocation("transformMatrix");
glUniformMatrix4fv(transMatLocation, 1, GL_FALSE, glm::value_ptr(trans));
// set camera Matrix
GLint projMatLocation = colorProgram.getUniformLocation("projectionMatrix");
glm::mat4 cameraMatrix = camera->getCameraMatrix();
glUniformMatrix4fv(projMatLocation, 1, GL_FALSE, glm::value_ptr(cameraMatrix));
objectsWithGraphicsComponentInThisScene[t]->getComponent<GraphicsComponent>()->getSprite()->draw();
// unbind all
glBindTexture(GL_TEXTURE_2D, 0);
}
colorProgram.unbind();
其中 colorProgram 是我的精灵使用的着色器,getPosition()
只是 return 我设置的值。 (其中 x y 和 z 值应作为屏幕坐标给出)。因此,例如,getPosition 可能 return [100, 50, 0] 但这会将对象呈现在屏幕之外(屏幕为 1280x720)。
现在是渲染精灵的代码 (objectsWithGraphicsComponentInThisScene[t]->getComponent()->getSprite()->draw();):
void Sprite::draw()
{
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glEnableVertexAttribArray(0);
// position
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
//color
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color));
// uv
glVertexAttribPointer(2, 2, GL_FLOAT, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, uv));
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
这是着色器 (colorProgram) 中的代码: 顶点着色器:
#version 130
// per vertex
// input data from VBO
in vec2 vertexPosition;
in vec4 vertexColor;
in vec2 vertexUV;
// output to fragment shader
out vec4 fragmentColor;
out vec2 fragmentUV;
uniform mat4 projectionMatrix;
uniform mat4 transformMatrix;
void main()
{
mat4 resultMatrix = transformMatrix * projectionMatrix;
gl_Position.xy = (resultMatrix * vec4(vertexPosition, 0.0, 1.0)).xy;
gl_Position.z = 0.0;
// Indicate that the coordinates are normalized
gl_Position.w = 1.0;
fragmentColor = vertexColor;
fragmentUV = vec2(vertexUV.x, 1.0 - vertexUV.y);
}
片段着色器
#version 130
// per pixel
// input from vertex shader
in vec4 fragmentColor;
in vec2 fragmentUV;
out vec4 color;
uniform sampler2D texSampler;
void main()
{
vec4 textureColor = texture(texSampler, fragmentUV);
if (textureColor.a < 0.5) discard;
color = fragmentColor * textureColor;
}
如果您需要更多代码,我很乐意添加更多代码,尽管我认为这就是所需的一切。
顶点着色器中的这个序列
mat4 resultMatrix = transformMatrix * projectionMatrix;
gl_Position.xy = (resultMatrix * vec4(vertexPosition, 0.0, 1.0)).xy;
不太可能是您真正想要的。由于您使用 matrix * vector 约定,因此您最终会得到
position = transform * projection * v
= transform * (projection * v)
换句话说:在 投影之后应用变换。由于在投影之后,观看体积在 [-1,1]^3 范围内(在透视划分之后的欧几里德 NDC space 中。实际上,我们在这里工作在剪辑 space 中,其中它是 [-w,w]^3,但这在这种情况下并不重要,),将对象平移 100 个单位肯定会将其移出平截头体。
您应该只颠倒矩阵乘法的顺序。