我们为上述的每一个步骤都创建了一个变换矩阵:模型矩阵、观察矩阵和投影矩阵。一个顶点坐标将会根据以下过程被变换到裁剪坐标:
Vclip=Mprojection⋅Mview⋅Mmodel⋅VlocalVclip=Mprojection⋅Mview⋅Mmodel⋅Vlocal
注意矩阵运算的顺序是相反的(记住我们需要从右往左阅读矩阵的乘法)。最后的顶点应该被赋值到顶点着色器中的gl_Position,OpenGL将会自动进行透视除法和裁剪。
顶点着色器的输出要求所有的顶点都在裁剪空间内,这正是我们刚才使用变换矩阵所做的。OpenGL然后对裁剪坐标执行透视除法从而将它们变换到标准化设备坐标。
OpenGL会使用glViewPort内部的参数来将标准化设备坐标映射到屏幕坐标,每个坐标都关联了一个屏幕上的点(在我们的例子中是一个800x600的屏幕)。这个过程称为视口变换。
1 //创建一个正射投影矩阵 2 //前两个参数指定了*截头体的左右坐标,第三四个三叔指定了*截头体的底部和顶部,通过这四个参数我们定义了**面和远*面的大小 3 //然后第五个和第六个参数则定义了**面和远*面的距离,这个投影矩阵会将这些处于这些x, y, z值范围内的坐标变换为标准化设备坐标 4 glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);
1 //创建一个透视投影矩阵 2 //第一个参数定义了fov的值,它表示的是视野(Fiele of View), 并且设置了观察空间的大小,如果想要一个真实的观察效果,它的值通常设置为 3 //45.0f, 但想要一个末日风格的结果你可以将其设置一个更大的值。 4 //第二个参数设置了宽高比,有视口的宽除以高所得, 5 //第三四个参数设置了*头截体的*和远*面,我们通常设置*距离为0.1f, 而远距离设为100.0f, 所有在**面和远*面内切处于*截头体内的顶点都会被渲染 6 glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)width / (float)height, 0.1f, 100.0f);
1 //创建一个模型矩阵 2 glm::mat4 model; 3 model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f)); //绕x轴旋转-55度 4 5 //创建一个观察矩阵 6 glm::mat4 view; 7 view = glm::translate(view, glm::vec3(0.0f, 0.0f,-3.0f)); //注意,我们将矩阵向们要进行移动场景的反方向移动, vec3为转轴 8 9 GLfloat screenWidth = 800; 10 GLfloat screenHeight = 600; 11 //创建一个投影矩阵(此处是透视投影) 12 glm::mat4 projection; 13 14 projection = glm::perspective(glm::radians(45.0f), screenWidth / screenHeight, 0.1f, 100.0f); //宽高比应与窗口宽高比例一致
在顶点着色器中分别为三个变换矩阵声明一个uniform,然后将它乘以顶点坐标,注意矩阵运算的顺序是相反的(记住我们需要从右往左阅读矩阵的乘法)Vclip=Mprojection⋅Mview⋅Mmodel⋅VlocalVclip=Mprojection⋅Mview⋅Mmodel⋅Vlocal
1 int modelLoc = glGetUniformLocation(ourShader.ID, "model"); 2 glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); 3 4 glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "view"), 1, GL_FALSE, glm::value_ptr(view)); 5 glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
创建10个立方体
1 float vertices[] = { 2 -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 3 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 4 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 5 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 6 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 7 -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 8 9 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 10 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 11 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 12 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 13 -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 14 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 15 16 -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 17 -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 18 -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 19 -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 20 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 21 -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 22 23 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 24 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 25 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 26 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 27 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 28 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 29 30 -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 31 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 32 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 33 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 34 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 35 -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 36 37 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 38 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 39 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 40 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 41 -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 42 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f 43 }; 44 45 //在一个glm::vec3数组中定义10个立方体的位置 46 glm::vec3 cubePosition[] = { 47 glm::vec3(0.0f, 0.0f, 0.0f), 48 glm::vec3(2.0f, 5.0f, -15.0f), 49 glm::vec3(-1.5f, -2.2f, -2.5f), 50 glm::vec3(-3.8f, -2.0f, -12.3f), 51 glm::vec3(2.4f, -0.4f, -3.5f), 52 glm::vec3(-1.7f, 3.0f, -7.5f), 53 glm::vec3(1.3f, -2.0f, -2.5f), 54 glm::vec3(1.5f, 2.0f, -2.5f), 55 glm::vec3(1.5f, 0.2f, -1.5f), 56 glm::vec3(-1.3f, 1.0f, -1.5f) 57 };
1 glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "view"), 1, GL_FALSE, glm::value_ptr(view)); 2 glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); 3 glBindVertexArray(VAO); 4 for (unsigned int i = 0; i < 10; i++) 5 { 6 glm::mat4 model; 7 model = glm::translate(model, cubePosition[i]); 8 float angle = 20.0f * i; 9 if (i % 4 == 0) 10 angle = glfwGetTime() * (25.0f + i * 10) ; 11 //model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); 12 model = glm::rotate(model, glm::radians(angle), glm::vec3((0.1 * i), 0.3f, 0.05 * i)); //转动立方体,vec3为绕着转动的轴 13 glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "model"), 1, GL_FALSE, glm::value_ptr(model)); 14 glDrawArrays(GL_TRIANGLES, 0, 36);