欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

learnOpenGL 4.6 立方纹理

程序员文章站 2022-03-25 10:34:22
...

立方纹理是一种特殊纹理,它利用从立方体中心出发的方向向量进行纹理的采样,如下图:
learnOpenGL 4.6 立方纹理
方向向量的大小并不重要,只要提供了方向,OpenGL就会获取方向向量(最终)所击中的纹素,并返回对应的采样纹理值。
这样子,只要立方体的中心位于原点,我们就能使用立方体的实际位置向量来对立方体贴图进行采样了。


于是乎,我们要做的就是要使面与相应的贴图对应。
learnOpenGL 4.6 立方纹理
因为立方体贴图包含有6个纹理,每个面一个,我们需要调用glTexImage2D函数6次,参数和之前教程中很类似。但这一次我们将纹理目标(target)参数设置为立方体贴图的一个特定的面,告诉OpenGL我们在对立方体贴图的哪一个面创建纹理。

和OpenGL的很多枚举(Enum)一样,它们背后的int值是线性递增的,所以如果我们有一个纹理位置的数组或者vector,我们就可以从GL_TEXTURE_CUBE_MAP_POSITIVE_X开始遍历它们,在每个迭代中对枚举值加1,遍历了整个纹理目标

int width, height, nrChannels;
unsigned char *data;  
for(unsigned int i = 0; i < textures_faces.size(); i++)
{
    data = stbi_load(textures_faces[i].c_str(), &width, &height, &nrChannels, 0);
    glTexImage2D(
        GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 
        0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data
    );
}

天空盒

立方纹理的一个重要应用就是天空盒,因为天空盒的中心始终在原点不移动,而且可以方便做反射折射等操作。

天空盒本质上是一个单位立方纹理,不过有几点特殊:

  • 它的深度值要设为1.0(最大值),因为作为背景不应该挡住任何物体。

为了方便,我们直接将z值设为和W值相同。

gl_Position = pos.xyww;

我们还要改变一下深度函数,将它从默认的GL_LESS改为GL_LEQUAL(小于等于)。因为1.0已经是默认的最大值,只能等于不可能小于。

glDepthFunc(GL_LEQUAL);
  • 它不需要model矩阵,因为在原点。
  • 它的观察矩阵应该不移动,只能旋转。

方便起见,我们可以通过取4x4矩阵左上角的3x3矩阵来移除变换矩阵的位移部分。我们可以将观察矩阵转换为3x3矩阵(移除位移),再将其转换回4x4矩阵,来达到类似的效果。

glm::mat4 view = glm::mat4(glm::mat3(camera.GetViewMatrix()));

反射折射

因为立方纹理只需要方向向量就可以进行纹理采样,我们只要计算反射和折射的向量,就可做出环境的反射和折射效果了。

learnOpenGL 4.6 立方纹理
learnOpenGL 4.6 立方纹理
顶点着色器:

...
void main()
{
    Normal = mat3(transpose(inverse(model))) * aNormal;
    Position = vec3(model * vec4(aPos, 1.0));
    gl_Position = projection * view * model * vec4(aPos, 1.0);
}

反射的片元着色器:

...
void main()
{             
    vec3 I = normalize(Position - cameraPos);
    vec3 R = reflect(I, normalize(Normal));
    FragColor = vec4(texture(skybox, R).rgb, 1.0);
}

折射的片元着色器:
1.52为玻璃的折射率。

...
void main()
{             
    float ratio = 1.00 / 1.52;
    vec3 I = normalize(Position - cameraPos);
    vec3 R = refract(I, normalize(Normal), ratio);
    FragColor = vec4(texture(skybox, R).rgb, 1.0);
}
相关标签: 笔记 opengl