На этой странице представлены примеры пользовательских моделей освещения шейдеров поверхности в Шейдеры поверхностиУпрощенный способ написания шейдеров для встроенного конвейера рендеринга. Подробнее
См. в Словарь. Для получения более общей информации Surface ShaderПрограмма, работающая на графическом процессоре. Подробнее
См. в Словарь, см. Примеры поверхностных шейдеров.
Поскольку Deferred Lighting плохо сочетается с некоторыми пользовательскими моделями освещения для каждого материала, в большинстве приведенных ниже примеров шейдеры компилируются в Forward RenderingПуть рендеринга, при котором каждый объект визуализируется за один или несколько проходов, в зависимости от освещения, воздействующего на объект. Сами источники света также обрабатываются Forward Rendering по-разному, в зависимости от их настроек и интенсивности. Подробнее
См. только в Словарь.
Совместимость конвейера рендеринга
Название функции | Встроенный конвейер рендеринга | Универсальный конвейер рендеринга (URP) | Конвейер рендеринга высокого разрешения (HDRP) | Пользовательский SRP |
---|---|---|---|---|
Surface Shaders | Да | No
Чтобы узнать об упрощенном способе создания объектов Shader в URP, см. раздел Shader Graph. |
No
Чтобы узнать об упрощенном способе создания объектов Shader в HDRP, см. раздел Shader Graph. |
Нет |
Рассеянный
Ниже приведен пример шейдера, использующего встроенную модель освещения Ламберта:
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"
}
Вот как это выглядит с Текстурой и без Текстуры, с одним направленным источником света в СценеСцена содержит среды и меню вашей игры. Думайте о каждом уникальном файле сцены как об уникальном уровне. В каждой сцене вы размещаете свое окружение, препятствия и декорации, по сути проектируя и создавая свою игру по частям. Подробнее
См. в Словарь:
В следующем примере показано, как добиться того же результата, написав собственную модель освещения вместо использования встроенной модели Ламберта.
Для этого необходимо использовать ряд функций модели освещения Surface Shader. Вот простой Ламберт. Обратите внимание, что изменяется только раздел 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
, поэтому окружающий код шейдера снова опускается:
...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...
Вот как это выглядит с текстурой и без текстуры, с одним направленным источником света в сцене:
Toon Ramp
В следующем примере показана модель освещения «Ramp», в которой используется линейное изменение текстуры для определения того, как поверхности реагируют на углы между источником света и нормалью. Это можно использовать для различных эффектов, особенно эффективно при использовании с освещением Toon.
...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...
Вот как это выглядит с текстурой и без текстуры, с одним направленным источником света в сцене:
Пользовательская ГУ
Мы начнем с шейдера, который имитирует встроенный GI Unity:
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"
}