此页提供了表面着色器中自定义 表面着色器光照模型 的示例。 表面着色器一种简化编写用于内置渲染管线着色器的方式。更多信息
在 术语 中查看. 对于更一般的表面 着色器在GPU上运行的程序。更多信息
在 术语 中查看 指引,请参阅 表面着色器示例。
由于 延迟着色在内置渲染管线中的一种渲染路径,它不对受一个游戏对象影响的灯光数量施加限制。所有灯光都按像素进行评估,意味着它们都能与法线贴图等正确地相互作用。此外,所有灯光都可以有cookie和阴影。《a class="tooltipMoreInfoLink" href="RenderTech-DeferredShading.html">更多信息
在 术语 中查看 与自定义每材料光照模型配合不佳,以下大多数示例都将着色器编译到 前向渲染一种渲染路径,它根据受对象影响的灯光数量在一次性或多次通过中渲染每个对象。前向渲染也会根据设置和强度以不同的方式处理灯光。更多信息
在 术语 中查看。
特性名称 | 内置 渲染管线一系列操作,它将场景的内容显示在屏幕上。Unity 允许您从预构建的渲染管线中选择,或编写自己的渲染管线。更多信息 在 术语 中查看 |
通用渲染管线(URP) | 高清晰度渲染管线(HDRP) | 自定义SRP |
---|---|---|---|---|
表面着色器 | 是 | 否 要在URP中创建着色器对象,请参阅 着色器图。 |
否 要在HDRP中创建着色器对象,请参阅 着色器图。 |
否 |
下面是一个使用内置Lambert光照模型的着色器示例
Shader "Example/Diffuse Texture" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
以下是使用纹理和未使用纹理的场景中一个方向灯光的样子
以下示例展示了通过编写自定义光照模型而不是使用内置Lambert模型实现相同结果的方式
为此,您需要使用多个表面着色器光照模型函数。以下是一个简单的Lambert示例。注意,只有 CGPROGRAM
部分有变化;周围的着色器代码完全相同
Shader "Example/Diffuse Texture" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf SimpleLambert
half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten);
c.a = s.Alpha;
return c;
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffuse"
}
本简单的漫反射光照模型使用 LightingSimpleLambert
函数。它的计算方法是计算表面法线与光方向之间的点积,然后应用光照衰减和颜色。
以下示例展示了 包裹漫反射,它是漫反射光的修改版本,其中光照“包裹”了物体的边缘。这对于模拟次表面散射效果很有用。只有 CGPROGRAM
部分有所变化,所以 Again,省略了周围的着色器代码
...ShaderLab code...
CGPROGRAM
#pragma surface surf WrapLambert
half4 LightingWrapLambert (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half diff = NdotL * 0.5 + 0.5;
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten);
c.a = s.Alpha;
return c;
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
...ShaderLab code...
以下是带有纹理和无纹理的样例,场景中有一个方向性光源
以下示例展示了一种使用纹理渐变来定义表面如何响应光线与法线之间角度的“渐变”光照模型。这可以用于多种效果,与 卡通 照明结合使用特别有效。
...ShaderLab code...
CGPROGRAM
#pragma surface surf Ramp
sampler2D _Ramp;
half4 LightingRamp (SurfaceOutput s, half3 lightDir, half atten) {
half NdotL = dot (s.Normal, lightDir);
half diff = NdotL * 0.5 + 0.5;
half3 ramp = tex2D (_Ramp, float2(diff)).rgb;
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * ramp * atten;
c.a = s.Alpha;
return c;
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
...ShaderLab code...
以下是带有纹理和无纹理的样例,场景中有一个方向性光源
以下示例展示了一种简单镜面反射光照模型,类似于内置的 BlinnPhong 照明模型。
...ShaderLab code...
CGPROGRAM
#pragma surface surf SimpleSpecular
half4 LightingSimpleSpecular (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
half3 h = normalize (lightDir + viewDir);
half diff = max (0, dot (s.Normal, lightDir));
float nh = max (0, dot (s.Normal, h));
float spec = pow (nh, 48.0);
half4 c;
c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * atten;
c.a = s.Alpha;
return c;
}
struct Input {
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
...ShaderLab code...
以下是带有纹理和无纹理的样例,场景中有一个方向性光源
我们将从一个模仿 Unity 内置 GI 的着色器开始
Shader "Example/CustomGI_ToneMapped" {
Properties {
_MainTex ("Albedo (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
CGPROGRAM
#pragma surface surf StandardDefaultGI
#include "UnityPBSLighting.cginc"
sampler2D _MainTex;
inline half4 LightingStandardDefaultGI(SurfaceOutputStandard s, half3 viewDir, UnityGI gi)
{
return LightingStandard(s, viewDir, gi);
}
inline void LightingStandardDefaultGI_GI(
SurfaceOutputStandard s,
UnityGIInput data,
inout UnityGI gi)
{
LightingStandard_GI(s, data, gi);
}
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutputStandard o) {
o.Albedo = tex2D(_MainTex, IN.uv_MainTex);
}
ENDCG
}
FallBack "Diffuse"
}
现在,让我们在 GI 上添加一些色调映射
Shader "Example/CustomGI_ToneMapped" {
Properties {
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Gain("Lightmap tone-mapping Gain", Float) = 1
_Knee("Lightmap tone-mapping Knee", Float) = 0.5
_Compress("Lightmap tone-mapping Compress", Float) = 0.33
}
SubShader {
Tags { "RenderType"="Opaque" }
CGPROGRAM
#pragma surface surf StandardToneMappedGI
#include "UnityPBSLighting.cginc"
half _Gain;
half _Knee;
half _Compress;
sampler2D _MainTex;
inline half3 TonemapLight(half3 i) {
i *= _Gain;
return (i > _Knee) ? (((i - _Knee)*_Compress) + _Knee) : i;
}
inline half4 LightingStandardToneMappedGI(SurfaceOutputStandard s, half3 viewDir, UnityGI gi)
{
return LightingStandard(s, viewDir, gi);
}
inline void LightingStandardToneMappedGI_GI(
SurfaceOutputStandard s,
UnityGIInput data,
inout UnityGI gi)
{
LightingStandard_GI(s, data, gi);
gi.light.color = TonemapLight(gi.light.color);
#ifdef DIRLIGHTMAP_SEPARATE
#ifdef LIGHTMAP_ON
gi.light2.color = TonemapLight(gi.light2.color);
#endif
#ifdef DYNAMICLIGHTMAP_ON
gi.light3.color = TonemapLight(gi.light3.color);
#endif
#endif
gi.indirect.diffuse = TonemapLight(gi.indirect.diffuse);
gi.indirect.specular = TonemapLight(gi.indirect.specular);
}
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutputStandard o) {
o.Albedo = tex2D(_MainTex, IN.uv_MainTex);
}
ENDCG
}
FallBack "Diffuse"
}