如果你也发现按照教程代码完成贴图时,你会底面的坐标和平常顶点坐标正负相反,比如-1.0f, -1.0f, -1.0f这个顶点对应的却是世界坐标中1.0f,-1.0f,1.0f
问题究竟出现在哪里?
原来是:objectFrame.GetCameraMatrix(mObjectFrame); //原书中的代码为GetMatrix,获取了objectFrame的朝向,导致顶点和纹理的对象关系出现了相反内容
objectFrame中的朝向和OpenGL的默认朝向相反,getMatrix的操作会导致modelViewMatrix在无形中执行了一次180°旋转。鉴于此,我们应该只需要获得其camera矩阵即可。这个camera矩阵记录了当前模型的旋转、缩放和位移。modelViewMatrix乘上这个矩阵的结果就是世界原点到模型各顶点的作用矩阵。
这里引出一个我差点忘记的概念:惯性坐标。
世界坐标系的原点通过变换矩阵,可定位了模型的位移、旋转(包含朝向和定义惯性正方向)、缩放状态(这个其实对世界顶点变换影响不大,只是模型对于自身的惯性相对点影响比较大)。实际渲染绘制流程是:世界原点,移动画刷(这个概念很重要),旋转画刷,根据缩放绘制模型各顶点。模型各顶点的位置是相对于画刷的,画刷其实在更多情况下命名为模型的惯性坐标系。从世界坐标系到画刷(模型惯性坐标系)则是模型变换矩阵,模型顶点的绘制则由模型编辑器或绘制算法定义。摄像机则影响了最终可视区域。有些情况下,模型惯性坐标系的原点是摄像机的当前所在位置。
如果代码中使用了
//modelViewMatrix.Translate(0.0f, -1.0f, -7.0f);
这样类似的操作,而不是从camera中获取相对位移矩阵,那么这个模型的惯性坐标系是相对于世界坐标空间的原点。
由此,纹理贴图的st对应关系环绕就清楚的和2D像素点操作明显区别开来。
OpenGL的st从左下角为原点,而内存中的像素操作是从左上角为原点。
#include <GLTools.h> #include <GLMatrixStack.h> #include <GLGeometryTransform.h> #include <GLFrustum.h> #include <GLFrame.h> #include <GLShaderManager.h> #include <iostream> #include <math.h> #ifdef __APPLE__ #include <glut/glut.h> #else #define FREEGLUT_STATIC #include <GL/glut.h> #endif GLMatrixStack mvpMatrix; GLMatrixStack projectionMatrix; GLMatrixStack modelViewMatrix; GLFrustum viewFrustum; GLGeometryTransform transformPipeLine; GLFrame cameraFrame; GLFrame objectFrame; GLBatch pyramidBatch; GLuint textureID; GLShaderManager shaderManager; void ChangeSize(int w, int h) { if (h <= 0) { h = 1; } glViewport(0, 0, w, h); viewFrustum.SetPerspective(35, float(w) / float(h), 1.0f, 1000.0f); projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); transformPipeLine.SetMatrixStacks(modelViewMatrix, projectionMatrix); } // Load a TGA as a 2D Texture. Completely initialize the state bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode) { GLbyte *pBits; int nWidth, nHeight, nComponents; GLenum eFormat; // Read the texture bits pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat); if (pBits == NULL) return false; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBits); free(pBits); if (minFilter == GL_LINEAR_MIPMAP_LINEAR || minFilter == GL_LINEAR_MIPMAP_NEAREST || minFilter == GL_NEAREST_MIPMAP_LINEAR || minFilter == GL_NEAREST_MIPMAP_NEAREST) glGenerateMipmap(GL_TEXTURE_2D); return true; } void MakePyramid(GLBatch & pyramidBatch) { //每三个点画一个三角形 pyramidBatch.Begin(GL_TRIANGLES, 18, 1); //原点在金字塔的几何中心(总之就是非重点,比中心高的的位置,高度的1/2) //底部,初始法线是向下,纹理映射的顶点需要查看原始纹理对照一下?? //todo //逆着法线看的话,下面三个点的环绕是逆时针的 pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f); pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f); pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f); pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f); pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f); pyramidBatch.Vertex3f(1.0f, -1.0f, -1.0f); pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f); pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f); pyramidBatch.Vertex3f(1.0f, -1.0f, 1.0f); //逆着法线看的话,下面三个点的环绕是逆时针的 pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f); pyramidBatch.MultiTexCoord2f(0, 0.0f, 1.0f); pyramidBatch.Vertex3f(-1.0f, -1.0f, 1.0f); pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f); pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f); pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f); pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f); pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f); pyramidBatch.Vertex3f(1.0f, -1.0f, 1.0f); //原先作者代码中的front和back的方向不是相对于观察者所得到的视野 //“前”这个面竟然是金字塔的背对着我们的面,即第一视角看不到这个面 //感觉这坐标竟然是 M3DVector3f vApex = { 0.0f, 1.0f, 0.0f }; M3DVector3f vFrontLeft = { -1.0f, -1.0f, 1.0f }; M3DVector3f vFrontRight = { 1.0f, -1.0f, 1.0f }; M3DVector3f vBackLeft = { -1.0f, -1.0f, -1.0f }; M3DVector3f vBackRight = { 1.0f, -1.0f, -1.0f }; M3DVector3f n; //求法线,前 m3dFindNormal(n, vApex, vFrontLeft, vFrontRight); pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f); pyramidBatch.Vertex3fv(vApex); pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f); pyramidBatch.Vertex3fv(vFrontLeft); pyramidBatch.Normal3fv(n); pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f); pyramidBatch.Vertex3fv(vFrontRight); ////求法线,左 //m3dFindNormal(n, vApex, vBackLeft, vFrontLeft); //pyramidBatch.Normal3fv(n); //pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f); //pyramidBatch.Vertex3fv(vApex); //pyramidBatch.Normal3fv(n); //pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f); //pyramidBatch.Vertex3fv(vBackLeft); //pyramidBatch.Normal3fv(n); //pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f); //pyramidBatch.Vertex3fv(vFrontLeft); ////求法线,右 //m3dFindNormal(n, vApex, vFrontRight, vBackRight); //pyramidBatch.Normal3fv(n); //pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f); //pyramidBatch.Vertex3fv(vApex); //pyramidBatch.Normal3fv(n); //pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f); //pyramidBatch.Vertex3fv(vFrontRight); //pyramidBatch.Normal3fv(n); //pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f); //pyramidBatch.Vertex3fv(vBackRight); ////求法线,后 //m3dFindNormal(n, vApex, vBackRight, vBackLeft); //pyramidBatch.Normal3fv(n); //pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f); //pyramidBatch.Vertex3fv(vApex); //pyramidBatch.Normal3fv(n); //pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f); //pyramidBatch.Vertex3fv(vBackRight); //pyramidBatch.Normal3fv(n); //pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f); //pyramidBatch.Vertex3fv(vBackLeft); pyramidBatch.End(); } void SetupRC(void) { glClearColor(0.7f, 0.7f, 0.7f, 1.0f); shaderManager.InitializeStockShaders(); glEnable(GL_DEPTH_TEST); glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); LoadTGATexture("stone.tga", GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE); MakePyramid(pyramidBatch); cameraFrame.MoveForward(-7.0f);//??什么用意?? } void RenderScene(void) { static GLfloat vLightPos[] = { 1.0f, 1.0f, 0.f }; static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); modelViewMatrix.PushMatrix(); //{ //处理画笔位置相关,即模型相对于摄像机的位置 M3DMatrix44f mCamera; cameraFrame.GetCameraMatrix(mCamera); modelViewMatrix.MultMatrix(mCamera); //modelViewMatrix.Translate(0.0f, -1.0f, -7.0f); //处理模型自身的旋转或缩放 M3DMatrix44f mObjectFrame; objectFrame.GetCameraMatrix(mObjectFrame); //原书中的代码为GetMatrix,获取了objectFrame的朝向,导致顶点和纹理的对象关系出现了相反内容 modelViewMatrix.MultMatrix(mObjectFrame); glBindTexture(GL_TEXTURE_2D, textureID); shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF, transformPipeLine.GetModelViewMatrix(), transformPipeLine.GetProjectionMatrix(), vLightPos, vWhite, 0); pyramidBatch.Draw(); //} modelViewMatrix.PopMatrix(); glutSwapBuffers(); } void ShutdownRC(void) { glDeleteTextures(1, &textureID); } void SpecialKeys(int key, int x, int y) { if (key == GLUT_KEY_UP) { objectFrame.RotateWorld(m3dDegToRad(5.0f),1.0f,0.0f,0.0f);//模型和摄像机的操作是相反的,模型向上旋转5.0f } if (key == GLUT_KEY_DOWN) { objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f); } if (key == GLUT_KEY_LEFT) { objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f); } if (key == GLUT_KEY_RIGHT) { objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f); } glutPostRedisplay(); } int main(int argc, char * argv[]) { gltSetWorkingDirectory(argv[0]); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL); glutInitWindowSize(800, 600); glutCreateWindow("Pyramid"); glutReshapeFunc(ChangeSize); glutSpecialFunc(SpecialKeys); glutDisplayFunc(RenderScene); GLenum err = glewInit(); if (GLEW_OK != err) { fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err)); return 1; } SetupRC(); glutMainLoop(); ShutdownRC(); return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
OpenGL蓝宝书第五章代码勘误以及惯性坐标系去解释模型变换
原文地址:http://blog.csdn.net/jingzhewangzi/article/details/46846437