OpenGL藍寶書第五章代碼勘誤以及慣性座標系去解釋模型變換,opengl藍寶書
如果你也發現按照教程程式碼完成貼圖時,你會底面的座標和平常頂點座標正負相反,比如-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>#endifGLMatrixStack 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 statebool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode){GLbyte *pBits;int nWidth, nHeight, nComponents;GLenum eFormat;// Read the texture bitspBits = 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;}
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。