立方体贴图

立方体贴图

立方体贴图是一个包含了6个2D纹理的纹理,这样可以用一个方向向量来进行索引和采样
a

//使用立方体贴图的着色器
in vec3 textureDir; // 代表3D纹理坐标的方向向量
uniform samplerCube cubemap; // 立方体贴图的纹理采样器

void main()
{             
    FragColor = texture(cubemap, textureDir);
}

天空盒!!


天空盒事实上就是一个立方体贴图

//加载天空盒贴图和立方体一样
unsigned int loadCubemap(vector<std::string> faces)
{
    unsigned int textureID;
    glGenTextures(1, &textureID);
    glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);

    int width, height, nrChannels;
    for (unsigned int i = 0; i < faces.size(); i++)
    {
        unsigned char *data = stbi_load(faces[i].c_str(), &width, &height, &nrChannels, 0);
        if (data)
        {
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 
                         0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data
            );
            stbi_image_free(data);
        }
        else
        {
            std::cout << "Cubemap texture failed to load at path: " << faces[i] << std::endl;
            stbi_image_free(data);
        }
    }
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

    return textureID;
}

对于立方体贴图来说,直接使用位置向量来进行采样即可。

把输入的位置向量作为输出给片段着色器的纹理坐标,然后在片段着色器中作为输入采样samplerCube.之后把立方体纹理绑定后就可以出现天空的效果。

注意:如果希望移动视角时,背景不移动,应该去除位移部分,之后再转换回为4x4矩阵可以达到目的
glm::mat4 view = glm::mat4(glm::mat3(camera.GetViewMatrix()));

优化

如果先渲染天空盒,会导致后来物体进行重复渲染,可以使用提前深度测试
即最后让天空盒渲染,但对应的这个天空盒的深度z必须是1,在透视除法中,xyz坐标除以w分量,而深度测试中,z就是深度值.所以当z分量等于w分量时可以让z分量一直为1.0.

环境映射

使用环境立方体贴图的技术,有两个:反射和折射.

  1. 反射:
#version 330 core
out vec4 FragColor;

in vec3 Normal;
in vec3 Position;

uniform vec3 cameraPos;
uniform samplerCube skybox;

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

进行反射计算取样,让物体可以实现反射的功能。

2.折射:

GLSL中有一些对应的折射函数refract

//着色器
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);
}

动态环境贴图:
可以使用帧缓冲来为6个不同角度创建纹理,在每次渲染迭代中存到立方体贴图中,动态产生立方体贴图。

高级数据

缓冲是一个管理特定内存块的对象,将缓冲绑定到目标时才会有对应的处理缓冲的方式。

一般使用glBufferData进行管理,可以设置为Null之后再进行填充,或者使用glBufferSubData来填充缓冲的特定区域

分批顶点属性

float positions[] = { ... };
float normals[] = { ... };
float tex[] = { ... };
// 填充缓冲
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), &positions);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions), sizeof(normals), &normals);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions) + sizeof(normals), sizeof(tex), &tex);

复制缓冲:
glCopyBufferSubData把一个缓冲复制到另一个缓冲中。

posted @ 2022-11-01 16:01  梦呓qwq  阅读(34)  评论(0编辑  收藏  举报