openGL 4,翻译和缩放出错
openGL 4, translate and scale going wrong
我正在尝试在代表地图的平面上进行正投影 - 想想“平面图”。我 运行 遇到了麻烦,因为 openGL 4 对我来说是新的(我上次使用的是 1.1,世界已经改变了)并且因为我正在尝试做的事情与网上常见的例子不太一样。我的问题是缩放和平移。
描述地图的数据是一系列带有端点的线,我称之为“地牢坐标单位”。当我渲染图像时,我希望有一个固定的规则“1 个单位是 1 个像素”。
我的坐标都在第一象限,(0,0)代表地图的左下角。我希望 (0,0) 显示在屏幕的左下方。
现在是棘手的部分。当我在片段着色器中渲染“地板”时,我被交给 gl_FragCoord,这是理想的。它实际上是一个像素位置,这意味着就我的目的而言,它相当于一个地牢坐标。我可以查找我传递给着色器的所有信息(也在地牢坐标中)并弄清楚如何绘制(或丢弃)该像素。它有效,除了……它绘制的 (0,0) 位于屏幕中央,而不是左下角。
更糟糕的是,有些东西,比如线条(“墙”),我在第二遍中用地牢坐标中的细三角形渲染。他们没有出现在我想要的地方。 (事实上我很确定我用来铺地板的三角形也是错误的,只是巧合地覆盖了屏幕。)
我真的非常需要 openGL 使用坐标系将 0,0 放在图像的左下角并让我以我的单位指定三角形顶点,这些顶点恰好直接映射到像素。
这似乎是一个简单的缩放和平移案例。但是我显然应用了比例尺并且翻译不正确。
顶点代码很简单:
#version 430
layout (location = 0) in vec3 Position;
uniform mat4 gWorld;
out vec4 Color; //unused; the fragment shader caslculates all colors
void main()
{
gl_Position = gWorld * vec4(Position, 1.0);
}
为地图地板构建 2 个三角形(现在是一个简单的矩形)看起来很简单:
Vector3f Vertices[4];
Vertices[0] = Vector3f(0.f, 0.f, 0.0f);
Vertices[1] = Vector3f(0.f, mapEdges.maxs.y, 0.0f);
Vertices[2] = Vector3f(mapEdges.maxs.x, 0.f, 0.0f);
Vertices[3] = Vector3f(mapEdges.maxs.x, mapEdges.maxs.y, 0.0f);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
unsigned int Indices[] = { 0, 1, 2,
1, 2, 3 };
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
我为他们使用了索引绘制。
C++代码(使用glm)设置世界矩阵:
glUseProgram(ShaderProgram); //this selects the shader
gWorldLocation = glGetUniformLocation(ShaderProgram, "gWorld");
assert(gWorldLocation != 0xFFFFFFFF);
...渲染时...
//try to fix openGL’s desire to think my buffer is -1 to 1 across
float scale = 1/1024.f; //test map is about 1024 units across
glm::mat4 sm = glm::scale(
glm::mat4( 1.0f ),
glm::vec3( scale, scale, 1.0f )
);
glm::mat4 ts = glm::translate(
sm,
glm::vec3( -512.0f, -512.0f, 0.0f ) //shove left and down
);
glUniformMatrix4fv(gWorldLocation, 1, GL_TRUE, &ts[0][0]);
因为我的测试地图大约有 1024 个单位,我原以为这会把东西推到位。但不是。地板(请记住,它使用 gl_FragCoord 来决定在哪里和画什么)是从屏幕中心向上和向右绘制的,尽管它看起来像我期望的那样。在地牢坐标中用瘦削的三角形绘制的墙壁无处可见,可能在某处缩小到以太中。
基本上我无法说服 openGL 我想让 x=0 成为图像的左边缘,而且我的缩放比例显然是完全错误的。遗憾的是,我有一个版本曾(错误地)在屏幕上画了一些墙,但我没有那个代码了。不过,它告诉我,我并没有完全放弃生成墙壁,只是将它们放下。
如何让 openGL 使用我的单位?
当你设置矩阵统一时,你转置了矩阵。因为在你的着色器程序中向量从右边乘以矩阵,这是错误的。参见 GLSL Programming/Vector and Matrix Operations
glUniformMatrix4fv(gWorldLocation, 1, GL_TRUE, &ts[0][0]);
glUniformMatrix4fv(gWorldLocation, 1, GL_FALSE, &ts[0][0]);
您可以使用 glm::ortho
:
矩阵设置正交投影,而不是缩放和平移顶点
glm::mat4 projection = glm::ortho(0.0f, 1024.0f, 0.0f, 1024.0f, -1.0f, 1.0f);
glUniformMatrix4fv(gWorldLocation, 1, GL_FALSE, glm::value_ptr(projection));
我正在尝试在代表地图的平面上进行正投影 - 想想“平面图”。我 运行 遇到了麻烦,因为 openGL 4 对我来说是新的(我上次使用的是 1.1,世界已经改变了)并且因为我正在尝试做的事情与网上常见的例子不太一样。我的问题是缩放和平移。
描述地图的数据是一系列带有端点的线,我称之为“地牢坐标单位”。当我渲染图像时,我希望有一个固定的规则“1 个单位是 1 个像素”。
我的坐标都在第一象限,(0,0)代表地图的左下角。我希望 (0,0) 显示在屏幕的左下方。
现在是棘手的部分。当我在片段着色器中渲染“地板”时,我被交给 gl_FragCoord,这是理想的。它实际上是一个像素位置,这意味着就我的目的而言,它相当于一个地牢坐标。我可以查找我传递给着色器的所有信息(也在地牢坐标中)并弄清楚如何绘制(或丢弃)该像素。它有效,除了……它绘制的 (0,0) 位于屏幕中央,而不是左下角。
更糟糕的是,有些东西,比如线条(“墙”),我在第二遍中用地牢坐标中的细三角形渲染。他们没有出现在我想要的地方。 (事实上我很确定我用来铺地板的三角形也是错误的,只是巧合地覆盖了屏幕。)
我真的非常需要 openGL 使用坐标系将 0,0 放在图像的左下角并让我以我的单位指定三角形顶点,这些顶点恰好直接映射到像素。
这似乎是一个简单的缩放和平移案例。但是我显然应用了比例尺并且翻译不正确。
顶点代码很简单:
#version 430
layout (location = 0) in vec3 Position;
uniform mat4 gWorld;
out vec4 Color; //unused; the fragment shader caslculates all colors
void main()
{
gl_Position = gWorld * vec4(Position, 1.0);
}
为地图地板构建 2 个三角形(现在是一个简单的矩形)看起来很简单:
Vector3f Vertices[4];
Vertices[0] = Vector3f(0.f, 0.f, 0.0f);
Vertices[1] = Vector3f(0.f, mapEdges.maxs.y, 0.0f);
Vertices[2] = Vector3f(mapEdges.maxs.x, 0.f, 0.0f);
Vertices[3] = Vector3f(mapEdges.maxs.x, mapEdges.maxs.y, 0.0f);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
unsigned int Indices[] = { 0, 1, 2,
1, 2, 3 };
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
我为他们使用了索引绘制。
C++代码(使用glm)设置世界矩阵:
glUseProgram(ShaderProgram); //this selects the shader
gWorldLocation = glGetUniformLocation(ShaderProgram, "gWorld");
assert(gWorldLocation != 0xFFFFFFFF);
...渲染时...
//try to fix openGL’s desire to think my buffer is -1 to 1 across
float scale = 1/1024.f; //test map is about 1024 units across
glm::mat4 sm = glm::scale(
glm::mat4( 1.0f ),
glm::vec3( scale, scale, 1.0f )
);
glm::mat4 ts = glm::translate(
sm,
glm::vec3( -512.0f, -512.0f, 0.0f ) //shove left and down
);
glUniformMatrix4fv(gWorldLocation, 1, GL_TRUE, &ts[0][0]);
因为我的测试地图大约有 1024 个单位,我原以为这会把东西推到位。但不是。地板(请记住,它使用 gl_FragCoord 来决定在哪里和画什么)是从屏幕中心向上和向右绘制的,尽管它看起来像我期望的那样。在地牢坐标中用瘦削的三角形绘制的墙壁无处可见,可能在某处缩小到以太中。
基本上我无法说服 openGL 我想让 x=0 成为图像的左边缘,而且我的缩放比例显然是完全错误的。遗憾的是,我有一个版本曾(错误地)在屏幕上画了一些墙,但我没有那个代码了。不过,它告诉我,我并没有完全放弃生成墙壁,只是将它们放下。
如何让 openGL 使用我的单位?
当你设置矩阵统一时,你转置了矩阵。因为在你的着色器程序中向量从右边乘以矩阵,这是错误的。参见 GLSL Programming/Vector and Matrix Operations
glUniformMatrix4fv(gWorldLocation, 1, GL_TRUE, &ts[0][0]);
glUniformMatrix4fv(gWorldLocation, 1, GL_FALSE, &ts[0][0]);
您可以使用 glm::ortho
:
glm::mat4 projection = glm::ortho(0.0f, 1024.0f, 0.0f, 1024.0f, -1.0f, 1.0f);
glUniformMatrix4fv(gWorldLocation, 1, GL_FALSE, glm::value_ptr(projection));