LearnGL - 学习笔记目录
前一篇:LearnGL - 15 - Skybox - 天空盒 - 了解了如何构造一个天空盒
这一篇:实现类似环境反射的效果,我们可以使用纯颜色、天空盒来做反射采样的颜色。
总体来说我现实的这种比较简单,不过很多都是基于之前的内容类实现的。
本人才疏学浅,如有什么错误,望不吝指出。
用到 r e f l e c t ( I , N ) reflect(I, N) reflect(I,N),也可以参考会之前的 LearnGL - 11.1 - 实现简单的Gouraud光照模型 - reflect - 反射高光方向
这个具体看 shader 了
主要看:calculateReflection
函数
void calculateReflection(vec3 worldNormal, vec3 viewDir, inout vec3 albedo) {
if (Material.ReflectionK > 0) {
vec3 reflection_color = albedo;
if (ClearType == CLEAR_TYPE_SKYBOX) { // 天空盒的
vec3 R = reflect(-viewDir, worldNormal);
reflection_color = texture(SkyboxTex, R).rgb;
} else if (ClearType == CLEAR_TYPE_COLOR) { // 清理颜色的
reflection_color = ClearColor; // 不用计算反射
}
albedo = mix(albedo, reflection_color, Material.ReflectionK);
}
}
// jave.lin - my_global.glsl
#ifndef _MY_GLOBAL__GLSL__
#define _MY_GLOBAL__GLSL__
#define CLEAR_TYPE_COLOR 0
#define CLEAR_TYPE_SKYBOX 1
// camera uniform
uniform vec3 _CamWorldPos; // 镜头世界坐标
uniform int ClearType; // 渲染相机的 clear type
uniform vec3 ClearColor; // 清理的颜色
uniform samplerCube SkyboxTex; // 天空盒
// scene uniform
uniform vec4 _Ambient; // .xyz 环境光颜色, .w 环境光系数
uniform int AmbientType; // 环境光类别,[测试用]
// local uniform
uniform mat4 mMat; // m 矩阵
uniform mat4 vMat; // v 矩阵
uniform mat4 pMat; // p 矩阵
uniform mat4 mvpMat; // m.v.p 矩阵
uniform mat4 IT_mMat; // Model Matrix 的逆矩阵的转置矩阵
// 将对象空间的法线转换到世界空间下的法线
vec3 ObjectToWorldNormal(vec3 n) {
return normalize(mat3(IT_mMat) * n); // 等价于:transpose(I_mMat) * vec4(n, 0)
}
vec3 getWorldViewDir(vec3 worldPos) {
return normalize(_CamWorldPos - worldPos);
}
#endif /* _MY_GLOBAL__GLSL__ */ // 这里一定要加 /* 你的头文件宏 */,否则会报错,太无语了
// jave.lin - my_lighting.glsl - 光照模型处理
#include "/Include/my_global.glsl"
#ifndef _MY_LIGHTING__GLSL__
#define _MY_LIGHTING__GLSL__
#define DIRECTIONAL_LIGHT_TYPE 0
#define POINT_LIGHT_TYPE 1
#define SPOT_LIGHT_TYPE 2
// 材质属性 - 很多的属性可以合并到其他没有满4个分量的属性,但学习目的,为了可读性高,可以分开来
struct Material_t {
float Glossy; // 光滑度
vec3 Emission; // 自发光颜色
vec3 DiffuseK; // 漫反射系数
vec3 SpecularK; // 高光系数
float ReflectionK; // 反射系数
};
uniform Material_t Material;
// 灯光属性 - 很多的属性可以合并到其他没有满4个分量的属性,但学习目的,为了可读性高,可以分开来
// 灯光属性也可以按类型来分为不同的材质结构体
// 但是为了编写方便,就没有分开了
struct LightData_t {
// common properties
int Enabled; // 是否开启
int Type; // 灯光类似
vec3 Color; // 灯光颜色
float Intensity; // 强度
// directional or spot light
vec3 Direction; // 方向光 或 聚光灯 照射方向
// point or spot light
vec3 Position; // 点光源 或 聚光灯 灯光世界坐标位置
float ATTEN_Kc; // 点光源 常数项系数
float ATTEN_Kl; // 点光源 一次项系数
float ATTEN_Kq; // 点光源 二次项系数
vec2 ATTEN_Range; // 点光源 有效范围, .x == range, .y == 1.0 / range
// spot light
float SpotFOL; // 聚光灯的张角量,Field Of Light(弧度)
float SpotFOL_FadeOut;// 这个边缘淡出的角度,必须小于 SpotFOL,否则没有效果
};
const uint MaxLightNum = 10;
uniform LightData_t Lights[MaxLightNum];
// ambient
vec3 getAmbient(vec3 albedo) {
if (AmbientType == 0) return _Ambient.rgb * _Ambient.a;
else return mix(_Ambient.rgb * _Ambient.a, albedo, _Ambient.a);
}
// point or spot light 的光距离衰减
float getDistanceAtten(float dist, LightData_t light) { // 获取距离衰减
// 由原来的 atten = 1 / (kc + kl * dist + kq * dist * dist) 改为只用一个 sommthstep就够了
// smoothstep 的曲线取反,即:1 - smoothstep,结果的曲线也不错
return 1 - smoothstep(0, light.ATTEN_Range.x, dist);
}
void phong_illumination(
in vec3 worldNormal,
in vec3 viewDir,
in vec3 worldPos,
out vec3 diffuse,
out vec3 specular
) {
for (int i = 0; i < MaxLightNum; ++i) {
LightData_t light = Lights[i];
// 如何有一个没开启,则后面都没开启,这是需要应用层配合使用的规则
if (light.Enabled == 0) break;
// 光源的方向
vec3 lightDir;
// 衰减
float atten = 1;
// 方向光
if (light.Type == DIRECTIONAL_LIGHT_TYPE) {
lightDir = light.Direction;
}
// 点光源
else {
// 点光源 或是 聚光灯 都需要处理的
lightDir = light.Position - worldPos; // 片段到光源的方向,简称:灯光方向
float dist = length(lightDir); // 片段到光源的距离
lightDir *= dist == 0 ? 1 : 1.0 / dist; // 归一化
atten = getDistanceAtten(dist, light); // 获取距离衰减
// 聚光灯
if (light.Type == SPOT_LIGHT_TYPE) {
float LdotSD = dot(lightDir, light.Direction);
float angle = acos(LdotSD);
if (angle < light.SpotFOL) {
// 在 FOL 张角内
if (angle > light.SpotFOL_FadeOut) {
// 平滑边缘
atten *= 1 - smoothstep(light.SpotFOL_FadeOut, light.SpotFOL, angle);
}
} else {
// 不在 FOL 张角内
atten = 0;
}
}
}
float D = max(0, dot(lightDir, worldNormal));
diffuse += light.Color * light.Intensity * D * Material.DiffuseK * atten;
vec3 H = normalize(lightDir + viewDir);
float S = 0;
if (D > 0) S = pow(max(0, dot(H, worldNormal)), Material.Glossy);
specular += light.Color * light.Intensity * S * Material.SpecularK * atten;
}
}
void calculateReflection(vec3 worldNormal, vec3 viewDir, inout vec3 albedo) {
if (Material.ReflectionK > 0) {
vec3 reflection_color = albedo;
if (ClearType == CLEAR_TYPE_SKYBOX) { // 天空盒的
vec3 R = reflect(-viewDir, worldNormal);
reflection_color = texture(SkyboxTex, R).rgb;
} else if (ClearType == CLEAR_TYPE_COLOR) { // 清理颜色的
reflection_color = ClearColor; // 不用计算反射
}
albedo = mix(albedo, reflection_color, Material.ReflectionK);
}
}
#endif