上节说过矩阵是可以结合的,而且相乘是按照和应用顺序相反的顺序进行的.我们之前初始化translationMatrix和rotationMatrix的时候,第一个参数都是使用的一个初始矩阵 glm::matrix4(),实际上我们可以对代码稍作优化,让初始化过程精简一些. 对比一下优化之前和优化之后的代码: 之前: glm::mat4 projectionMatrix = glm::perspective(30.0f, ((float)width()) / height(), 0.1f, 10.0…
大部分OpenGL教程都会在一开始就讲解VAO,但是该教程的作者认为这是很不合理的,因为要理解它的作用需要建立在我们此前学过的知识基础上.因此直到教程已经进行了一大半,作者才引入VAO这个概念.在我看来这也是非常合理和自然的. 先预览一下最终的代码逻辑: 准备工作 为了讲解后面的内容,我们对代码进行了更改(算是回退吧,改回到以前不使用Instancing的版本): 去掉了sendDataToOpenGL()函数中关于实例化的部分代码 把VertexShader中的MVP矩阵改回Uniform 在…
我们使用15节学到的知识来绘制14节的立方体. 在第14节我们使用了两次glDrawElements实现了OpenGL实例化,发现这样仍然不太方便,如果需要绘制成千上万的立方体,就需要手写成千上万次的glDrawElements(). 而15节我们知道了glDrawElementsInstanced函数可以支持批量绘制. 我们需要绘制的多个立方体唯一不同的只是转换矩阵,为了达到这个目的,我们只需要定义一组不同的变换矩阵,采用glDrawElementsInstanced即可达到目的. 构建矩阵的…
如果我们需要绘制两个(或者多个)一样的立方体(或者物体),只是位置.缩放.旋转不一样,那么我们可以不需要多次将这个物体的顶点信息.颜色信息等发送到显卡,而是发送一次,绘制多次,仅仅是每次绘制之前应用不同的转换矩阵.这种方法叫做OpenGL Instancing.它的效率比每次都重新发送一次数据到显卡要高很多. 看具体代码: void MyGlWindow::paintGL() { glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glView…
为了证明我们上节渲染出来的是一个立方体而不是一个平面,我们决定将它旋转一定角度,这样我们就需要一个旋转矩阵(也属于ModelTransformMatrix的一部分) 上一节我们的ModelTransformMatrix中做了一个移动(translation)的操作,所以我们将它重命名为translationMatrix. 先看修改后的paintGL()函数: void MyGlWindow::paintGL() { glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_B…
本节我们将绘制一个3维物体,立方体. 如果要渲染3D物体,我们需要了解MVP(Model View Projection),它表示三个转换矩阵.实际上这个名字不够明确,更加确切的释义如下: Model - Model to World  模型空间到世界空间 View - World to View      世界空间到视图空间 Projection - View to Projection   视图空间到投影空间 要实现这三个转换矩阵,我们需要借助glm数学库提供的一些方便的结构体和函数. 重构…
启用Depth Test OpenGL是个3D绘图API,也就是说不只有xy坐标轴,还有第三个坐标轴z,z轴的方向是垂直于屏幕,指向屏幕内. 靠近人眼的方向是负方向,标准化设备坐标的最小值是-1, 最大正值是1. 在未启用深度测试的情况下,同一个像素如果被绘制两次,后绘制的像素会覆盖先绘制的像素. 如果启用了深度测试,情况则完全不同了.后绘制的像素会对深度做一次比较,如果后绘制的像素深度(z)小于之前的像素深度,则会覆盖,如果大于或者等于之前的像素深度,则不会覆盖. Depth需要在绘制之前启用…
从这里就接触到了可编程图形渲染管线. 下面介绍使用Vertex Shader (顶点着色器)和 Fragment Shader(像素着色器)的方法. 我们的目标是使用这两个着色器给三角形填充绿色. 添加了一个cpp文件存放Shader文件,MyShaderCode.cpp: 1 const char* vertexShaderCode = 2 " #version 430 \r\n" 3 " \r\n" 4 " in layout(location=0)…
本节绘制一个三角形,并讲解Buffer Object-缓冲对象 OpenGL的窗口坐标 屏幕中心为坐标原点,横向朝右为x正方向,纵向朝上为y正方向,最大值最小值分别为1,-1. Buffer Object 缓冲对象为内存中的一块空间,用来和OpenGL交互数据. 使用BufferObject的步骤: 创建Buffer的“名称”(或者理解为ID,地址), GLuint类型; 生成Buffer; 绑定Buffer到OpenGL的绑定点(Binding Point); 设置Buffer数据; 具体代码…
在11节我们说过,MVP矩阵中目前只应用了两个矩阵,World to View 矩阵被省略了,这就导致我们的画面没有办法转换视角. 本节我们将添加这一环节,让相机可以旋转. 为了实现这一目的,我们添加一个相机类, Camera类. Camera.h: #pragma once #include <glm\glm.hpp> class Camera { private: glm::vec3 position; glm::vec3 viewDirection; const glm::vec3 UP…