Glew的配置与使用
参考网址:https://learnopengl-cn.github.io/legacy/
编译和链接GLEW
- OpenGL定义的这些GL基元类型的内存布局是与平台无关的,使用GL基元类型可以保证你的程序在不同的平台上工作一致。
- GLEW是OpenGL Extension Wrangler Library的缩写,因为GLEW也是一个库,我们同样需要构建并将其链接进工程。
- Glew的下载地址为:http://glew.sourceforge.net/index.html
- 对于Glew的选择,如果不确定的话,选择32位的二进制版本。
- 使用GLEW的静态版本glew32s.lib(注意这里的“s”),将库文件添加到你的库目录,将include内容添加到你的include目录。接下来,在VS的链接器选项里加上glew32s.lib。
GLEW的初始化
- GLEW是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLEW。
- 我们在初始化GLEW之前设置glewExperimental变量的值为
GL_TRUE
,这样做能让GLEW在管理OpenGL的函数指针时更多地使用现代化的技术。
视口
- 我们必须告诉OpenGL渲染窗口的尺寸大小,这样OpenGL才只能知道怎样相对于窗口大小显示数据和坐标。
- 我们可以通过调用glViewport函数来设置窗口的维度。
- glViewport函数前两个参数控制窗口左下角的位置。第三个和第四个参数控制渲染窗口的宽度和高度(像素)。
- 实际上也可以将视口的维度设置为比GLFW的维度小,这样子之后所有的OpenGL渲染将会在一个更小的窗口中显示。
- OpenGL幕后使用glViewport中定义的位置和宽高进行2D坐标的转换,将OpenGL中的位置坐标转换为你的屏幕坐标。处理过的OpenGL坐标范围只为-1到1。
- 具体的应用示例:
输入
- 按键回调是众多回调函数中的一种。当我们设置了按键回调之后,GLFW会在用户有键盘交互时调用它。
- 按键回调函数接受一个GLFWwindow指针作为它的第一个参数;第二个整形参数用来表示按下的按键;
action
参数表示这个按键是被按下还是释放;最后一个整形参数表示是否有Ctrl、Shift、Alt、Super等按钮的操作。 - 具体的示例:
- 上述实例说明:在我们(新创建的)key_callback函数中,我们检测了键盘是否按下了Escape键。如果键的确按下了(不释放),我们使用glfwSetwindowShouldClose函数设定
WindowShouldClose
属性为true
从而关闭GLFW。main函数的while
循环下一次的检测将为失败,程序就关闭了。 - 最后就是通过GLFW注册我们的函数至合适的回调:
SOIL
- SOIL是简易OpenGL图像库(Simple OpenGL Image Library)的缩写,它支持大多数流行的图像格式。
- SOIL的下载网址:http://www.lonesock.net/soil.html
- 要想使用SOIL必须自己生成.lib。可以使用/projects文件夹内的任意一个解决方案(Solution)文件。还要添加src文件夹里面的文件到includes文件夹;将SOIL.lib添加到链接器选项,并在代码文件的开头加上
#include <SOIL.h>
。 - 使用SOIL加载图片的示例:
- 函数首先需要输入图片文件的路径。然后需要两个
int
指针作为第二个和第三个参数,SOIL会分别返回图片的宽度和高度到其中。后面我们在生成纹理的时候会用图像的宽度和高度。第四个参数指定图片的通道(Channel)数量,但是这里我们只需留为0
。最后一个参数告诉SOIL如何来加载图片:我们只关注图片的RGB
值。结果会储存为一个很大的char/byte数组。
生成纹理
- 纹理是使用ID引用的。glGenTextures函数首先需要输入生成纹理的数量,然后把它们储存在第二个参数的
GLuint
数组中。 - 我们需要绑定它,让之后任何的纹理指令都可以配置当前绑定的纹理。
- 我们可以使用前面载入的图片数据生成一个纹理了。纹理可以通过glTexImage2D来生成:
- 当调用glTexImage2D时,当前绑定的纹理对象就会被附加上纹理图像。然而,目前只有基本级别(Base-level)的纹理图像被加载了,如果要使用多级渐远纹理,我们必须手动设置所有不同的图像(不断递增第二个参数)。或者,直接在生成纹理之后调用glGenerateMipmap。这会为当前绑定的纹理自动生成所有需要的多级渐远纹理。
- 释放图像的内存并解绑纹理对象操作。
- 生成一个纹理的完整过程
纹理单元
- 一个纹理的位置值通常称为一个纹理单元,一个纹理的默认纹理单元是0,它是默认的**纹理单元。
- 使用glUniform1i,我们可以给纹理采样器分配一个位置值,这样的话我们能够在一个片段着色器中设置多个纹理。
- 纹理单元的主要目的是让我们在着色器中可以使用多于一个的纹理。通过把纹理单元赋值给采样器,我们可以一次绑定多个纹理。
- 我们可以使用glActiveTexture**纹理单元,传入我们需要使用的纹理单元:
- **纹理单元之后,接下来的glBindTexture函数调用会绑定这个纹理到当前**的纹理单元。纹理单元GL_TEXTURE0默认总是被激。
- 我们需要编辑片段着色器来接收另一个采样器,具体的演示示例如下:
- 最终输出颜色现在是两个纹理的结合。GLSL内建的mix函数需要接受两个值作为参数,并对它们根据第三个参数进行线性插值。如果第三个值是
0.0
,它会返回第一个输入;如果是1.0
,会返回第二个输入值。0.2
会返回80%
的第一个输入颜色和20%
的第二个输入颜色,即返回两个纹理的混合色。 - 先绑定两个纹理到对应的纹理单元,然后定义哪个uniform采样器对应哪个纹理单元:
- 我们使用glUniform1i设置uniform采样器的位置值,或者说纹理单元。通过glUniform1i的设置,我们保证每个uniform采样器对应着正确的纹理单元。
- 根据上图可以发现:纹理上下颠倒了。这是因为OpenGL要求y轴
0.0
坐标是在图片的底部的,但是图片的y轴0.0
坐标通常在顶部。一些图片加载器比如Devil在加载的时候有选项重置y原点,但是SOIL没有。 - SOIL却有一个叫做SOIL_load_OGL_texture函数可以使用一个叫做SOIL_FLAG_INVERT_Y的标记加载并生成纹理,这可以解决我们的问题。不过这个函数用了一些在现代OpenGL中失效的特性。
-
修复我们的小问题,有两个选择:
- (1)我们可以改变顶点数据的纹理坐标,翻转
y
值(用1减去y坐标)。 - (2)我们可以编辑顶点着色器来自动翻转
y
坐标,替换TexCoord
的值为TexCoord = vec2(texCoord.x, 1.0f - texCoord.y);
。
摄像机-自由移动
- 首先我们必须设置一个摄像机系统,所以在我们的程序前面定义一些摄像机变量很有用:
- 我们首先将摄像机位置设置为之前定义的cameraPos。方向是当前的位置加上我们刚刚定义的方向向量。
- 当我们按下WASD键的任意一个,摄像机的位置都会相应更新。如果我们希望向前或向后移动,我们就把位置向量加上或减去方向向量。如果我们希望向左右移动,我们使用叉乘来创建一个右向量(Right Vector),并沿着它相应移动就可以了。这样就创建了使用摄像机时熟悉的扫射(Strafe)效果。
- 因为大多数事件输入系统一次只能处理一个键盘输入,它们的函数只有当我们**了一个按键时才被调用。