learnOpenGL笔记-光照贴图

光照贴图

在现实世界中,一个物体都是由很多部分组成的,而组成物体的各个部分也拥有着完全不同的材质,而在之前我们所定义的物体为一个均匀的材质,这是远远不够的。

这里就引入漫反射贴图以及镜面反射贴图,允许我们能够更精确的控制漫反射分量和镜面分量。

漫反射贴图

漫反射贴图说白了就是之前所运用到的纹理,两者所用到的原理完全相同。

漫反射贴图表示的是物体所有漫反射颜色的纹理图像。例如下图:

用法与纹理一样,只不过在此处之前的漫反射颜色向量vec3 ambient替换为漫反射贴图。将纹理存储为结构体material中的一个sampler2D。

同时也移除了环境光颜色向量,因为环境光颜色与漫反射颜色基本一致,所以不需要分开存储。

struct Material {
    sampler2D diffuse;
    vec3      reflection;
    float     shininess;
}; 
...
in vec2 TexCoords;

由于纹理采样需要纹理坐标,所以需要从顶点着色器中接收一个纹理坐标,然后进行采样。

vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoord                   s));

其中light.diffuse表示的是环境光强度,diff表示的是光线与法线夹角的余弦值,用来衡量漫反射的多少,vec(texture(...))是对纹理的采样。

对环境光做同样操作。

vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));

顶点的数据也需要更新,形式为:vec3(位置)vec3(法线)vec2(纹理),例如立方体其中一面:

    -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,
     0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 0.0f,
     0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
     0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,

同时更新顶点着色器layout,并向片段着色器输出纹理坐标。

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
...
out vec2 TexCoords;

void main()
{
    ...
    TexCoords = aTexCoords;
}

接着要更新两个VAO的顶点属性指针

glBindVertexArray(lightingVAO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
glBindVertexArray(lightCubeVAO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

镜面光贴图

在上面生成的你可能会觉得有些奇怪,木头不应该有这样强的高光,我们可以设置镜面光材质为vec3(0.0)来解决,但是又会出现一个新的问题,箱子一圈的钢圈本应该有高光的,设置完后会丢失高光,所以我们想让木头与钢圈显示不用的高光强度。

因此我们可以使用一个镜面光贴图来专门用于生成高光,我们需要一个黑白纹理来表示高光强度,如下:

镜面高光的强度可以通过每个像素的亮度来获取。镜面光贴图上的每一个像素都可以用一个颜色向量来表示,vec3(0.0)表示黑色,vec3(1.0)表示白色,这样就可以在片段着色器中将对应的颜色向量乘以光源的镜面强度,得到物体的镜面光分量,颜色越量,所得值越大。(这里假设木头没有高光,其实还是有微小高光)。

绑定纹理单元:

lightingShader.setInt("material.reflection", 1);
...
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, specularMap);

更新片段着色器的材质属性:

struct Material {
    sampler2D diffuse;
    sampler2D reflection;
    float     shininess;
};

采样镜面光贴图,计算镜面光强度

vec3 ambient  = light.ambient  * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse  = light.diffuse  * diff * vec3(texture(material.diffuse, TexCoords));  
vec3 ref = light.ref * ref * vec3(texture(material.reflection, TexCoords));
FragColor = vec4(ambient + diffuse + ref, 1.0);

可以看到高光只在钢圈上出现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值