Writing Surface Shaders
Writing shaders that interact with lighting is complex. There is different light types, different shadow options, different rendering paths (forward and deferred rendering), and The shader should somehow handle all that complexity.
It is very complicated to write shaders that interact with light. They have different types of lighting, different shading options, different render paths (forward rendering and deferred rendering), and shaders should handle these complex things in some appropriate way.
Surface Shaders in Unity is a code generation approach this 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 has to be written by hand. You still write shader code in CG/HLSL.
Unity3d's surface shaders are written only by writing code, making it easier to write light shaders than using low-level vertex/pixel shaders. Note that writing a surface shader does not have any custom language and shortcuts. It simply generates some duplicate code by writing it manually.
You can still write it in CG/HLSL language.
For some examples, take a look at Surface Shader examples and surface Shader Custom Lighting examples.
Here are some examples that you can look at: surface shaders and custom illuminated surface shaders.
How it works
You define a "surface function" which takes any UVs or data you need as input, and fills in output structuresurfaceoutput. Surfaceoutput basically describes properties of the surface (it's albedo color, normal, emission, specularity etc). You write the code in CG/HLSL.
You define a "surface function" that takes uvs or data as input parameters and populates the surfaceoutput as the output structure body. Surfaceoutput describes the underlying surface properties (illumination color reflectivity, normal, spontaneous light, mirror, etc.). You can write it with CG/HLSL.
Surface Shader Compiler then figures out what inputs is needed, what outputs is filled and so on, and generates actual V Ertex&pixel shaders, as well as rendering passes to handle forward and deferred rendering.
The compiler for the surface shader indicates what needs to be entered, what is filled in the output, and so on, and produces the true vertex & pixel shader, and processes the render path for forward rendering or deferred rendering.
Standard output structure of surface shaders are this: the normal surface shader output structure is as follows:
struct Surfaceoutput {
Half3 Albedo;
Half3 Normal;
HALF3 emission;
Half specular;
Half Gloss;
Half Alpha;
};
Samples Example
See surface Shader Examples and surface Shader Custom Lighting Examples pages.
Refer to Surface Shader Examples and surface Shader Custom Lighting Examples.
Surface Shader Compile Directives face shader compilation instructions
Surface shader is placed inside Cgprogram. ENDCG block, just like any other shader. The differences are:
The surface shader must be placed in the Cgprogram. ENDCG blocks, just like any other shader. The difference is:
It must is placed inside Subshader block, not inside Pass. Surface shader'll compile into multiple passes itself.
It must be placed in the Subshader block and cannot be placed in the pass. The surface shader compiles itself within multiple channels.
It uses #pragma surface ... directive to indicate it's a surface shader.
It uses the #pragma surface directive to indicate that it is a shader.
The #pragma surface directive is: #pragma surface instructions to use:
#pragma surface surfacefunction Lightmodel [Optionalparams]
Required Parameters: Required Parameters
Surfacefunction-which Cg function has surface shader code. The function should has the form of void surf (Input in, InOut surfaceoutput o), where Input was a structure you have Defi Ned. Input should contain any texture coordinates and extra automatic variables the needed by surface function. Indicates which CG functions have a surface shader code. The format of this function is as follows: void surf (input in,inout surfaceoutput o), input is your custom structure. The input structure contains all the texture coordinates and additional automatic variables required by the surfacefunction.
Lightmodel-lighting model to use. Built-in ones is Lambert (diffuse) and blinnphong (specular). See Custom Lighting Models page for what to write your own.
Used in light mode. The built-in lighting modes are Lambert (diffuse) and blinnphong (specular). Please refer to: Custom Lighting Models.
Optional Parameters: Optional Parameters
Alpha-alpha blending mode. Use the this for semitransparent shaders.
Alpha blending mode. It can be written to be used as a translucent coloring process.
Alphatest:variablename-alpha testing mode. Use the this for transparent-cutout shaders. Cutoff value is in a float variable with VariableName.
Alpha test mode. Use it to write a transparent silhouette effect. The value of the silhouette is represented by a variable of type float.
Vertex:vertexfunction-custom Vertex modification function. See Tree Bark Shader for example.
A custom vertex modification function. Please refer to Example: Bark shader (tree Bark shader).
Finalcolor:colorfunction-custom Final color modification function. See Surface Shader Examples.
A custom final color modification function. Refer to: Surface shader examples Surface Shader Examples
Exclude_path:prepass or exclude_path:forward-do not generate passes for given rendering path.
Prepass (previous channel) or Exclude_path:forward-do not generate a channel for a given render path.
Addshadow-add Shadow Caster & collector passes. Commonly used with custom vertex modification, so this shadow casting also gets any procedural vertex animation.
Add shadow casts and collection channels. Often used to customize the modification of vertices, so that shadows can also be projected on the vertex animations of any process.
Dualforward-use dual lightmaps in forward rendering path.
Using a dual illumination map in a forward render path
Fullforwardshadows-support all shadow types in Forward rendering path.
All shadow types are supported in the forward render path.
Decal:add-additive decal shader (e.g. terrain addpass).
Add a print shader (for example: Terrain addpass).
Decal:blend-semitransparent decal shader.
Hybrid-Translucent print shader (semitransparent decal shader).
Softvegetation-makes the surface shader only being rendered when Soft vegetation are on.
Use a surface shader only when soft vegetation is open
Noambient-do not apply any ambient lighting or spherical harmonics lights.
Does not apply to any ambient lighting or spherical harmonic illumination.
Novertexlights-do not apply any spherical harmonics or per-vertex lights in Forward rendering.
In forward rendering, it is not suitable for spherical and light-per-vertex illumination.
Nolightmap-disables lightmap Support on this shader (makes a shader smaller).
Disables the light map on this shader. (Makes the shader smaller)
Nodirlightmap-disables directional lightmaps Support on this shader (makes a shader smaller).
Disables the directional light map on this shader. (Makes the shader smaller).
Noforwardadd-disables Forward Rendering additive pass. This makes the shader-one full directional light, with all other lights computed per-vertex/sh. Makes shaders smal Ler as well.
Disables forward rendering to add channels. This causes the shader to support a full directional light and all the light that is computed by vertex/sh, making the shader smaller.
Approxview-computes normalized view direction Per-vertex instead of Per-pixel, for shaders that need it. This was faster, but view direction was not entirely correct when camera gets close to surface.
When the shader is needed, calculate each vertex, not the direction of each pixel. This is faster, but the view direction is not exactly right when the camera is approaching the surface.
Halfasview-pass half-direction vector into the lighting function instead of view-direction. Half-direction'll be computed and normalized per vertex. This is faster and not entirely correct.
The half-direction vector is passed in the illumination function, not the view direction vector. The half-direction calculates and standardizes each vertex. This is faster, but not entirely true.
Additionally, can write #pragma debug inside Cgprogram block, and then surface compiler'll spit out a lot of comment S of the generated code. You can view the using Open Compiled Shader in Shader Inspector.
In addition, you can use the #pragma debug directive in the Cgprogram block, and the compiler generates a lot of commented code. You can view them in the shader panel by opening these already compiled shaders.
Surface Shader input structure indicates the shader input structure
The input structure input generally has a texture coordinates needed by the shader. Texture coordinates must be named "Uvs" followed by Texture name (or start it with "Uv2" to use second Texture coordinate s Gtk.
Input structural body input contains the texture coordinates required for coloring. The texture coordinates must be preceded by a "UV" on the texture name. (or named with "Uv2" as the header to use the second set of texture coordinates)
Additional values that can is put into Input structure:
The following added value can also be placed in the input structure.
FLOAT3 Viewdir-will contain view direction, for computing Parallax effects, RIM lighting etc.
In order to calculate parallax, edge illumination and other effects, input needs to include the view orientation.
FLOAT4 with color Semantic-will contain interpolated Per-vertex COLOR.
FLOAT4 color semantics: interpolation of each vertex color
FLOAT4 Screenpos-will contain screen space position for reflection effects. Used by Wetstreet shader in Dark Unity for example.
Screen coordinates. To get the reflection effect, you need to include screen coordinates. For example, the wetstreet shader used in the dark Unity example.
FLOAT3 Worldpos-will contain world space position.
World coordinates.
FLOAT3 Worldrefl-will contain world reflection vectors if surface shader does not write to O.normal. See Reflect-diffuse Shader for example.
The reflection vector in the world. If the surface coloring is not written to O. Normal, which will contain the world reflection vector. Please refer to this example: Reflect-diffuse shader.
FLOAT3 worldnormal-will contain world normal vector if surface shader does not write to O.normal.
The normal vector in the world. This parameter is included if the surface shader does not write to the normal (o.normal) parameter.
FLOAT3 WORLDREFL;Internal_data -would contain world reflection vectors if surface shader writes to O.normal. To get the reflection vector based on per-pixel normal map with use Worldreflectionvector (in, O.normal). See reflect-bumped Shader for example.
Internal data. If the surface coloring is written to O. Normal, which will contain the world reflection vector. To get a reflection vector based on the normal map of each pixel, use worldreflectionvector (in input, o.normal). Refer to the bump reflection shader.
Float3 Worldnormal; internal_data -would contain world normal vectors if surface shader writes to O.normal. To get the normal vector based on per-pixel normal map, use Worldnormalvector (in, O.normal).
Internal data. If the surface coloring is written to O. Normal, which will contain the world normal vector. To get a normal vector based on the normal map for each pixel, use the world normal vector (in input, o.normal)
Further documentation more reference documents
Surface Shader Examples
Custom Lighting models in surface Shaders
Surface Shader Lighting Examples
Original by www.J2meGame.com, reproduced please specify.
Unity3d Shader Official Tutorials Translation (19)----shader syntax, writing surface shaders