5、片元着色器之基础光照模型:Phong模型和Blinn-Phong模型

1、什么是Phong光照模型?

Phong模型就是在兰伯特模型的基础上增加了镜面反射光的计算。具体来说,兰伯特模型只考虑漫反射光,而Phong模型在此基础上引入了镜面反射光的概念,以模拟光线在光滑表面反射时产生的高光效果。镜面反射光的计算考虑了观察者的视角和光源的方向,能够产生更加逼真的高光效果。

2、示例

cpp 复制代码
//限制光线步进的范围,防止计算过长的距离。
const float maxDistance=40.;
// 球心在原点,半径为1.0的球体
float sdSphere(vec3 point)
{
    return length(point)-1.;
}
// 光线步进,start指的是相机(视点)位置;direction表示从相机(视点)发出的光线的方向
float rayMarching(vec3 start,vec3 direction)
{
    float d=0.;
    for(int i=0;i<9999;i++)
    {
        vec3 point=start+d*direction;
        // 像素点到球体表面的距离
        float d0=sdSphere(point);
        // 当d0小于0.001时认为射线和球体表面相交了
        if(d0<.001||d>maxDistance)break;
        d+=d0;
    }
    return d;
}

vec3 getNormal(vec3 p)
{
    float d=sdSphere(p);
    vec2 e=vec2(.001,.0);
    float fdx=d-sdSphere(p-e.xyy);
    float fdy=d-sdSphere(p-e.yxy);
    float fdz=d-sdSphere(p-e.yyx);
    return normalize(vec3(fdx,fdy,fdz));
}
// 构建绕y轴旋转的旋转矩阵
mat2 rot(float angle){
    float c=cos(angle);
    float s=sin(angle);
    return mat2(c,-s,s,c);
}
void mainImage(out vec4 fragColor,in vec2 fragCoord){
    // 将像素坐标标准化为 [-1, 1] 的范围
    vec2 uv=(fragCoord-iResolution.xy*.5)/iResolution.y;
    
    vec3 color=vec3(0.);
    // 视点在z轴正方向上,渲染结果就是相机在该位置看到的结果
    vec3 cameraPosition=vec3(0.,0.,5.);
    
    // 改变direction的z分量实际上相当于修改了fov的大小,fov越小,物体看起来越大(前提是其他参数不变)
    //vec3 direction=normalize(vec3(uv,-1.0));// fov是90°
    vec3 direction=normalize(vec3(uv,-2.));// fov是53.13°
    
    float d=rayMarching(cameraPosition,direction);
    if(d<maxDistance){
        vec3 point=cameraPosition+d*direction;
        vec3 normal=getNormal(point);
        // 定义光源位置,在xoy坐标系的第一象限
        vec3 lightPosition=vec3(5.,5.,0.);
        // 相机绕着y轴转
        lightPosition.xz*=rot(iTime);
        // 定义光源方向
        vec3 lightDir=normalize(lightPosition-point);
        
        // 光源的强度
        float lightIntensity=1.;
        
        // 漫反射系数
        float kd=1.;
        // 漫反射光强(兰伯特模型)
        float diffuseIntensity=kd*lightIntensity*max(dot(normal,lightDir),0.);
        
        //镜面反射
        vec3 reflectDir=reflect(-lightDir,normal);//reflect函数:提供入射光线和法线,返回反射向量
        //视线向量:从表面指向观察者
        vec3 viewDir=normalize(cameraPosition-point);
        // 镜面反射系数
        float ks=1.;
        //控制高光区域大小的系数。数值越大,光斑越小且越亮
        float shininess=8.0;
        //通过点乘来衡量反射光线是否接近视线方向;pow用于实现高光的集中度
        float specular=pow(max(dot(reflectDir,viewDir),0.0),shininess);
        // 灯光颜色
        vec3 lightColor=vec3(1.,.5,.3);
        // 设置球体颜色
        color+=lightColor*(diffuseIntensity+specular);
    }
    fragColor=vec4(color,1.);
}

3、Blinn-Phong模型

Blinn-Phong光照模型是Phong光照模型的一种改进,主要用于计算镜面反射光的强度。相较于Phong模型,Blinn-Phong模型在计算上更加高效,并且能够更好地模拟光照效果。Phong模型需要计算反射光线,是有一定计算量的,Blinn-Phong使用半角向量来简化计算。

4、示例

cpp 复制代码
//限制光线步进的范围,防止计算过长的距离。
const float maxDistance=40.;
// 球心在原点,半径为1.0的球体
float sdSphere(vec3 point)
{
    return length(point)-1.;
}
// 光线步进,start指的是相机(视点)位置;direction表示从相机(视点)发出的光线的方向
float rayMarching(vec3 start,vec3 direction)
{
    float d=0.;
    for(int i=0;i<9999;i++)
    {
        vec3 point=start+d*direction;
        // 像素点到球体表面的距离
        float d0=sdSphere(point);
        // 当d0小于0.001时认为射线和球体表面相交了
        if(d0<.001||d>maxDistance)break;
        d+=d0;
    }
    return d;
}

vec3 getNormal(vec3 p)
{
    float d=sdSphere(p);
    vec2 e=vec2(.001,.0);
    float fdx=d-sdSphere(p-e.xyy);
    float fdy=d-sdSphere(p-e.yxy);
    float fdz=d-sdSphere(p-e.yyx);
    return normalize(vec3(fdx,fdy,fdz));
}
// 构建绕y轴旋转的旋转矩阵
mat2 rot(float angle){
    float c=cos(angle);
    float s=sin(angle);
    return mat2(c,-s,s,c);
}
void mainImage(out vec4 fragColor,in vec2 fragCoord){
    // 将像素坐标标准化为 [-1, 1] 的范围
    vec2 uv=(fragCoord-iResolution.xy*.5)/iResolution.y;
    
    vec3 color=vec3(0.);
    // 视点在z轴正方向上,渲染结果就是相机在该位置看到的结果
    vec3 cameraPosition=vec3(0.,0.,5.);
    
    // 改变direction的z分量实际上相当于修改了fov的大小,fov越小,物体看起来越大(前提是其他参数不变)
    //vec3 direction=normalize(vec3(uv,-1.0));// fov是90°
    vec3 direction=normalize(vec3(uv,-2.));// fov是53.13°
    
    float d=rayMarching(cameraPosition,direction);
    if(d<maxDistance){
        vec3 point=cameraPosition+d*direction;
        vec3 normal=getNormal(point);
        // 定义光源位置,在xoy坐标系的第一象限
        vec3 lightPosition=vec3(5.,5.,0.);
        // 相机绕着y轴转
        lightPosition.xz*=rot(iTime);
        // 定义光源方向
        vec3 lightDir=normalize(lightPosition-point);
        
        // 光源的强度
        float lightIntensity=1.;
        
        // 漫反射系数
        float kd=1.;
        // 漫反射光强(兰伯特模型)
        float diffuseIntensity=kd*lightIntensity*max(dot(normal,lightDir),0.);
        
        //视线向量:从表面指向观察者
        vec3 viewDir=normalize(cameraPosition-point);
        // 半角向量
        vec3 halfVector=normalize(lightDir+viewDir);
        // 镜面反射系数
        float ks=1.;
        //控制高光区域大小的系数。数值越大,光斑越小且越亮
        float shininess=8.0;
        //通过点乘来衡量半角向量是否接近法线方向;pow用于实现高光的集中度
        float specular=pow(max(dot(halfVector,normal),0.0),shininess);

        // 灯光颜色
        vec3 lightColor=vec3(1.,.5,.3);
        // 设置球体颜色
        color+=lightColor*(diffuseIntensity+specular);
    }
    fragColor=vec4(color,1.);
}
相关推荐
二狗哈3 小时前
Cesium快速入门27:GeoJson自定义样式
前端·cesium·着色器
二狗哈2 天前
Cesium快速入门24:Appearance编写着色器修改外观
3d·webgl·cesium·着色器·地图可视化
二狗哈3 天前
Cesium快速入门22:fabric自定义着色器
运维·开发语言·前端·webgl·fabric·cesium·着色器
米芝鱼7 天前
UnityURP3D管线自定义功能shader
游戏·unity·shader·urp·着色器
联系QQ 19226387 天前
PEM电解槽Simulink模型,得出I-V曲线图,通过调参可以分析各参数对电解电压的影响。 ...
着色器
Echo_NGC223711 天前
【AirSim 教程指南】Part 3:相机与传感器(RGB / 深度 / 分割 / LiDAR)
人工智能·计算机视觉·游戏引擎·ar·无人机·图形渲染·着色器
gis分享者14 天前
学习threejs,使用自定义GLSL 着色器,实现抽象艺术特效
threejs·着色器·glsl·shadermaterial·抽象艺术
熊猫悟道17 天前
Unity shader 之,Shader内部时间离散处理
unity·游戏引擎·材质·着色器
流星魂小七2 个月前
颜色选择器
android·着色器·环形颜色选择器·圆形颜色选择器·colorpicker·colorwheelview
da_vinci_x2 个月前
在Substance Designer里“预演”你的游戏着色器(Shader)
人工智能·游戏·技术美术·着色器·游戏策划·游戏美术·substance designer