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 光照模型的原理和实现,以及顶点着色器和片段着色器的区别和作用。

相关推荐
Forest_10101 小时前
GLSL(OpenGL 着色器语言)基础语法
着色器
牙膏上的小苏打233316 小时前
Unity Surround开关后导致获取主显示器分辨率错误
unity·主屏幕
Unity大海18 小时前
诠视科技Unity SDK开发环境配置、项目设置、apk打包。
科技·unity·游戏引擎
huoyingcg1 天前
3D Mapping秀制作:沉浸式光影盛宴 3D mapping show
科技·3d·动画·虚拟现实
浅陌sss1 天前
Unity中 粒子系统使用整理(一)
unity·游戏引擎
维度攻城狮1 天前
实现在Unity3D中仿真汽车,而且还能使用ros2控制
python·unity·docker·汽车·ros2·rviz2
为你写首诗ge1 天前
【Unity网络编程知识】FTP学习
网络·unity
神码编程1 天前
【Unity】 HTFramework框架(六十四)SaveDataRuntime运行时保存组件参数、预制体
unity·编辑器·游戏引擎
菲fay1 天前
Unity 单例模式写法
unity·单例模式
火一线1 天前
【Framework-Client系列】UIGenerate介绍
游戏·unity