Article
Unity着色器训练营(3) -基于图片的光照着色器（下）
Published 2 years ago
975
0

Unity 着色器训练营（1）：着色器入门
Unity 着色器训练营（2）： MVP转换和法线贴图
Unity 着色器训练营（3）： 替换着色器方法(上)

``````Shader "Shader Course/03/IBL/Start"
{
Properties
{
_MainTex("Albedo Texture", 2D) = "white" {}
[NoScaleOffset]
_NormalTex("Normal Texture", 2D) = "bump" {}
}

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

CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

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

struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float3 wNormal : TEXCOORD1;
float3 wTangent : TEXCOORD2;
float3 wBitangent : TEXCOORD3;
};

sampler2D _MainTex;
half4 _MainTex_ST;
sampler2D _NormalTex;

v2f vert(appdata v)
{
v2f o;

o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.wNormal = UnityObjectToWorldNormal(v.normal);
o.wTangent = UnityObjectToWorldNormal(v.tangent.xyz);
o.wBitangent = cross(o.wNormal, o.wTangent) * v.tangent.w *
unity_WorldTransformParams.w;

return o;
}

fixed4 frag(v2f i) : SV_Target
{
half3 albedoColor = tex2D(_MainTex, i.uv);
half3 normalTex = tex2D(_NormalTex, i.uv) * 2 - 1;

half3 N = normalize(i.wTangent * normalTex.r +
i.wBitangent * normalTex.g + i.wNormal * normalTex.b);

half4 color = 0;
color.rgb = albedoColor;

return color;
}
ENDCG
}
}
}``````

``````Shader "Shader Course/03/IBL/Diffuse"
{
Properties
{
_MainTex("Albedo Texture", 2D) = "white" {}
[NoScaleOffset]
_NormalTex("Normal Texture", 2D) = "bump" {}
_IBLTexCube("IBL Cubemap", Cube) = "black" {}
}

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

CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

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

struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
half3 wNormal : TEXCOORD1;
half3 wTangent : TEXCOORD2;
half3 wBitangent : TEXCOORD3;
};

sampler2D _MainTex;
half4 _MainTex_ST;
sampler2D _NormalTex;
samplerCUBE _IBLTexCube;

v2f vert(appdata v)
{
v2f o;

o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.wNormal = UnityObjectToWorldNormal(v.normal);
o.wTangent = UnityObjectToWorldNormal(v.tangent.xyz);
o.wBitangent = cross(o.wNormal, o.wTangent) *
v.tangent.w * unity_WorldTransformParams.w;

return o;
}

#define DIFFUSE_MIP_LEVEL 5

half3 SampleTexCube(samplerCUBE cube, half3 normal, half mip)
{
return texCUBElod(cube, half4(normal, mip));
}

fixed4 frag(v2f i) : SV_Target
{
half3 albedoColor = tex2D(_MainTex, i.uv);
half3 normalTex = tex2D(_NormalTex, i.uv) * 2 - 1;

half3 N = normalize(i.wTangent * normalTex.r +
i.wBitangent * normalTex.g + i.wNormal * normalTex.b);

half3 indirectDiffuse = SampleTexCube(_IBLTexCube, N, DIFFUSE_MIP_LEVEL);
half3 diffuse = albedoColor * indirectDiffuse;

half4 color = 0;
color.rgb = diffuse;

return color;
}
ENDCG
}
}
}``````

``````Shader "Shader Course/03/IBL/Full"
{
Properties
{
_MainTex("Albedo Texture", 2D) = "white" {}
[NoScaleOffset]
_NormalTex("Normal Texture", 2D) = "bump" {}
[NoScaleOffset]
_IBLTexCube("IBL Cubemap", Cube) = "black" {}
_Gloss("Gloss", Range(0, 1)) = 0.5
_Reflectivity("Reflectivity", Range(0, 1)) = 0.5
}

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

CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

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

struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float3 wNormal : TEXCOORD1;
float3 wTangent : TEXCOORD2;
float3 wBitangent : TEXCOORD3;
float3 eyeVec : TEXCOORD4;
};

sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _NormalTex;
samplerCUBE _IBLTexCube;

float _Gloss;
float _Reflectivity;

v2f vert(appdata v)
{
v2f o;

o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.wNormal = UnityObjectToWorldNormal(v.normal);
o.wTangent = UnityObjectToWorldNormal(v.tangent.xyz);
o.wBitangent = cross(o.wNormal, o.wTangent) *
v.tangent.w * unity_WorldTransformParams.w;

float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.eyeVec = normalize(worldPos - _WorldSpaceCameraPos);

return o;
}

#define DIFFUSE_MIP_LEVEL 5
#define GLOSSY_MIP_COUNT 6

half3 SampleTexCube(samplerCUBE cube, half3 normal, half mip)
{
return texCUBElod(cube, half4(normal, mip));
}

fixed4 frag(v2f i) : SV_Target
{
half3 mainTex = tex2D(_MainTex, i.uv);
half3 normalTex = tex2D(_NormalTex, i.uv) * 2 - 1;

half oneMinusReflectivity = 1 - _Reflectivity;
half roughness = 1 - _Gloss;
half3 N = normalize(i.wTangent * normalTex.r +
i.wBitangent * normalTex.g + i.wNormal * normalTex.b);
half3 eyeVec = normalize(i.eyeVec);
half3 R = reflect(eyeVec, N);

half3 albedoColor = lerp(0, mainTex.rgb, oneMinusReflectivity);

half3 directDiffuse = saturate(dot(N, _WorldSpaceLightPos0));
half3 indirectDiffuse = SampleTexCube(_IBLTexCube, N, DIFFUSE_MIP_LEVEL);
half3 diffuse = albedoColor * (directDiffuse + indirectDiffuse);

half3 indirectSpecular = SampleTexCube(_IBLTexCube, R,
roughness * GLOSSY_MIP_COUNT) * _Reflectivity;

half4 color = 0;
color.rgb = diffuse + indirectSpecular;

return color;
}
ENDCG
}
}
}``````

``````float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.eyeVec = normalize(worldPos - _WorldSpaceCameraPos);``````

``half3 indirectSpecular = SampleTexCube(_IBLTexCube, R, roughness * GLOSSY_MIP_COUNT) * _Reflectivity; ``

``````half oneMinusReflectivity = 1 - _Reflectivity;
…
half3 albedoColor = lerp(0, mainTex.rgb, oneMinusReflectivity); ``````
albedoColor 通过1减反射率的值作为权重，线性差值计算主纹理的颜色，反射率越高，物体越明亮，主纹理颜色越不明显；反射率越低，物体越暗淡，主纹理颜色越明显。越是明亮，物体的金属质感也越明显。
``color.rgb = diffuse + indirectSpecular;``

IBL基于图片光照着色器的内容就介绍这里，Unity着色器训练营第三期的技术内容也暂告一段落。该项目中的资源整理后，会与第一期第二期的资源一同分享给各位开发者。当然我们的Unity着色器训练营还会继续，请大家关注我们Unity的官方微信发布的直播信息，敬请期待！更多精彩内容尽在Unity Connect平台!
Unity China
677