立方体贴图
立方体贴图(Cube Map):将多个纹理组合起来映射到一张纹理上的一种纹理(简单来说,就是一个包含了 6
个 2D
纹理的纹理,每个 2D
纹理都组成了立方体的一个面:一个有纹理的立方体。)。
创建立方体贴图
1 | GLuint textureID; |
生成立方体贴图:
1 | GLint width, height, nrChannels; |
由于立方体有 6 个面,OpenGL
提供了 6
个特殊的纹理目标,专门对应立方体贴图的一个面。
纹理目标 | 方位 |
---|---|
GL_TEXTURE_CUBE_MAP_POSITIVE_X |
右 |
GL_TEXTURE_CUBE_MAP_NEGATIVE_X |
左 |
GL_TEXTURE_CUBE_MAP_POSITIVE_Y |
上 |
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y |
下 |
GL_TEXTURE_CUBE_MAP_POSITIVE_Z |
后 |
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z |
前 |
设置环绕和过滤方式:
1 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
使用纹理:
1 | glActiveTexture(unit); // 先激活对应的纹理单元 |
用于贴图
3D
立方体的立方体贴图可以使用立方体的位置作为纹理坐标来采样。当立方体处于 原点(0, 0, 0) 时,它的每一个位置向量都是从原点出发的方向向量。这个方向向量正是获取立方体上特定位置的纹理值所需要的,因此,只需要提供位置向量而不用纹理坐标了。
天空盒
绘制天空盒时,需要将它变为场景中的 第一个 渲染的物体,并且禁用深度写入。这样天空盒就会永远被绘制在其它物体的背后了。(但这样会对屏幕上的每一个像素运行一遍片段着色器,效率不高且耗性能)。
优化
在顶点着色器运行之后执行的,透视除法 将 gl_Position
的 xyz
坐标除以 w
分量;而相除结果的 z
分量等于顶点的 深度值。根据这些信息,如果将输出位置的 z
分量等于它的 w
分量,这样当透视除法执行之后,z
分量会变为 w / w = 1.0
。这样就可以把天空盒子绘制在最后以降低性能消耗。
1 | void main() |
环境映射
环境映射:使用环境立方体贴图给物体一定属性的技术。其中最常见的两个是 反射
和 折射
。
反射
反射(Reflection):属性表现为物体(或物体的一部分)反射它周围环境(即根据观察者的视角,物体的颜色或多或少等于它的环境)。
- I:观察方向向量
- N:物体的法向量
- R:反射向量(可以使用
GLSL
内建的reflect
函数来计算这个反射向量;其需要一个法向量和一个观察方向向量)
其片段着色器大致如下:
1 |
|
折射
折射(Refraction):是光线由于传播介质的改变而产生的方向变化。
- I:观察方向向量
- N:物体的法向量
- R:折射向量(可以使用
GLSL
内建的refract
函数来计算这个折射向量;其需要一个法向量、一个观察方向向量和两个材质之间的折射率(Refractive Index)。)
常见物体折射率(决定了材质中光线弯曲的程度):
材质 | 折射率 |
---|---|
空气 | 1.00 |
水 | 1.33 |
冰 | 1.309 |
玻璃 | 1.52 |
钻石 | 2.42 |
使用这些折射率来计算光传播的两种材质间的比值;例如,光线/视线从空气进入玻璃,则比值为 1.00/1.52=0.658
,其片段着色器大致如下:
1 |
|
效果
Demo
参考
教程来源:https://learnopengl.com/。