OpenGL 正交投影和平移
OpenGL Orthographic Projection and Translate
下面的代码使用 OpenGL ES2 在二维屏幕中绘制一个矩形 space。如何在不修改矩形顶点的情况下将绘制的矩形向右移动 1 个像素?
具体来说,我要做的是将坐标向右移动 0.5 个像素。我以前必须用 GLES1.x 来做这个,原因是我在正确的地方画线有问题,除非我用 0.5f.
做了一个 glTranslate()
我对下面代码中 glm::translate() 的使用感到困惑。
如果我尝试平移 0.5f,整个矩形会从屏幕左侧移动到中间 - 跳跃大约 200 像素。
无论我在模型或视图矩阵上执行 glm::translate,我都会得到相同的结果。
矩阵相乘的顺序是不是错了,应该是什么?
short g_RectFromTriIndices[] =
{
0, 1, 2,
0, 2, 3
}; // The order of vertex rendering.
GLfloat g_AspectRatio = 1.0f;
//--------------------------------------------------------------------------------------------
// LoadTwoTriangleVerticesForRect()
//--------------------------------------------------------------------------------------------
void LoadTwoTriangleVerticesForRect( GLfloat *pfRectVerts, float fLeft, float fTop, float fWidth, float fHeight )
{
pfRectVerts[ 0 ] = fLeft;
pfRectVerts[ 1 ] = fTop;
pfRectVerts[ 2 ] = 0.0;
pfRectVerts[ 3 ] = fLeft + fWidth;
pfRectVerts[ 4 ] = fTop;
pfRectVerts[ 5 ] = 0.0;
pfRectVerts[ 6 ] = fLeft + fWidth;
pfRectVerts[ 7 ] = fTop + fHeight;
pfRectVerts[ 8 ] = 0.0;
pfRectVerts[ 9 ] = fLeft;
pfRectVerts[ 10 ] = fTop + fHeight;
pfRectVerts[ 11 ] = 0.0;
}
//--------------------------------------------------------------------------------------------
// Draw()
//--------------------------------------------------------------------------------------------
void Draw( void )
{
GLfloat afRectVerts[ 12 ];
//LoadTwoTriangleVerticesForRect( afRectVerts, 0, 0, g_ScreenWidth, g_ScreenHeight );
LoadTwoTriangleVerticesForRect( afRectVerts, 50, 50, 100, 100 );
// Correct for aspect ratio so squares ARE squares and not rectangular stretchings..
g_AspectRatio = (GLfloat) g_ScreenWidth / (GLfloat) g_ScreenHeight;
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
GLuint hPosition = glGetAttribLocation( g_SolidProgram, "vPosition" );
// PROJECTION
glm::mat4 Projection = glm::mat4(1.0);
// Projection = glm::perspective( 45.0f, g_AspectRatio, 0.1f, 100.0f );
// VIEW
glm::mat4 View = glm::mat4(1.0);
static GLfloat transValY = 0.5f;
static GLfloat transValX = 0.5f;
//View = glm::translate( View, glm::vec3( transValX, transValY, 0.0f ) );
// MODEL
glm::mat4 Model = glm::mat4(1.0);
// static GLfloat rot = 0.0f;
// rot += 0.001f;
// Model = glm::rotate( Model, rot, glm::vec3( 0.0f, 0.0f, 1.0f ) ); // where x, y, z is axis of rotation (e.g. 0 1 0)
glm::mat4 Ortho = glm::ortho( 0.0f, (GLfloat) g_ScreenWidth, (GLfloat) g_ScreenHeight, 0.0f, 0.0f, 1000.0f );
glm::mat4 MVP;
MVP = Projection * View * Model * Ortho;
GLuint hMVP;
hMVP = glGetUniformLocation( g_SolidProgram, "MVP" );
glUniformMatrix4fv( hMVP, 1, GL_FALSE, glm::value_ptr( MVP ) );
glEnableVertexAttribArray( hPosition );
// Prepare the triangle coordinate data
glVertexAttribPointer( hPosition, 3, GL_FLOAT, FALSE, 0, afRectVerts );
// Draw the rectangle using triangles
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, g_RectFromTriIndices );
glDisableVertexAttribArray( hPosition );
}
这是顶点着色器源代码:
attribute vec4 vPosition;
uniform mat4 MVP;
void main()
{
gl_Position = MVP * vPosition;
}
更新:我发现下面的矩阵乘法给我更好的结果。我不知道这是 "correct" 还是不是:
MVP = Ortho * Model * View * Projection;
那个 MVP 对我来说真的很奇怪,你不应该需要 4 个东西来获得你的 MVP..你的投影矩阵应该只是正交矩阵,所以在这种情况下
MVP = Projection * View * Ortho;
但我也可以看到您的投影矩阵已经从透视角度进行了评论,所以我认为它现在做的不多。
听起来既然你想让模型坐标在移动时保持不变,你想移动你的相机吗?所以(从它的外观来看,你的顶点使用每像素 1 个单位的坐标范围)对你的视图进行 0.5f 的平移会移动你的投影 space 的一半。相反,您想要 Camera
class 之类的东西,您可以通过使用相机的 X
和 Y
位置获得 View
。
然后您可以使用相机位置获取您的视图矩阵,它可以共享您正在使用的世界单位系统,即每像素 1 个单位。
glm::mat4 view;
view = glm::lookAt(glm::vec3(camX, camY, 0.0), glm::vec3(0.0, 0.0, 0.0),glm::vec3(0.0, 1.0, 0.0));
我从一个非常好的相机 3d 教程中直接撕下了这条线(减去 camY 的 camZ)here 但完全相同的概念可以应用于正交相机
我知道这会增加一些开销,但是拥有一个可以通过这种方式控制的 cmaera class 比手动使用 glm::translate,rotate&scale 来控制视口更好(并且它可以确保您正在使用相机和模型坐标点之间更明显的坐标系。
下面的代码使用 OpenGL ES2 在二维屏幕中绘制一个矩形 space。如何在不修改矩形顶点的情况下将绘制的矩形向右移动 1 个像素?
具体来说,我要做的是将坐标向右移动 0.5 个像素。我以前必须用 GLES1.x 来做这个,原因是我在正确的地方画线有问题,除非我用 0.5f.
做了一个 glTranslate()我对下面代码中 glm::translate() 的使用感到困惑。
如果我尝试平移 0.5f,整个矩形会从屏幕左侧移动到中间 - 跳跃大约 200 像素。
无论我在模型或视图矩阵上执行 glm::translate,我都会得到相同的结果。
矩阵相乘的顺序是不是错了,应该是什么?
short g_RectFromTriIndices[] =
{
0, 1, 2,
0, 2, 3
}; // The order of vertex rendering.
GLfloat g_AspectRatio = 1.0f;
//--------------------------------------------------------------------------------------------
// LoadTwoTriangleVerticesForRect()
//--------------------------------------------------------------------------------------------
void LoadTwoTriangleVerticesForRect( GLfloat *pfRectVerts, float fLeft, float fTop, float fWidth, float fHeight )
{
pfRectVerts[ 0 ] = fLeft;
pfRectVerts[ 1 ] = fTop;
pfRectVerts[ 2 ] = 0.0;
pfRectVerts[ 3 ] = fLeft + fWidth;
pfRectVerts[ 4 ] = fTop;
pfRectVerts[ 5 ] = 0.0;
pfRectVerts[ 6 ] = fLeft + fWidth;
pfRectVerts[ 7 ] = fTop + fHeight;
pfRectVerts[ 8 ] = 0.0;
pfRectVerts[ 9 ] = fLeft;
pfRectVerts[ 10 ] = fTop + fHeight;
pfRectVerts[ 11 ] = 0.0;
}
//--------------------------------------------------------------------------------------------
// Draw()
//--------------------------------------------------------------------------------------------
void Draw( void )
{
GLfloat afRectVerts[ 12 ];
//LoadTwoTriangleVerticesForRect( afRectVerts, 0, 0, g_ScreenWidth, g_ScreenHeight );
LoadTwoTriangleVerticesForRect( afRectVerts, 50, 50, 100, 100 );
// Correct for aspect ratio so squares ARE squares and not rectangular stretchings..
g_AspectRatio = (GLfloat) g_ScreenWidth / (GLfloat) g_ScreenHeight;
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
GLuint hPosition = glGetAttribLocation( g_SolidProgram, "vPosition" );
// PROJECTION
glm::mat4 Projection = glm::mat4(1.0);
// Projection = glm::perspective( 45.0f, g_AspectRatio, 0.1f, 100.0f );
// VIEW
glm::mat4 View = glm::mat4(1.0);
static GLfloat transValY = 0.5f;
static GLfloat transValX = 0.5f;
//View = glm::translate( View, glm::vec3( transValX, transValY, 0.0f ) );
// MODEL
glm::mat4 Model = glm::mat4(1.0);
// static GLfloat rot = 0.0f;
// rot += 0.001f;
// Model = glm::rotate( Model, rot, glm::vec3( 0.0f, 0.0f, 1.0f ) ); // where x, y, z is axis of rotation (e.g. 0 1 0)
glm::mat4 Ortho = glm::ortho( 0.0f, (GLfloat) g_ScreenWidth, (GLfloat) g_ScreenHeight, 0.0f, 0.0f, 1000.0f );
glm::mat4 MVP;
MVP = Projection * View * Model * Ortho;
GLuint hMVP;
hMVP = glGetUniformLocation( g_SolidProgram, "MVP" );
glUniformMatrix4fv( hMVP, 1, GL_FALSE, glm::value_ptr( MVP ) );
glEnableVertexAttribArray( hPosition );
// Prepare the triangle coordinate data
glVertexAttribPointer( hPosition, 3, GL_FLOAT, FALSE, 0, afRectVerts );
// Draw the rectangle using triangles
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, g_RectFromTriIndices );
glDisableVertexAttribArray( hPosition );
}
这是顶点着色器源代码:
attribute vec4 vPosition;
uniform mat4 MVP;
void main()
{
gl_Position = MVP * vPosition;
}
更新:我发现下面的矩阵乘法给我更好的结果。我不知道这是 "correct" 还是不是:
MVP = Ortho * Model * View * Projection;
那个 MVP 对我来说真的很奇怪,你不应该需要 4 个东西来获得你的 MVP..你的投影矩阵应该只是正交矩阵,所以在这种情况下
MVP = Projection * View * Ortho;
但我也可以看到您的投影矩阵已经从透视角度进行了评论,所以我认为它现在做的不多。
听起来既然你想让模型坐标在移动时保持不变,你想移动你的相机吗?所以(从它的外观来看,你的顶点使用每像素 1 个单位的坐标范围)对你的视图进行 0.5f 的平移会移动你的投影 space 的一半。相反,您想要 Camera
class 之类的东西,您可以通过使用相机的 X
和 Y
位置获得 View
。
然后您可以使用相机位置获取您的视图矩阵,它可以共享您正在使用的世界单位系统,即每像素 1 个单位。
glm::mat4 view;
view = glm::lookAt(glm::vec3(camX, camY, 0.0), glm::vec3(0.0, 0.0, 0.0),glm::vec3(0.0, 1.0, 0.0));
我从一个非常好的相机 3d 教程中直接撕下了这条线(减去 camY 的 camZ)here 但完全相同的概念可以应用于正交相机
我知道这会增加一些开销,但是拥有一个可以通过这种方式控制的 cmaera class 比手动使用 glm::translate,rotate&scale 来控制视口更好(并且它可以确保您正在使用相机和模型坐标点之间更明显的坐标系。