Unity 的 Surface Shader有關記錄
Writing Surface Shaders
Writing shaders
that interact with lighting is complex. There are different light types, different shadow options, different rendering
paths (forward and deferred rendering), and the shader should somehow handle all that complexity.
Surface Shaders in Unity is a code generation approach that makes it much easier to write lit shaders than using low level vertex/pixel shader programs. Note that there are no custom languages, magic or ninjas involved in Surface Shaders; it just generates all the repetitive code that would have to be written by hand. You still write shader code in HLSL.
For some examples, take a look at Surface Shader Examples and Surface Shader Custom Lighting Examples.
How it works
You define a “surface function” that takes any UVs or data you need as input, and fills in output structure SurfaceOutput
. SurfaceOutput basically describes properties of the surface (it’s albedo color, normal, emission, specularity etc.). You write this code in HLSL.
Surface Shader compiler then figures out what inputs are needed, what outputs are filled and so on, and generates actual vertex&pixel shaders, as well as rendering passes to handle forward and deferred rendering.
Standard output structure of surface shaders is this:
struct SurfaceOutput
{
fixed3 Albedo; // diffuse color
fixed3 Normal; // tangent space normal, if written
fixed3 Emission;
half Specular; // specular power in 0..1 range
fixed Gloss; // specular intensity
fixed Alpha; // alpha for transparencies
};
In Unity 5, surface shaders can also use physically based lighting models. Built-in Standard and StandardSpecular lighting models (see below) use these output structures respectively:
struct SurfaceOutputStandard
{
fixed3 Albedo; // base (diffuse or specular) color
fixed3 Normal; // tangent space normal, if written
half3 Emission;
half Metallic; // 0=non-metal, 1=metal
half Smoothness; // 0=rough, 1=smooth
half Occlusion; // occlusion (default 1)
fixed Alpha; // alpha for transparencies
};
struct SurfaceOutputStandardSpecular
{
fixed3 Albedo; // diffuse color
fixed3 Specular; // specular color
fixed3 Normal; // tangent space normal, if written
half3 Emission;
half Smoothness; // 0=rough, 1=smooth
half Occlusion; // occlusion (default 1)
fixed Alpha; // alpha for transparencies
};
Samples
See Surface Shader Examples, Surface Shader Custom Lighting Examples and Surface Shader Tessellation pages.
Surface Shader compile directives
Surface shader is placed inside CGPROGRAM..ENDCG
block, just like any other shader. The differences are:
- It must be placed inside SubShader
block, not inside Pass. Surface shader will compile into multiple passes itself. - It uses
#pragma surface ...
directive to indicate it’s a surface shader.
The #pragma surface
directive is:
#pragma surface surfaceFunction lightModel [optionalparams]
Required parameters
surfaceFunction
- which Cg function has surface shader code. The function should have the form ofvoid surf (Input IN, inout SurfaceOutput o)
, where Input is a structure you have defined. Input should contain any texture coordinates and extra automatic variables needed by surface function.lightModel
- lighting model to use. Built-in ones are physically basedStandard
andStandardSpecular
, as well as simple non-physically basedLambert
(diffuse) andBlinnPhong
(specular). See Custom Lighting Models page for how to write your own.Standard
lighting model usesSurfaceOutputStandard
output struct, and matches the Standard (metallic workflow) shader in Unity.StandardSpecular
lighting model usesSurfaceOutputStandardSpecular
output struct, and matches the Standard (specular setup) shader in Unity.Lambert
andBlinnPhong
lighting models are not physically based (coming from Unity 4.x), but the shaders using them can be faster to render on low-end hardware.
Optional parameters
Transparency and alpha testing is controlled by alpha
and alphatest
directives. Transparency can typically be of two kinds: traditional alpha blending (used for fading objects out) or more physically plausible “premultiplied blending” (which allows semitransparent surfaces to retain proper specular reflections). Enabling semitransparency makes the generated surface shader code contain blending commands; whereas enabling alpha cutout will do a fragment discard in the generated pixel
shader, based on the given variable.
alpha
oralpha:auto
- Will pick fade-transparency (same asalpha:fade
) for simple lighting functions, and premultiplied transparency (same asalpha:premul
) for physically based lighting functions.alpha:blend
- Enable alpha blending.alpha:fade
- Enable traditional fade-transparency.alpha:premul
- Enable premultiplied alpha transparency.alphatest:VariableName
- Enable alpha cutout transparency. Cutoff value is in a float variable with VariableName. You’ll likely also want to useaddshadow
directive to generate proper shadow caster pass.keepalpha
- By default opaque surface shaders write 1.0 (white) into alpha channel, no matter what’s output in the Alpha of output struct or what’s returned by the lighting function. Using this option allows keeping lighting function’s alpha value even for opaque surface shaders.decal:add
- Additive decal shader (e.g. terrain AddPass). This is meant for objects that lie atop of other surfaces, and use additive blending. See Surface Shader Examplesdecal:blend
- Semitransparent decal shader. This is meant for objects that lie atop of other surfaces, and use alpha blending. See Surface Shader Examples
Custom modifier functions can be used to alter or compute incoming vertex data, or to alter final computed fragment color.
vertex:VertexFunction
- Custom vertex modification function. This function is invoked at start of generated vertex shader
, and can modify or compute per-vertex data. See Surface Shader Examples.finalcolor:ColorFunction
- Custom final color modification function. See Surface Shader Examples.finalgbuffer:ColorFunction
- Custom deferred path for altering gbuffer content.finalprepass:ColorFunction
- Custom prepass base path.
Shadows and Tessellation - additional directives can be given to control how shadows and tessellation is handled.
addshadow
- Generate a shadow caster pass. Commonly used with custom vertex modification, so that shadow casting also gets any procedural vertex animation. Often shaders don’t need any special shadows handling, as they can just use shadow caster pass from their fallback.fullforwardshadows
- Support all light shadow types in Forward rendering path
. By default shaders only support shadows from one directional light in forward rendering
(to save on internal shader variant count). If you need point or spot light shadows in forward rendering, use this directive.tessellate:TessFunction
- use DX11 GPU tessellation; the function computes tessellation factors. See Surface Shader Tessellation for details.
Code generation options - by default generated surface shader code tries to handle all possible lighting/shadowing/lightmap
scenarios. However in some cases you know you won’t need some of them, and it is possible to adjust generated code to skip them. This can result in smaller shaders that are faster to load.
exclude_path:deferred
,exclude_path:forward
,exclude_path:prepass
- Do not generate passes for given rendering path (Deferred Shading
, Forwardand Legacy Deferred respectively).noshadow
- Disables all shadow receiving support in this shader.noambient
- Do not apply any ambient lighting or light probes
.novertexlights
- Do not apply any light probes or per-vertex lights in Forward rendering.nolightmap
- Disables all lightmapping support in this shader.nodynlightmap
- Disables runtime dynamic global illumination
support in this shader.nodirlightmap
- Disables directional lightmaps support in this shader.nofog
- Disables all built-in Fog support.nometa
- Does not generate a “meta” pass (that’s used by lightmapping & dynamic global illumination to extract surface information).noforwardadd
- Disables Forward rendering additive pass. This makes the shader support one full directional light, with all other lights computed per-vertex/SH. Makes shaders smaller as well.nolppv
- Disables Light Probe Proxy Volume
support in this shader.noshadowmask
- Disables Shadowmask support for this shader (both Shadowmask
and Distance Shadowmask
).
Miscellaneous options
softvegetation
- Makes the surface shader only be rendered when Soft Vegetation is on.interpolateview
- Compute view direction in the vertex shader and interpolate it; instead of computing it in the pixel shader. This can make the pixel shader faster, but uses up one more texture interpolator.halfasview
- Pass half-direction vector into the lighting function instead of view-direction. Half-direction will be computed and normalized per vertex. This is faster, but not entirely correct.approxview
- Removed in Unity 5.0. Useinterpolateview
instead.dualforward
- Use dual lightmaps in forward rendering path.dithercrossfade
- Makes the surface shader support dithering effects. You can then apply this shader to GameObjects
that use an LOD Group
component configured for cross-fade transition mode.
To see what exactly is different from using different options above, it can be helpful to use “Show Generated Code” button in the Shader Inspector.
Surface Shader input structure
The input structure Input
generally has any texture coordinates needed by the shader. Texture coordinates must be named “uv
” followed by texture name (or start it with “uv2
” to use second texture coordinate set).
Additional values that can be put into Input structure:
float3 viewDir
- contains view direction, for computing Parallax effects, rim lighting etc.float4
withCOLOR
semantic - contains interpolated per-vertex color.float4 screenPos
- contains screen space position for reflection or screenspace effects. Note that this is not suitable for GrabPass; you need to compute custom UV yourself usingComputeGrabScreenPos
function.float3 worldPos
- contains world space position.float3 worldRefl
- contains world reflection vector if surface shader does not write to o.Normal. See Reflect-Diffuse shader for example.float3 worldNormal
- contains world normal vector if surface shader does not write to o.Normal.float3 worldRefl; INTERNAL_DATA
- contains world reflection vector if surface shader writes to o.Normal. To get the reflection vector based on per-pixel normal map
, useWorldReflectionVector (IN, o.Normal)
. See Reflect-Bumped shader for example.float3 worldNormal; INTERNAL_DATA
- contains world normal vector if surface shader writes to o.Normal. To get the normal vector based on per-pixel normal map, useWorldNormalVector (IN, o.Normal)
.
Surface Shaders and DirectX 11 HLSL syntax
Currently some parts of surface shader compilation pipeline do not understand DirectX 11-specific HLSL syntax, so if you’re using HLSL features like StructuredBuffers, RWTextures and other non-DX9 syntax, you have to wrap it into a DX11-only preprocessor macro.
See Platform Specific Differences and Shading Language pages for details.
Surface Shaders and rendering paths
In the Built-in Render Pipeline, when using a Surface Shader
, how lighting is applied and which Passes of the shader
are used depends on which rendering path
is used. Each pass in a shader communicates its lighting type via Pass Tags.
- In Forward Rendering
,ForwardBase
andForwardAdd
passes are used. - In Deferred Shading
,Deferred
pass is used. - In legacy Deferred Lighting,
PrepassBase
andPrepassFinal
passes are used. - In legacy Vertex Lit,
Vertex
,VertexLMRGBM
andVertexLM
passes are used. - In any of the above, to render Shadows
or a depth texture,ShadowCaster
pass is used.
Forward Rendering
path
ForwardBase
pass renders ambient, lightmaps
, main directional light and not important (vertex/SH) lights at once. ForwardAdd
pass is used for any additive per-pixel lights; one invocation per object illuminated by such light is done. See Forward Rendering for details.
If forward rendering is used, but a shader does not have forward-suitable passes (i.e. neither ForwardBase
nor ForwardAdd
pass types are present), then that object is rendered just like it would in Vertex Lit path, see below.
Deferred Shading path
Deferred
pass renders all information needed for lighting (in built-in shaders: diffuse color, specular color, smoothness, world space normal, emission). It also adds lightmaps, reflection probes and ambient lighting into the emission channel. See Deferred Shading for details.
Legacy Deferred Lighting path
PrepassBase
pass renders normals & specular exponent; PrepassFinal
pass renders final color by combining textures, lighting & emissive material properties. All regular in-scene lighting is done separately in screen-space. See Deferred Lighting for details.
Legacy Vertex Lit Rendering path
Since vertex lighting is most often used on platforms that do not support programmable shaders, Unity can’t create multiple shader variants internally to handle lightmapped vs. non-lightmapped cases. So to handle lightmapped and non-lightmapped objects, multiple passes have to be written explicitly.
Vertex
pass is used for non-lightmapped objects. All lights are rendered at once, using a fixed function OpenGL/Direct3D lighting model (Blinn-Phong)VertexLMRGBM
pass is used for lightmapped objects, when lightmaps are RGBM encoded (PC and consoles). No realtime lighting is applied; pass is expected to combine textures with a lightmap.VertexLM
pass is used for lightmapped objects, when lightmaps are double-LDR encoded (mobile platforms). No realtime lighting is applied; pass is expected to combine textures with a lightmap.
Custom lighting models in Surface Shaders
When writing Surface Shaders
, you describe the properties of a surface (such as albedo color and normal), and a Lighting Model computes the lighting interaction.
There are two built-in lighting models: Lambert
for diffuse lighting, and BlinnPhong
for specular lighting. The Lighting.cginc file inside Unity defines these models (Windows: <unity install path>/Data/CGIncludes/Lighting.cginc; macOS: /Applications/Unity/Unity.app/Contents/CGIncludes/Lighting.cginc).
Sometimes you might want to use a custom lighting model. You can do this with Surface Shaders
. A lighting model is simply a couple of Cg/HLSL functions that match some conventions.
Declaring lighting models
A lighting model consists of regular functions with names that begin Lighting
. You can declare them anywhere in your shader file, or one of the included files. The functions are:
-
half4 Lighting<Name> (SurfaceOutput s, UnityGI gi);
Use this in forward rendering
paths for light models that are not dependent on the view direction. -
half4 Lighting<Name> (SurfaceOutput s, half3 viewDir, UnityGI gi);
Use this in forward rendering
paths for light models that are dependent on the view direction. -
half4 Lighting<Name>_Deferred (SurfaceOutput s, UnityGI gi, out half4 outDiffuseOcclusion, out half4 outSpecSmoothness, out half4 outNormal);
Use this in deferred lighting paths. -
half4 Lighting<Name>_PrePass (SurfaceOutput s, half4 light);
Use this in light prepass (legacy deferred) lighting paths.
Note that you don’t need to declare all functions. A lighting model either uses view direction or it does not. Similarly, if the lighting model only works in forward rendering, do not declare the _Deferred
or _Prepass
function. This ensures that Shaders that use it only compile to forward rendering.
Custom GI
Declare the following function to customize the decoding lightmap
data and probes:
half4 Lighting<Name>_GI (SurfaceOutput s, UnityGIInput data, inout UnityGI gi);
Note that to decode standard Unity lightmaps and SH probes, you can use the built-in DecodeLightmap
and ShadeSHPerPixel
functions, as seen in UnityGI_Base
in the UnityGlobalIllumination.cginc file inside Unity (Windows: <unity install path>/Data/CGIncludes/UnityGlobalIllumination.cginc; macOS: /Applications/Unity/Unity.app/Contents/CGIncludes/UnityGlobalIllumination.cginc_).
Examples
See documentation on Surface Shader Lighting Examples for more information.
相關文章
- Unity Shader 00 - 梳理 Unity Shader 的基本結構Unity
- Unity Shader 入門精要 筆記(1)Unity筆記
- Unity3D學習筆記3——Unity Shader的初步使用Unity3D筆記
- Blender Shader Node簡單記錄
- 有關Editor的記錄(一)
- unity 統一替換shaderUnity
- unity shader 溶解,上下左右,cutoffUnity
- Unity&Shader常用函式的使用方法Unity函式
- Unity Shader 實現雨天的水面漣漪效果Unity
- Unity3D 透明物體ShaderUnity3D
- Unity的Shader學習筆記(09)[20/12/24_週四][33-36]Unity筆記
- Unity Shader基於視差對映的雲海效果Unity
- Unity Shader-後處理:Bloom全屏泛光UnityOOM
- Unity Shader 基於光照圖的簡易晝夜變化Unity
- 《Unity Shader入門精要》自學筆記(五)第八章 透明效果Unity筆記
- Unity Shader之磨砂玻璃與水霧玻璃效果Unity
- Unity Shader之雙面材質和多Pass渲染Unity
- Unity學習記錄-Universal RP渲染管道Unity
- Unity Shader- UV動畫原理及簡易實現Unity動畫
- Unity3D Demo專案開發記錄Unity3D
- Unity學習疑問記錄之介面適配Unity
- Hellow C# unity學習記錄(8)函式的遞迴C#Unity函式遞迴
- Laravel 記錄相關Laravel
- ePWM相關記錄
- linux相關記錄Linux
- 關於javascript原型鏈的記錄JavaScript原型
- 記錄一些有關資料庫操作的擴充套件包資料庫套件
- 【Unity】相關Unity
- 關於fsdb的一些記錄
- 關於 JMeter 5.4.1 的一點記錄JMeter
- 微軟Surface Pro X怎麼樣?微軟Surface Pro X筆記本使用評測微軟筆記
- 微軟Surface Laptop Go怎麼樣?微軟Surface Laptop Go筆記本上手評測微軟APTGo筆記
- 關聯物件(防止自己忘記記錄)物件
- 【Shader】ComputeScreenPos 的使用
- Unity製作本地離線數字人功能模組記錄Unity
- 關於SpringBoot的外部化配置使用記錄Spring Boot
- Openwrt(LUCI相關記錄1)
- Spring相關問題記錄Spring