【Shader笔记3】基础光照-逐顶点高光反射和逐像素高光反射

本文详细介绍了Unity Shader中实现高光反射的两种方法:逐顶点高光反射和逐像素高光反射,并对比了Blinn和Blinn-Phong光照模型的差异。通过对Shader代码的解析,展示了如何利用UnityCG.cginc和Lighting.cginc中的函数来优化高光效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.逐顶点高光反射

在原来漫反射的基础上增加了高光,以及加入两个参数调节高光的范围以及颜色
PS: reflect(I, N)
根据入射光方向向量 I,和顶点法向量N,计算反射光方向向量。其中I和N 必须被归一化,需要非常注意的是,这个I 是指向顶点的;函数只对三元向量有效。


Shader "Custom/vertex specular"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		//通过参数调整高光的范围和颜色
		_Gloss("Gloss ",Range(0,20))=5
		_Color("Color", COLOR )=(1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "LightMode"="ForwardBase" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

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

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
				float3 normal:NORMAL;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
				fixed3 color:COLOR;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

			//为什么要用half:关于一些性能上的考虑,尽量使用低精度的浮点数
			//浮点数精度相关:fixed<half<float
			half _Gloss;
			fixed4 _Color;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                //o.uv = TRANSFORM_TEX(v.uv, _MainTex);

				//环境光的颜色
				fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;
				//模型空间转换到世界空间
				fixed3 normalDir=normalize( mul(unity_ObjectToWorld,v.normal));
				//取到世界空间下平行光的位置
				fixed3 lightDir=normalize(_WorldSpaceLightPos0.xyz);
				//漫反射  ; _LightColor0.rgb:取得第一个平行光的颜色
				fixed3 diffuse=_LightColor0.rgb * max(0,dot(normalDir,lightDir));


				//反射光的方向
				fixed3 reflectDir = reflect (-lightDir,normalDir);

				//相机的位置减去顶点的位置,顶点要先从模型空间转换到世界空间
				fixed3 viewDir = normalize ( _WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld,v.vertex).xyz ) ;
				
				//高光
				fixed3 specular =_LightColor0.rgb * pow ( max ( 0,dot( reflectDir,viewDir ))  ,_Gloss ) * _Color;

				o.color=diffuse + ambient + specular ;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				 return fixed4(i.color,1);
            }
            ENDCG
        }
    }
}


二. 逐像素高光反射

Shader "Custom/fragment specular"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		//通过参数调整高光的范围和颜色
		_Gloss("Gloss ",Range(0,20))=5
		_Color("Color", COLOR )=(1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "LightMode"="ForwardBase" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

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

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;

				float3 normal:NORMAL;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;

				fixed3 color:COLOR;
				//其实TEXCOORD0也可以存储法线向量。。
				//不能有相同的纹理坐标
				float3 worldNormalDir:TEXCOORD1;
				float3 worldVertex:TEXCOORD2;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

			//为什么要用half:关于一些性能上的考虑,尽量使用低精度的浮点数
			//浮点数精度相关:fixed<half<float
			half _Gloss;
			fixed4 _Color;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                //o.uv = TRANSFORM_TEX(v.uv, _MainTex);

				o.worldNormalDir=normalize( mul(unity_ObjectToWorld,v.normal));
				o.worldVertex=mul(unity_ObjectToWorld,v.vertex).xyz;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
			
				fixed3 normalDir=normalize(i.worldNormalDir);
				//环境光的颜色
				fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;
				//取到世界空间下平行光的位置
				fixed3 lightDir=normalize(_WorldSpaceLightPos0.xyz);
				//漫反射  ; _LightColor0.rgb:取得第一个平行光的颜色
				fixed3 diffuse=_LightColor0.rgb * max(0,dot(normalDir,lightDir));

				//反射光的方向
				fixed3 reflectDir = reflect (-lightDir,normalDir);

				//相机的位置减去顶点的位置,顶点要先从模型空间转换到世界空间
				fixed3 viewDir = normalize ( _WorldSpaceCameraPos.xyz - i.worldVertex) ;
				
				//高光
				fixed3 specular =_LightColor0.rgb * pow ( max ( 0,dot( reflectDir,viewDir ))  ,_Gloss ) * _Color;

				fixed3 tempColor=diffuse=diffuse + ambient + specular ;

				 return fixed4(tempColor,1);
            }
            ENDCG
        }
    }
}


************Blinn光照模型和Blinn-Phong 光照模型 ************
Blinn光照模型:Specular =平行光 * pow ( max ( 0 , cosθ) , 参数x )
Blinn-Phong光照模型:Specular =平行光 * pow ( max ( 0 , cosθ) , 参数x )
(θ为平行光与视野方向夹角的平分线与法线的夹角)

代码修改:

fixed3 reflectDir = reflect (-lightDir,normalDir);
fixed3 specular =_LightColor0.rgb * pow ( max ( 0,dot( reflectDir,viewDir ))  ,_Gloss ) * _Color;

//获得平分线的向量
fixed3 halfDir = normalize( lightDir + viewDir );
fixed3 specular =_LightColor0.rgb * pow ( max ( 0,dot( normalDir,halfDir ))  ,_Gloss ) * _Color;

区别:Blinn-Phong 的高光范围比Blinn的大点
在这里插入图片描述
三.使用UnityCG.cgnic中一些常用的函数修改后的代码

Shader "Custom/Gai_fragment sprcular"
{
	Properties
	{
		_Diffuse("Diffuse Color",Color)=(1,1,1,1)
		_Specular("Specular Color",Color)=(1,1,1,1)
		_Gloss("Gloss",Range(1,50))=20
	}

	SubShader
	{
		Pass
		{
			Tags{"LightMode"="ForwardBase"}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

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

			fixed4 _Diffuse;
			fixed4 _Specular;
			half _Gloss;

			struct a2v
			{
				float4 vertex:POSITION;  //取得顶点位置
				float3 normal:NORMAL;
				
			};
			struct v2f
			{
				float4 svPos:SV_POSITION;  //剪裁空间下的顶点坐标
				float3 worldNormal:TEXCOORD0;
				float4 worldVertex:TEXCOORD1; //世界空间下的顶点坐标
			};

			v2f vert(a2v v)
			{
				v2f f;
				f.svPos=UnityObjectToClipPos(v.vertex);
				f.worldNormal=UnityObjectToWorldNormal(v.normal); 
//法线从模型空间=》世界空间
				f.worldVertex=mul(unity_ObjectToWorld,v.vertex); 
//顶点坐标从模型空间=》世界空间
				return f;

			}

			fixed4 frag(v2f f):SV_TARGET
			{
				fixed3 normalDir=normalize(f.worldNormal); //法线向量
				fixed3 lightDir=normalize(WorldSpaceLightDir(f.worldVertex));
 //光线向量
				fixed3 viewDir=normalize(UnityWorldSpaceViewDir(f.worldVertex));
 //视野方向
				fixed3 halfDir=normalize(lightDir + viewDir); //平分向量

				fixed3 diffuse=_LightColor0.rgb * _Diffuse.rgb * max(0,dot(lightDir ,normalDir)); //漫反射
				fixed3 specular=_LightColor0.rgb * _Specular.rgb * pow ( max(0,dot(normalDir,halfDir) ),_Gloss); //高光反射
				

				fixed3 tempcolor=diffuse+specular+UNITY_LIGHTMODEL_AMBIENT.rgb; //UNITY_LIGHTMODEL_AMBIENT.rgb环境光颜色
				return fixed4(tempcolor,1);

			}

			ENDCG
		}
	}

	FallBack"SPECULAR"
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值