opengl环境映射,反射贴图

注意完整的mesh与shader文件:

  • mesh增加了法线与高度贴图:
    // render the mesh
    void Draw(Shader shader)
    {
        // bind appropriate textures
        unsigned int diffuseNr = 1;
        unsigned int specularNr = 1;
        unsigned int normalNr = 1;
        unsigned int heightNr = 1;
        for (unsigned int i = 0; i < textures.size(); i++)
        {
            glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding
            // retrieve texture number (the N in diffuse_textureN)
            string number;
            string name = textures[i].type;
            if (name == "texture_diffuse")
                number = std::to_string(static_cast<long long>(diffuseNr++));
            else if (name == "texture_specular")
                number = std::to_string(static_cast<long long>(specularNr++)); // transfer unsigned int to stream
            else if (name == "texture_normal")
                number = std::to_string(static_cast<long long>(normalNr++)); // transfer unsigned int to stream
            else if (name == "texture_height")
                number = std::to_string(static_cast<long long>(heightNr++)); // transfer unsigned int to stream

                                                     // now set the sampler to the correct texture unit
            glUniform1i(glGetUniformLocation(shader.ID, (name + number).c_str()), i);
            // and finally bind the texture
            glBindTexture(GL_TEXTURE_2D, textures[i].id);
        }

        // draw mesh
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);

        // always good practice to set everything back to defaults once configured.
        glActiveTexture(GL_TEXTURE0);
    }
  • model增加了两个贴图的传值
    Mesh processMesh(aiMesh* mesh, const aiScene* scene)
    {
        // data to fill
        vector<Vertex> vertices;
        vector<unsigned int> indices;
        vector<Texture> textures;

        // Walk through each of the mesh's vertices
        for (unsigned int i = 0; i < mesh->mNumVertices; i++)
        {
            Vertex vertex;
            glm::vec3 vector; // we declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first.
            // positions
            vector.x = mesh->mVertices[i].x;
            vector.y = mesh->mVertices[i].y;
            vector.z = mesh->mVertices[i].z;
            vertex.Position = vector;
            // normals
            vector.x = mesh->mNormals[i].x;
            vector.y = mesh->mNormals[i].y;
            vector.z = mesh->mNormals[i].z;
            vertex.Normal = vector;
            // texture coordinates
            if (mesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
            {
                glm::vec2 vec;
                // a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't 
                // use models where a vertex can have multiple texture coordinates so we always take the first set (0).
                vec.x = mesh->mTextureCoords[0][i].x;
                vec.y = mesh->mTextureCoords[0][i].y;
                vertex.TexCoords = vec;
            }
            else
                vertex.TexCoords = glm::vec2(0.0f, 0.0f);
            // tangent
            vector.x = mesh->mTangents[i].x;
            vector.y = mesh->mTangents[i].y;
            vector.z = mesh->mTangents[i].z;
            vertex.Tangent = vector;
            // bitangent
            vector.x = mesh->mBitangents[i].x;
            vector.y = mesh->mBitangents[i].y;
            vector.z = mesh->mBitangents[i].z;
            vertex.Bitangent = vector;
            vertices.push_back(vertex);
        }
        // now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.
        for (unsigned int i = 0; i < mesh->mNumFaces; i++)
        {
            aiFace face = mesh->mFaces[i];
            // retrieve all indices of the face and store them in the indices vector
            for (unsigned int j = 0; j < face.mNumIndices; j++)
                indices.push_back(face.mIndices[j]);
        }
        // process materials
        aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
        // we assume a convention for sampler names in the shaders. Each diffuse texture should be named
        // as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER. 
        // Same applies to other texture as the following list summarizes:
        // diffuse: texture_diffuseN
        // specular: texture_specularN
        // normal: texture_normalN

        // 1. diffuse maps
        vector<Texture> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
        textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
        // 2. specular maps
        vector<Texture> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
        textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
        // 3. normal maps
        std::vector<Texture> normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
        textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
        // 4. height maps
        std::vector<Texture> heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height");
        textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());

        // return a mesh object created from the extracted mesh data
        return Mesh(vertices, indices, textures);
    }
  • model中在push的时候打印纹理信息:
            if (!skip)
            {   // if texture hasn't been loaded already, load it
                Texture texture;
                texture.id = TextureFromFile(str.C_Str(), this->directory);
                texture.type = typeName;
                texture.path = str.C_Str();
                textures.push_back(texture);
                textures_loaded.push_back(texture);  // store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures.
                cout << "textures_loaded.push_back ID:" << texture.id << " type:" << texture.type << " parth:" << texture.path << endl;
            }

环境映射

  • 我们现在将整个环境映射到了一个纹理对象上了,能利用这个信息的不仅仅只有天空盒。通过使用环境的立方体贴图,我们可以给物体反射和折射的属性。这样使用环境立方体贴图的技术叫做环境映射(Environment Mapping),其中最流行的两个是反射(Reflection)和折射(Refraction)。

反射

  • 反射这个属性表现为物体(或物体的一部分)反射它周围环境,即根据观察者的视角,物体的颜色或多或少等于它的环境。镜子就是一个反射性物体:它会根据观察者的视角反射它周围的环境。

  • 我们根据观察方向向量I¯和物体的法向量N¯,来计算反射向量R¯。

  • GLSL内建的reflect函数来计算这个反射向量。最终的R¯向量将会作为索引/采样立方体贴图的方向向量,返回环境的颜色值。最终的结果是物体看起来反射了天空盒。
    在这里插入图片描述

  • 注意这里的position和cameraPos就是例子代码中的FragPosition和ViewPosion

#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);
}
  • 我们先计算了观察/摄像机方向向量I,并使用它来计算反射向量R,之后我们将使用R来从天空盒立方体贴图中采样。注意,我们现在又有了片段的插值Normal和Position变量,所以我们需要更新一下顶点着色器。
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;

out vec3 Normal;
out vec3 Position;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    Normal = mat3(transpose(inverse(model))) * aNormal;
    Position = vec3(model * vec4(aPos, 1.0));
    gl_Position = projection * view * model * vec4(aPos, 1.0);
}
  • 例子代码:只改变了片段着色器的代码
//	FragColor = vec4(result,1.0);

	vec3 I = normalize(FragPos - viewPos);
    vec3 R = reflect(I, normalize(Normal));
    FragColor = vec4(texture(skybox, R).rgb, 1.0);

在这里插入图片描述

折射

  • 环境映射的另一种形式是折射,它和反射很相似。折射是光线由于传播介质的改变而产生的方向变化。在常见的类水表面上所产生的现象就是折射,光线不是直直地传播,而是弯曲了一点。将你的半只胳膊伸进水里,观察出来的就是这种效果。
    折射是通过斯涅尔定律(Snell’s Law)来描述的,使用环境贴图的话看起来像是这样:
    在这里插入图片描述
  • 同样,我们有一个观察向量I¯,一个法向量N¯,而这次是折射向量R¯。可以看到,观察向量的方向轻微弯曲了。弯折后的向量R¯将会用来从立方体贴图中采样。
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);
}

在这里插入图片描述

增加模型上不同纹理的反射渲染

  • main函数在补全shader和mesh的函数之后,添加绑定skybox用于进行反射渲染的值。注意设定成31是因为肯定不会被占用,使用的时候是先激活后绑定
    注意之前用的纹理获取是什么样的,这里注意mesh.H中的纹理单元先激活后绑定glBindTexture(GL_TEXTURE_2D, textures[i].id)
    unsigned int cubemapTexture = loadCubemap(faces);
//在mesh.h中先激活后进行绑定
    void Draw(Shader shader)
    {
        // bind appropriate textures
        unsigned int diffuseNr = 1;
        unsigned int specularNr = 1;
        unsigned int normalNr = 1;
        unsigned int heightNr = 1;
        for (unsigned int i = 0; i < textures.size(); i++)
        {
            glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding
            // retrieve texture number (the N in diffuse_textureN)
            string number;
            string name = textures[i].type;
            if (name == "texture_diffuse")
                number = std::to_string(static_cast<long long>(diffuseNr++));
            else if (name == "texture_specular")
                number = std::to_string(static_cast<long long>(specularNr++)); // transfer unsigned int to stream
            else if (name == "texture_normal")
                number = std::to_string(static_cast<long long>(normalNr++)); // transfer unsigned int to stream
            else if (name == "texture_height")
                number = std::to_string(static_cast<long long>(heightNr++)); // transfer unsigned int to stream

            // now set the sampler to the correct texture unit
            glUniform1i(glGetUniformLocation(shader.ID, (name + number).c_str()), i);
            // and finally bind the texture
            glBindTexture(GL_TEXTURE_2D, textures[i].id);
        }
  • 激活一个纹理单元,所以应该用31,注意纹理值(cubemapTexture)要和skybox绑定
        //ourModel.Draw(cubeShader);
        glActiveTexture(GL_TEXTURE31);  //激活一个纹理单元,第31个肯定不会被占用
        modelShader.setInt("skybox", 31);   //设定值31号位置为skybox
        glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);//纹理值必须要绑定
  • 添加反射光渲染
uniform samplerCube skybox;
//增加纹理的光反射渲染
vec3 CalcReflectLight()
{

	vec3 result = vec3(0.0,0.0,0.0);
	vec3 I = normalize(FragPos - viewPos);
    vec3 R = reflect(I, normalize(Normal));
	return texture(skybox, R).rgb;
	
}
  • 主函数上设定渲染后的材质光
void main()
{
	//材质光
	vec3 reflect1 = vec3(texture(texture_height1,TexCoords));	
  • 去掉手电筒光源之后的result
	vec3 result = vec3(0.0,0.0,0.0);
	result += CalcReflectLight()*reflect1.r;
	result +=  CalcPointLight(light);

	FragColor = vec4(result,1.0);
  • 效果请添加图片描述
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值