一步步学OpenGL《复合变换》.doc_第1页
一步步学OpenGL《复合变换》.doc_第2页
一步步学OpenGL《复合变换》.doc_第3页
一步步学OpenGL《复合变换》.doc_第4页
一步步学OpenGL《复合变换》.doc_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

一步步学OpenGL复合变换背景在前面的几个教程中我们建立了几种基本图形变换是我们能灵活的将物体移动到3d世界的任意地方。我们还有很多要学(相机控制和透视投影等等),但你可能也已经想到,复合的图形变换也是必的。多数情况下,你会想缩放物体来和3d世界相适应,旋转物体到合适的方向,移动物体到某个地方等等。到现在我们已经实践了每一次的单一图形变换。为了实现上面一系列的变换,我们需要对顶点位置左乘第一个变换矩阵,然后得到的结果再左乘下一个变换矩阵等等,将所有变换矩阵都左乘顶点位置之后实现多个变换。一种笨办法就是在shader中应用每一个变换矩阵实现所有的变换,但这样很低效,因为对于所有顶点这些矩阵都是一样的,只有顶点的位置发生变化,这样要不断重复对每个顶点位置进行这一系列的矩阵相乘操作。幸运的是线性代数中有一些规则可以说让我们的生活更加简易,他告我们对于给定的一组矩阵M0Mn和一个向量V有下面的等式换算:Mn * Mn-1 * . * M0 * V = (Mn* Mn-1 * . * M0) * V所以如果你令:N = Mn * Mn-1 * . * M0那么:Mn * Mn-1 * . * M0 * V = (Mn * Mn-1 * . * M0) * V = N * V这意味着我们可以一次性计算N,然后把它作为一致变量传给shader和每一个顶点位置相乘完成所有的变换,这个只需要GPU对每个顶点进行一次矩阵/向量相乘操作。当计算N的时候怎样安排每个变换矩阵的先后顺序呢?你首先要记住向量最开始先是被最右边的矩阵左乘的(上面的例子就是M0)。然后向量被从右边到左边所有的变换矩阵所变换。在3d图形中你通常希望先缩放物体,然后旋转它,然后平移,之后再进行camera转换最后投影到2d屏幕。让我们先看先旋转后平移会怎样:可以看出,如果先平移物体的话会很难来设置物体的最终位置,因为当你将物体远离坐标原点后,再旋转物体会同时造成物体的平移效果(是绕原点旋转,而不是绕自身旋转了),这是我们希望能避免的。通过先旋转后移动可以避免这两个操作的相互依赖性,这也是尽量围绕原点对称建模的原因,那样当你缩放或者旋转物体不会产生副作用,缩放和旋转后物体依然保持和之前一样对称。源代码详解(1) #define ToRadian(x) (x) * M_PI / 180.0f)#define ToDegree(x) (x) * 180.0f / M_PI)在这个教程中我们开始要使用具体的角度值了。标准C语言库中三角函数使用弧度值作为参数。上面的宏定义可以实现角度和弧度之间的转换。(2)inline Matrix4f operator*(const Matrix4f& Right) const Matrix4f Ret; for (unsigned int i = 0 ; i 4 ; i+) for (unsigned int j = 0 ; j 4 ; j+) Ret.mij = mi0 * Right.m0j + mi1 * Right.m1j + mi2 * Right.m2j + mi3 * Right.m3j; return Ret;这里是定义了矩阵相乘的操作符。可以看到结果矩阵的值依次是左边矩阵每一行和右边矩阵对应每一列的点乘。这个矩阵相乘的操作对实现管线类十分重要。(3)class Pipeline public: Pipeline() . void Scale(float ScaleX, float ScaleY, float ScaleZ) . void WorldPos(float x, float y, float z) . void Rotate(float RotateX, float RotateY, float RotateZ) . const Matrix4f* GetTrans(); private: Vector3f m_scale; Vector3f m_worldPos; Vector3f m_rotateInfo; Matrix4f m_transformation;管线类抽象出了一个物体的所有变换的数据信息。现在有3个私有vector成员变量分别来存储物体在世界空间中的缩放比例,位置和每个像素的旋转角度。另外有接口函数来设置他们的值,以及可以获取表示所有变换最终的复合变换矩阵。(4)const Matrix4f* Pipeline:GetTrans() Matrix4f ScaleTrans, RotateTrans, TranslationTrans; InitScaleTransform(ScaleTrans); InitRotateTransform(RotateTrans); InitTranslationTransform(TranslationTrans); m_transformation = TranslationTrans * RotateTrans * ScaleTrans; return &m_transformation;这个函数初始化了那三个独立的变换矩阵并把它们一个一个的相乘然后返回最终的积。注意相乘的顺序是和上面描述的一样固定死的。如果你想更灵活一点你可以设置一个定义变换顺序的位掩码。还要注意它总是将最终的复合变换矩阵作为一个陈成员变量。你可以通过检查标记来做优化,当上一次的变换函数没有任何变化时可以返回上一次存储的变换矩阵,避免重复计算。这个函数按照之前教程的内容讲的使用私有方法来产生不同的变换。在下一个教程中这个类还将被扩展,来进行相机控制和透视变换。(5)Pipeline p;p.Scale(sinf(Scale * 0.1f), sinf(Scale * 0.1f), sinf(Scale * 0.1f);p.WorldPos(sinf(Scale), 0.0f, 0.0f);p.Rotate(sinf(Scale) * 90.0f, sinf(Scale) * 90.0f, sinf(Scale) * 90.0f);glUniformMatrix4fv(gWorldLocation, 1, GL_TRUE, (const GLfloat*)p.GetTrans();上面的语句是渲染函数中做的变化。我们实例化一个pipeline管线类对象,初始化配置好之后传递给shader。通过调整参数来看最终图像的效果。示例Demo用到了matrix4x4头文件中的扩展工具函数;#include #include #include #include #include #include ogldev_util.h#include ogldev_pipeline.hGLuint VBO;GLuint IBO;GLuint gWorldLocation;const char* pVSFileName = shader.vs;const char* pFSFileName = shader.fs;static void RenderSceneCB() glClear(GL_COLOR_BUFFER_BIT); static float Scale = 0.0f; Scale += 0.001f; / 实例化一个pipeline管线类对象,初始化配置好之后传递给shader Pipeline p; p.Scale(sinf(Scale * 0.1f), sinf(Scale * 0.1f), sinf(Scale * 0.1f); p.WorldPos(sinf(Scale), 0.0f, 0.0f); p.Rotate(sinf(Scale) * 90.0f, sinf(Scale) * 90.0f, sinf(Scale) * 90.0f); glUniformMatrix4fv(gWorldLocation, 1, GL_TRUE, (const GLfloat*)p.GetWorldTrans(); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, VBO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_INT, 0); glDisableVertexAttribArray(0); glutSwapBuffers();static void InitializeGlutCallbacks() glutDisplayFunc(RenderSceneCB); glutIdleFunc(RenderSceneCB);static void CreateVertexBuffer() Vector3f Vertices4; Vertices0 = Vector3f(-1.0f, -1.0f, 0.0f); Vertices1 = Vector3f(0.0f, -1.0f, 1.0f); Vertices2 = Vector3f(1.0f, -1.0f, 0.0f); Vertices3 = Vector3f(0.0f, 1.0f, 0.0f); glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);static void CreateIndexBuffer() unsigned int Indices = 0, 3, 1, 1, 3, 2, 2, 3, 0, 0, 1, 2 ; glGenBuffers(1, &IBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);static void AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType) GLuint ShaderObj = glCreateShader(ShaderType); if (ShaderObj = 0) fprintf(stderr, Error creating shader type %dn, ShaderType); exit(1); const GLchar* p1; p0 = pShaderText; GLint Lengths1; Lengths0= strlen(pShaderText); glShaderSource(ShaderObj, 1, p, Lengths); glCompileShader(ShaderObj); GLint success; glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success); if (!success) GLchar InfoLog1024; glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog); fprintf(stderr, Error compiling shader type %d: %sn, ShaderType, InfoLog); exit(1); glAttachShader(ShaderProgram, ShaderObj);static void CompileShaders() GLuint ShaderProgram = glCreateProgram(); if (ShaderProgram = 0) fprintf(stderr, Error creating shader programn); exit(1); string vs, fs; if (!ReadFile(pVSFileName, vs) exit(1); ; if (!ReadFile(pFSFileName, fs) exit(1); ; AddShader(ShaderProgram, vs.c_str(), GL_VERTEX_SHADER); AddShader(ShaderProgram, fs.c_str(), GL_FRAGMENT_SHADER); GLint Success = 0; GLchar ErrorLog1024 = 0 ; glLinkProgram(ShaderProgram); glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success); if (Success = 0) glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog); fprintf(stderr, Error linking ader program: %sn, ErrorLog); exit(1); glValidateProgram(ShaderProgram); glGetProgramiv(ShaderProgram, GL_VALIDATE_STATUS, &Success); if (!Success) glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog); fprintf(stderr, Invalid shader program: %sn, ErrorLog); exit(1); glUseProgram(ShaderProgram); gWorldLocation = glGetUniformLocation(ShaderProgram, gWorld); assert(gWorldLocation != 0xFFFFFFFF);int main(int argc, char* argv) glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA); glutInitWindowSize(1024, 768); glutInitWindowPosition(100, 100); glutCreateWindow(Tutorial 1

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论