zoukankan      html  css  js  c++  java
  • 3D Computer Grapihcs Using OpenGL

    本节我们将绘制一个3维物体,立方体。

    如果要渲染3D物体,我们需要了解MVP(Model View Projection),它表示三个转换矩阵。实际上这个名字不够明确,更加确切的释义如下:

    • Model - Model to World  模型空间到世界空间
    • View - World to View      世界空间到视图空间
    • Projection - View to Projection   视图空间到投影空间

    要实现这三个转换矩阵,我们需要借助glm数学库提供的一些方便的结构体和函数。

    重构

    我们先对程序结构进行修改,对工程右键>Add > New Filter, 创建一个Primitives 文件夹,在其中创建两个文件,一个Vertex.h,一个ShapeData.h

    Vertex.h中定义了一个Vertex结构体,它包含两个glm::vec3成员,分别表示位置和颜色。

    1 #pragma once
    2 #include <glmglm.hpp>
    3 
    4 struct Vertex
    5 {
    6     glm::vec3 position;
    7     glm::vec3 color;
    8 };

    ShapeData.h中定义了一个ShapeData结构体,包含四个成员变量,分别是

    • Vertex* 类型:顶点数组指针
    • Gluint类型:顶点数量
    • GLushort* 类型:索引数组指针
    • GLuint 类型:索引数组长度

    另外还提供了构造函数,清理函数

     1 #pragma once
     2 #include <GLglew.h>
     3 #include "Vertex.h"
     4 
     5 struct ShapeData
     6 {
     7     ShapeData() :
     8         vertices(0), numVertices(0), indices(0), numIndices(0) {}
     9 
    10     Vertex* vertices;
    11     GLuint numVertices;
    12     GLushort* indices;
    13     GLuint numIndices;
    14 
    15     GLsizeiptr vertexBufferSize() const
    16     {
    17         return numVertices * sizeof(Vertex);
    18     }
    19     GLsizeiptr indexBufferSize() const
    20     {
    21         return numIndices * sizeof(GLushort);
    22     }
    23 
    24     void cleanUp()
    25     {
    26         delete[] vertices;
    27         delete[] indices;
    28         numVertices = numIndices = 0;
    29     }
    30 };

    此外还加入了一个新的类,ShapeGenerator

    ShapeGenerator.h

    1 #pragma once
    2 #include <ShapeData.h>
    3 
    4 class ShapeGenerator
    5 {
    6 public:
    7     static ShapeData makeCube();
    8 };

    ShapeGenerator.cpp

     1 #include "ShapeGenerator.h"
     2 #include "Vertex.h"
     3 
     4 #define NUM_ARRAY_ELEMENTS(a) sizeof(a) / sizeof(*a)
     5 
     6 ShapeData ShapeGenerator::makeCube()
     7 {
     8     ShapeData ret;
     9     Vertex stackVerts[]=
    10     {
    11         glm::vec3(-1.0f, +1.0f, +1.0f), //0
    12         glm::vec3(+1.0f, 0.0f, 0.0f),   //Color
    13         glm::vec3(+1.0f, +1.0f, +1.0f), //1
    14         glm::vec3(0.0f, +1.0f, 0.0f),    //Color
    15         glm::vec3(+1.0f, +1.0f, -1.0f), //2
    16         glm::vec3(0.0f, 0.0f, +1.0f), //Color
    17         glm::vec3(-1.0f, +1.0f, -1.0f), //3
    18         glm::vec3(+1.0f, +1.0f, +1.0f), //Color
    19 
    20         glm::vec3(-1.0f, +1.0f, -1.0f), //4
    21         glm::vec3(+1.0f, 0.0f, +1.0f),   //Color
    22         glm::vec3(+1.0f, +1.0f, -1.0f), //5
    23         glm::vec3(0.0f, 0.5f, 0.2f),    //Color
    24         glm::vec3(+1.0f, -1.0f, -1.0f), //6
    25         glm::vec3(0.8f, 0.6f, 0.4f), //Color
    26         glm::vec3(-1.0f, -1.0f, -1.0f), //7
    27         glm::vec3(0.3f, +1.0f, +0.5f), //Color
    28 
    29         glm::vec3(+1.0f, +1.0f, -1.0f), //8
    30         glm::vec3(0.2f, 0.5f, 0.2f),  //Color
    31         glm::vec3(+1.0f, +1.0f, +1.0f), //9
    32         glm::vec3(0.9f, 0.3f, 0.7f),    //Color
    33         glm::vec3(+1.0f, -1.0f, +1.0f), //10
    34         glm::vec3(0.3f, 0.7f, 0.5f),    //Color
    35         glm::vec3(+1.0f, -1.0f, -1.0f), //11
    36         glm::vec3(0.5f, 0.7f, 0.5f),  //Color
    37 
    38         glm::vec3(-1.0f, +1.0f, +1.0f), //12
    39         glm::vec3(0.7f, 0.8f, 0.2f),   //Color
    40         glm::vec3(-1.0f, +1.0f, -1.0f), //13
    41         glm::vec3(0.5f, 0.7f, 0.3f),    //Color
    42         glm::vec3(-1.0f, -1.0f, -1.0f), //14
    43         glm::vec3(0.8f, 0.6f, 0.4f), //Color
    44         glm::vec3(-1.0f, -1.0f, +1.0f), //15
    45         glm::vec3(0.3f, +1.0f, +0.5f), //Color
    46 
    47         glm::vec3(+1.0f, +1.0f, +1.0f), //16
    48         glm::vec3(0.7f, 0.8f, 0.2f),   //Color
    49         glm::vec3(-1.0f, +1.0f, +1.0f), //17
    50         glm::vec3(0.5f, 0.7f, 0.3f),    //Color
    51         glm::vec3(-1.0f, -1.0f, +1.0f), //18
    52         glm::vec3(0.8f, 0.6f, 0.4f), //Color
    53         glm::vec3(+1.0f, -1.0f, +1.0f), //19
    54         glm::vec3(0.3f, +1.0f, +0.5f), //Color
    55 
    56         glm::vec3(+1.0f, -1.0f, -1.0f), //20
    57         glm::vec3(0.7f, 0.8f, 0.2f),   //Color
    58         glm::vec3(-1.0f, -1.0f, -1.0f), //21
    59         glm::vec3(0.5f, 0.7f, 0.3f),    //Color
    60         glm::vec3(-1.0f, -1.0f, +1.0f), //22
    61         glm::vec3(0.8f, 0.6f, 0.4f), //Color
    62         glm::vec3(+1.0f, -1.0f, +1.0f), //23
    63         glm::vec3(0.3f, +1.0f, +0.5f), //Color
    64     };
    65 
    66     ret.numVertices = NUM_ARRAY_ELEMENTS(stackVerts);
    67     ret.vertices = new Vertex[ret.numVertices];
    68     memcpy(ret.vertices, stackVerts, sizeof(stackVerts));
    69 
    70     unsigned short stackIndices[] = 
    71     {
    72         0,1,2,0,2,3,
    73         4,5,6,4,6,7,
    74         8,9,10,8,10,11,
    75         12,13,14,12,14,15,
    76         16,17,18,16,18,19,
    77         20,22,21,20,23,22,
    78     };
    79 
    80     ret.numIndices = NUM_ARRAY_ELEMENTS(stackIndices);
    81     ret.indices = new GLushort[ret.numIndices];
    82     memcpy(ret.indices, stackIndices, sizeof(stackIndices));
    83     return ret;
    84 }

    主要作用是提供了一个静态方法 makeCube,返回一个立方体的数据。

    修改MyGlWindow类

      1 #include <glglew.h>
      2 #include "MyGlWindow.h"
      3 #include <iostream>
      4 #include <fstream>
      5 #include <glmgtcmatrix_transform.hpp>
      6 #include <ShapeGenerator.h>
      7 
      8 
      9 
     10 GLuint programID;
     11 GLuint numIndices;
     12 
     13 void MyGlWindow::sendDataToOpenGL()
     14 {
     15     
     16     ShapeData shape = ShapeGenerator::makeCube();
     17 
     18     GLuint vertexBufferID;
     19     glGenBuffers(1, &vertexBufferID);
     20     glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
     21     glBufferData(GL_ARRAY_BUFFER, shape.vertexBufferSize(), shape.vertices, GL_STATIC_DRAW);
     22 
     23     GLuint indexBufferID;
     24     glGenBuffers(1, &indexBufferID);
     25     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
     26     glBufferData(GL_ELEMENT_ARRAY_BUFFER, shape.indexBufferSize(), shape.indices, GL_STATIC_DRAW);
     27 
     28     glEnableVertexAttribArray(0);
     29     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0);
     30 
     31     glEnableVertexAttribArray(1);
     32     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (char*)(sizeof(GLfloat) * 3));
     33 
     34     numIndices = shape.numIndices;
     35     shape.cleanUp();
     36 
     37 }
     38 
     39 void MyGlWindow::installShaders()
     40 {
     41     GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
     42     GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
     43 
     44     std::string tmp = ReadShaderCode("VertexShaderCode2.glsl");
     45     const char* vertexShaderCode = tmp.c_str();
     46     glShaderSource(vertexShaderID, 1, &vertexShaderCode, 0);
     47 
     48     tmp = ReadShaderCode("FragmentShaderCode2.glsl");
     49     const char* fragmentShaderCode = tmp.c_str();    
     50     glShaderSource(fragmentShaderID, 1, &fragmentShaderCode, 0);
     51 
     52     glCompileShader(vertexShaderID);
     53     glCompileShader(fragmentShaderID);
     54 
     55     programID = glCreateProgram();
     56     glAttachShader(programID, vertexShaderID);
     57     glAttachShader(programID, fragmentShaderID);
     58 
     59     glLinkProgram(programID);
     60 
     61     glUseProgram(programID);
     62 }
     63 
     64 void MyGlWindow::initializeGL()
     65 {
     66     glewInit();
     67     glEnable(GL_DEPTH_TEST);
     68     sendDataToOpenGL();
     69     installShaders();
     70 }
     71 
     72 void MyGlWindow::paintGL()
     73 {
     74     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
     75     glViewport(0, 0, width(), height());
     76 
     77     //更新:最新版本的glm中,glm::mat4()生成的是不是单位矩阵,而是零矩阵,这里要使用glm::mat4(1.0f)才可以
     78     glm::mat4 modelTransformMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f,-3.0f));
     79     glm::mat4 projectionMatrix = glm::perspective(30.0f, ((float)width()) / height(), 0.1f, 10.0f);
     80 
     81     GLint modelTransformUniformLocation = glGetUniformLocation(programID, "modelMatrix");
     82     GLint projectionMatrixUniformLocation = glGetUniformLocation(programID, "projectionMatrix");
     83 
     84     glUniformMatrix4fv(modelTransformUniformLocation, 1, GL_FALSE, &modelTransformMatrix[0][0]);
     85     glUniformMatrix4fv(projectionMatrixUniformLocation, 1, GL_FALSE, &projectionMatrix[0][0]);
     86 
     87     glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0);
     88 
     89 }
     90 
     91 
     92 std::string MyGlWindow::ReadShaderCode(const char* fileName)
     93 {
     94     std::ifstream myInput(fileName);
     95     if (!myInput.good())
     96     {
     97         std::cout << "File failed to load..." << fileName;
     98         exit(1);
     99     }
    100     return std::string(
    101         std::istreambuf_iterator<char>(myInput),
    102         std::istreambuf_iterator<char>());
    103 }

    Vertex Shader :

     1 #version 430                           
     2                                        
     3 in layout(location=0) vec3 position;   
     4 in layout(location=1) vec3 vertexColor;                                       
     5                                       
     6 uniform mat4 modelMatrix;
     7 uniform mat4 projectionMatrix; 
     8 
     9 out vec3 passingColor;
    10                                        
    11 void main()                            
    12 {                                      
    13   vec4 v =  vec4(position,1.0);
    14   vec4 newPosition = modelMatrix * v;
    15   gl_Position = projectionMatrix * newPosition;
    16   passingColor= vertexColor;           
    17 }

    Fragment Shader:

     1 #version 430                                         
     2                                       
     3 in vec3 passingColor;                 
     4 out vec4 finalColor;                  
     5 
     6                          
     7 void main()                           
     8 {                                     
     9   finalColor = vec4(passingColor,1.0);
    10 }                            

    注意MyGlWindow的78-85行,是使用Uniform 变量的通用方法,使用的是Vertex Shader中第6-7行的两个uniform。

    使用Uniform变量的步骤总结:

    1. 使用glGetUniformLocation获取Uniform变量的ID,并储存在一个GLint 变量中
    2. 使用glUnifomxxxx()类的函数和刚才得到的ID给Uniform赋值。

    另外要注意85-86行,函数的最后一参数需要一个const GLfloat * 类型的变量,所以我们使用[0][0]获取矩阵的第一个元素,它是个GLfloat类型的,再对他使用取地址符&得到它的地址。

    编译运行以后得到一个平面(实际上是立方体的一个面):

    我们在最开始提到了3个矩阵,但是这里只用到了两个,实际上少了第二个矩阵,World to View矩阵,这也正是为什么我们现在无法移动观察视角的原因,我们的相机被假设在世界原点,朝向-z的方向看去,这是默认的设置。后面我们会学习world to view的转换矩阵。

  • 相关阅读:
    python-进阶-优雅的python写法
    springMVC3学习(十一)--文件上传CommonsMultipartFile
    springMVC3学习(十)--注解式控制器
    CSS3/jQuery自定义弹出窗口
    window.open()详解及浏览器兼容性问题
    空格&nbsp在不同浏览器中显示距离不一致问题解决方法
    jQuery拖动调整表格列宽度-resizableColumns
    jQuery表格排序组件-tablesorter
    springMVC3学习(九)--redirect和forward跳转
    springMVC3学习(八)--全局的异常处理
  • 原文地址:https://www.cnblogs.com/AnKen/p/8350165.html
Copyright © 2011-2022 走看看