Unity3d Shader篇(四)— Phong顶点高光反射着色器

文章目录

  • 前言
  • 一、Phong顶点高光反射着色器是什么?
    • [1. Phong顶点高光反射着色器的工作原理](#1. Phong顶点高光反射着色器的工作原理)
    • [2. Phong顶点高光反射着色器的优缺点](#2. Phong顶点高光反射着色器的优缺点)
  • 二、使用步骤
    • [1. Shader 属性定义](#1. Shader 属性定义)
    • [2. SubShader 设置](#2. SubShader 设置)
    • [3. 渲染 Pass](#3. 渲染 Pass)
    • [4. 定义结构体和顶点着色器函数](#4. 定义结构体和顶点着色器函数)
    • [5. 片元着色器函数](#5. 片元着色器函数)
  • 三、效果
  • 四、总结

前言

在 Unity 中,Shader 可以用来实现各种视觉效果。本教程将详细介绍如何编写一个基于Phong顶点高光反射着色器,使物体的颜色根据光照和法线方向的变化而变化。


一、Phong顶点高光反射着色器是什么?

1. Phong顶点高光反射着色器的工作原理

Phong 顶点高光反射着色器是一种基于 Phong 光照模型的着色器,它可以模拟物体表面的漫反射、环境光和高光效果。Phong 光照模型是一种经验性的局部光照模型,它描述了物体表面反射光的方式,是一种常用的光照模拟方法。

Phong 顶点高光反射着色器的主要特点是,它在顶点着色器中计算光照颜色,然后在片段着色器中插值输出颜色。这样做的好处是,可以减少片段着色器的计算量,提高性能。但是,这样做的缺点是,会导致光照效果不够精细,尤其是在物体表面有弯曲或者高光区域时,会出现明显的锯齿或者平面化的现象

2. Phong顶点高光反射着色器的优缺点

优点

它可以模拟物体表面的漫反射、环境光和高光效果,使物体看起来更加真实和立体。

它在顶点着色器中计算光照颜色,减少了片段着色器的计算量,提高了性能和效率。

它是一种基础的着色器,易于理解和实现,适合学习和入门。

缺点

它会导致光照效果不够精细,尤其是在物体表面有弯曲或者高光区域时,会出现明显的锯齿或者平面化的现象。

它不能处理复杂的光照情况,例如多光源、阴影、透明度、反射、折射等,需要使用更高级的着色器来实现。

二、使用步骤

1. Shader 属性定义

c 复制代码
// 定义属性
Properties
{
    _Diffuse("Diffuse",Color)=(1,1,1,1) // 漫反射颜色属性,默认白色
    _Specular("Specular",Color)=(1,1,1,1) // 高光颜色性,默认白色
    _Gloss("Gloss",Range(1,256))=5// 高光反射系数
}

这段代码定义了Shader的属性,其中:

_Diffuse: 表示漫反射颜色属性,使用RGBA格式表示颜色,默认为白色 (1, 1, 1, 1)。

_Specular: 表示高光颜色属性,同样使用RGBA格式表示颜色,默认为白色 (1, 1, 1, 1)。

_Gloss: 表示高光反射系数属性,使用Range声明范围为1到256,默认值为5。

2. SubShader 设置

c 复制代码
SubShader
{
    Tags
    {
        "RenderType" = "Opaque" // 渲染类型为不透明
    }
    
    LOD 100 // 细节级别
}

SubShader 定义了一组渲染设置,包括标签和细节级别。在这里,我们将渲染类型标签设置为 "Opaque",表示物体是不透明的。

3. 渲染 Pass

c 复制代码
Pass
{
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag

    #include "UnityCG.cginc"
    #include "Lighting.cginc"
}

这里开始了渲染 Pass 部分。在这里,我们使用了 CGPROGRAM 指令来声明顶点着色器和片元着色器函数。#pragma vertex vert 和 #pragma fragment frag 分别指定了顶点着色器函数和片元着色器函数的名称。

然后,我们包含了 UnityCG.cginc 和 Lighting.cginc,它们提供了许多有用的函数和宏,用于简化编写 Shader。

4. 定义结构体和顶点着色器函数

c 复制代码
// 定义结构体:从顶点到片段的数据传递
struct v2f
{
    float4 vertex:SV_POSITION; // 顶点位置
    fixed3 color:COLOR; // 颜色
};

// 顶点着色器函数
v2f vert(appdata_base v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex); // 顶点位置变换到裁剪空间

    //unity_ObjectToWorld 是一个变换矩阵,用于将顶点从对象空间变换到世界空间。
    //v.vertex 是顶点的位置信息。
    //mul() 函数表示矩阵相乘操作,这里将对象空间中的顶点位置矩阵与对象到世界的变换矩阵相乘,得到世界空间中的顶点位置。
    fixed3 worldPos=mul(unity_ObjectToWorld,v.vertex);
    
    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; //获取环境光
    fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); // 世界空间法线
    //漫反射计算
    //光源位置
    //fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); 
    //光源位置简化
    fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(worldPos)); 
    fixed3 diffuse = _LightColor0 * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir)); // 漫反射颜色计算


    //高光反射计算
    // 计算反射方向
    fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
    // 计算视线方向
    //fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - UnityObjectToWorldDir(v.vertex));
    //计算视线方向简化版本
    fixed3 viewDir=normalize(UnityWorldSpaceViewDir(worldPos));
    
    // 计算高光颜色
    fixed3 specular = _LightColor0 * _Specular * pow(max(0, dot(reflectDir, viewDir)), _Gloss);

    o.color = diffuse + ambient + specular; // 输出颜色
    return o;
}

顶点着色器的输入是一个结构体 appdata_base ,它包含了顶点的位置和法线信息。顶点着色器的输出是一个结构体 v2f ,它包含了顶点的裁剪空间位置和光照颜色信息。

顶点着色器的主要逻辑是:

  1. 使用 UnityObjectToClipPos 函数,将顶点的位置从对象空间变换到裁剪空间,这是渲染管线的必要步骤。
  2. 使用 unity_ObjectToWorld 矩阵,将顶点的位置从对象空间变换到世界空间,这是为了计算光照效果所需的坐标系。
  3. 使用 UNITY_LIGHTMODEL_AMBIENT 宏,获取环境光的颜色,这是 Phong 光照模型的第一个分量。
  4. 使用 UnityObjectToWorldNormal 函数,将顶点的法线从对象空间变换到世界空间,这是为了计算光照效果所需的方向向量。
  5. 使用 UnityWorldSpaceLightDir 函数,获取光源的方向向量,这是为了计算漫反射和高光效果所需的角度。
  6. 使用 _LightColor0 和 _Diffuse 变量,获取光源的颜色和物体的漫反射颜色,然后使用 max 和 dot 函数,计算光源和法线的夹角的余弦值,这是 Phong 光照模型的第二个分量。
  7. 使用 reflect 函数,计算光源的反射方向向量,这是为了计算高光效果所需的角度。
    然后,使用 UnityWorldSpaceViewDir 函数,获取视线的方向向量,这是为了计算高光效果所需的角度。
  8. 使用 _LightColor0 和 _Specular 变量,获取光源的颜色和物体的高光颜色,然后使用 max 和 dot 函数,计算反射方向和视线方向的夹角的余弦值,然后使用 pow 函数,计算高光的强度,这是 Phong 光照模型的第三个分量。
  9. 将环境光、漫反射和高光的颜色相加,得到最终的光照颜色,作为顶点着色器的输出。

5. 片元着色器函数

c 复制代码
// 片段着色器函数
fixed4 frag(v2f i) : SV_Target
{
    return fixed4(i.color, 1); // 输出颜色
}

片段着色器的输入是一个结构体 v2f ,它包含了顶点的裁剪空间位置和光照颜色信息。片段着色器的输出是一个 fixed4 类型的颜色值,它表示了片段的颜色。

片段着色器的主要逻辑是:

  1. 使用 fixed4 构造函数,将光照颜色转换为颜色值,同时设置透明度为 1 。
  2. 直接返回颜色值,作为片段着色器的输出。

三、效果

左:普通材质 右:Phong顶点高光反射着色器(_Diffuse设置成了红色)

四、总结

Phong 顶点高光反射着色器是一种基于 Phong 光照模型的着色器,它可以模拟物体表面的漫反射、环境光和高光效果。它的主要特点是,在顶点着色器中计算光照颜色,然后在片段着色器中插值输出颜色。这样做的好处是,可以减少片段着色器的计算量,提高性能。但是,这样做的缺点是,会导致光照效果不够精细,尤其是在物体表面有弯曲或者高光区域时,会出现明显的锯齿或者平面化的现象。Phong 顶点高光反射着色器的应用场景主要是,当需要模拟物体表面的光照效果,但又不需要太高的精度和细节时,可以使用这种着色器。Phong 顶点高光反射着色器也可以作为一种基础的着色器,用于学习和理解 Phong 光照模型的原理和实现,以及顶点着色器和片段着色器的区别和作用。

相关推荐
暴走约伯1 小时前
【VFX工具链源码拆解 09】终极工业化闭环:基于 ID 规则驱动的全自动场景建档、骨骼挂载与男转女场景迁移
unity·c#·游戏引擎·材质
Martina_032121 小时前
AI生成的3D白模单帧没问题,镜头一移动就被挡?用6步检查遮挡与构图
图像处理·人工智能·数学建模·3d·ai·自然语言处理·游戏策划
寂寞的船1 天前
【Unity知识速递】第13期 Unity 内存泄漏排查实战:从 Memory Profiler 到 Lua 引用泄漏的生产级全链路诊断
unity·junit·c#·游戏引擎·lua
寂寞的船2 天前
【Unity Bug挑战】第12期 Awaitable 二次 await 死锁之谜 —— 为什么同一个异步操作等两次就卡死?
unity·c#·游戏引擎·bug
探求虚无3 天前
用 AI 在 Unity 里做一款 RTS:最难的不是生成代码,而是证明它真的能玩
人工智能·unity·游戏引擎
时间的情敌3 天前
Cesium 建筑单体化、3DTiles 分类、楼层显隐、分户高亮(BIM + 倾斜孪生高频)
前端·3d·cesium
总要学点什么4 天前
第96篇:三维数据加载-城市建筑白模样式+着色器——让色带按体量上色,最白的那档却涂不上去
前端·gis·webgl·cesium·着色器·空间分析·白模
17岁的勇气4 天前
Unity Shader unity文档学习笔记(二十二):shader变体
笔记·学习·unity
加搜科技观察4 天前
哪个品牌 3D 相机好用?工业 3D 相机品牌选型评估指南
数码相机·3d
寂寞的船5 天前
【Unity知识速递】第10期 Unity GC 零分配实战:从 UnityEngine.Pool 到手动 GC 控制的全链路优化
jvm·unity·c#·游戏引擎·lucene