Here are some examples of surface shader. The following examples focus on using built-in lighting models, and for examples of how to use custom lighting models, see surface Shader Lighting Examples.
Simple
We will start with a very simple shader, and gradually improve on this basis. The following shader will place the surface color "white". It uses the built-in Lambert (diffuse) illumination model.
Shader "Example/diffuse simple" { Subshader { Tags {"Rendertype" = "Opaque" } cgprogram # pragma surface surf Lambert struct Input { float4 color:color; }; void Surf (Input in, InOut surfaceoutput o) { O.albedo = 1; } ENDCG } Fallback "diffuse" }
Here's what it's like to use two lights to act on a model:
Texture
An all-white object is too boring, so let's add a texture. We will add a Properties block to the shader so that we can get a texture selector in the material. The following bold changes are other:
Shader "Example/diffuse Texture" { Properties { _maintex ("Texture", 2D) = "White" {} } Subshader { Tags {"Rendertype" = "Opaque" } cgprogram 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" }
Normal map
Let's add some normal maps:
Shader "Example/diffuse Bump" { Properties { _maintex ("Texture", 2D) = "White" {} _bumpmap (" BumpMap ", 2D) =" Bump " {} } subshader { Tags {" Rendertype "=" Opaque " } cgprogram # pragma surface surf Lambert struct Input { float2 Uv_maintex; Float2 uv_bumpmap; }; Sampler2d _maintex; Sampler2d _bumpmap; void Surf (Input in, InOut surfaceoutput o) {O.albedo = tex2d (_maintex, In.uv_maintex). RGB; o.normal = Unpack Normal (tex2d (_bumpmap, In.uv_bumpmap)); } ENDCG} Fallback "Diffuse" }
Edge Illumination
Now try adding some edge lighting (Rim Lighting) to highlight the edges of an object. We will add some scattered light based on the angle between the surface normals and the line of sight. To do this, we'll use the built-in surface shader variablesviewDir。
Shader "Example/rim" {Properties {_maintex ("Texture", 2D) = "White" {} _bumpmap ("BumpMap", 2D) = "Bump" {} _rimcolor ("Rim color", Color) = (0.26,0.19,0.16,0.0) _rimpower ("Rim Power", Range (0.5,8.0)) = 3.0 } subshader {Tags {"rendertype" = "Opaque" } cgprogram #pragma surface surf Lambert struct Input {float2 uv_maintex; float2 uv_bumpmap; float3 Viewdir;} ; Sampler2d _maintex; Sampler2d _bumpmap; FLOAT4 _rimcolor; float _rimpower; void Surf (Input in, InOut surfaceoutput o) {O.albedo = tex2d (_maintex, In.uv_maintex). RGB; o.normal = Unpack Normal (tex2d (_bumpmap, In.uv_bumpmap)); Half rim = 1.0- saturate (dot (normalize (in.viewdir), o.normal); o.emission = _rimcolor.rgb * pow (rim, _rimpow ER); } ENDCG} Fallback "Diffuse" }
Detail Texture
To have a different effect, let's add a texture that combines the textures with the base texture. Detail textures Use the same uvs in the material, but often use different tiling. So we have to use different UV coordinates as input.
Shader "Example/detail" { Properties { _maintex ("Texture", 2D) = "White" {} _bumpmap ("BumpMap", 2D = "Bump" {} _detail ("Detail", 2D) = "Gray" {} } subshader { Tags {"Rendertype" = "Opaque"
cgprogram
#pragma surface surf Lambert
struct
void Surf (Input in, InOut surfaceoutput o) {O.albedo = tex2d (_maintex, In.uv_maintex). RGB; O.albedo *= tex2d (_detail, In.uv_detail). RGB * 2; o.normal = Unpacknormal (tex2d (_bumpmap, In.uv_bumpmap));} ENDCG} Fallback "Diffuse" }
Using a checkerboard texture does not make much sense, but it shows the effect:
Detail texture of screen space
What is the detail texture of the screen space? This doesn't make much sense to the soldier's head model, but it shows screenPos
how the built-in input is used:
Shader "Example/screenpos" { Properties { _maintex ("Texture", 2D) = "White" {} _detail ("Detail", 2D) = "Gray" {} } subshader { Tags {"Rendertype" = "Opaque" } cgprogram #pragma surface S Urf Lambert struct Input { float2 Uv_maintex; FLOAT4 screenpos; }; Sampler2d _maintex; Sampler2d _detail; void Surf (Input in, InOut surfaceoutput o) {O.albedo = tex2d (_maintex, In.uv_maintex). RGB; FLOAT2 SCREENUV = IN.screenPos.xy/ in.screenpos.w; SCREENUV *= float2 (8,6); O.albedo *= tex2d (_detail, SCREENUV). RGB * 2;} ENDCG} Fallback "Diffuse" }
The normal map is removed from the above, just to make the code shorter.
Cube Map Reflection
Here's one with built-in inputworldRefl的shader实现立方体贴图反射。它实际上和内建的反射/漫反射shader非常像:
Shader "Example/worldrefl" { Properties { _maintex ("Texture", 2D) = "White" {} _cube ("Cubemap", CUBE) = "" {} } subshader { Tags {"Rendertype" = "Opaque" } cgprogram #pragma surface sur F Lambert struct Input { float2 Uv_maintex; FLOAT3 worldrefl; }; Sampler2d _maintex; Samplercube _cube; void Surf (Input in, InOut surfaceoutput o) {O.albedo = tex2d (_maintex, In.uv_maintex). RGB * 0.5; o.emission = Texcube (_cube, IN.WORLDREFL). RGB;} ENDCG} Fallback "Diffuse" }
Once the reflection color is assigned to emission, we can get a very shiny soldier:
If you want to implement a reflection effect that is performed by a normal map, simply add a little bit of content: INTERNAL_DATA
It needs to be added to the input structure, and after you write the normal output, the Worldreflectionvector function calculates each vertex reflection vector.
Shader "Example/worldrefl Normalmap" { Properties { _maintex ("Texture", 2D) = "White" {} _bumpmap ( "BumpMap", 2D) = "Bump" {} _cube ("Cubemap", Cube) = "" {} } subshader { Tags {"Rendertype" = " Opaque " } cgprogram #pragma surface surf Lambert struct Input {float2 Uv_maintex; Float2 uv_ BumpMap; FLOAT3 WORLDREFL; Internal_data}; Sampler2d _maintex; Sampler2d _bumpmap; Samplercube _cube; void Surf (Input in, InOut surfaceoutput o) {O.albedo = tex2d (_maintex, In.uv_maintex). RGB * 0.5; O.normal =
Unpacknormal (tex2d (_bumpmap, In.uv_bumpmap)); O.emission =
Texcube (_cube, Worldreflectionvector (in, O.normal)). RGB; ENDCG} Fallback "Diffuse" }
Here is a normal map for the shiny soldier:
Slicing in world space coordinates
Here the shader the "cut" object by dropping the pixels on the close horizontal ring. It is done by using the CG/HLSL function clip () for pixels in a single world coordinate. We'll use the built-in surface shader variable Worldpos.
Shader "Example/slices" { Properties { _maintex ("Texture", 2D) = "White" {} _bumpmap ("BumpMap", 2D = "Bump" {} } subshader { Tags {"Rendertype" = "Opaque" } Cull Off cgprogram # pragma surface surf Lambert struct Input { float2 Uv_maintex; FLOAT2 Uv_bumpmap; FLOAT3 worldpos; }; Sampler2d _maintex; Sampler2d _bumpmap; void Surf (Input in, InOut surfaceoutput o) {Clip (Frac ((in.worldpos.y+in.worldpos.z*0.1) * 5)-0.5); O.albedo = tex2d (_maintex, In.uv_maintex). RGB; o.normal = Unpacknormal (tex2d (_bumpmap, In.uv_bumpmap));} ENDCG} Fallback "Diffuse" }
use the normal extrusion of the vertex modifier (normal Extrusion )
In vertex shader, it is possible to use the vertex modifier function that modifies the input vertex data. This can be used for program animation, normal extrusion and so on. Compilation instructions for surface shadervertex:functionName用来实现它,其函数参数为appdata_full
。
The following shader are used to move vertices in a material by a given amount in the direction of the normals:
Shader "Example/normal Extrusion" { Properties { _maintex ("Texture", 2D) = "White" {} _amount (" Extrusion Amount ", Range ( -1,1)) = 0.5 } subshader { Tags {" Rendertype "=" Opaque " } Cgprogram #pragma surface surf Lambert vertex:vert struct Input { float2 uv_maintex; }; float _amount; void Vert (inout appdata_full v) {v.vertex.xyz + = V.normal * _amount;} sampler2d _maintex; void Surf (Input in, InOut surfaceoutput o) {O.albedo = tex2d (_maintex, In.uv_maintex). RGB; ENDCG} Fallback "Diffuse" }
Moving vertices in the normal direction creates a fat soldier:
Calculation of custom data by vertex (computed Per-vertex)
The vertex modifier can also be used to calculate custom data in vertex shader and then be passed to the surface shader function by vertex. You need to use the same compiler directive vertex:functionname, but this function takes two arguments inout appdata_full
andout Input。你还可以加入任意非内建的输入参数。
Note: custom member names in this way cannot begin with "Uvs", otherwise they will not be valid.
The following example defines a custom member float Customcolor, which is used in the vertex function to calculate:
Shader "Example/custom Vertex Data" { Properties { _maintex ("Texture", 2D) = "White" {} } Subshader { Tags {"Rendertype" = "Opaque" } cgprogram #pragma surface surf Lambert Vertex:vert struct Input { float2 Uv_maintex; FLOAT3 customcolor; }; void Vert (InOut appdata_full V, out Input o) { unity_initialize_output (input,o); O.customcolor = ABS (v.normal);} sampler2d _maintex; void Surf (Input in, InOut surfaceoutput o) {O.albedo = tex2d (_maintex, In.uv_maintex). RGB; O.albedo *= I N.customcolor; } ENDCG} Fallback "Diffuse" }
In this example, customColor
the absolute value of the line is set:
A more practical use could be to calculate any per-vertex data provided by non-built input variables, or to optimize shader calculations. For example, edge illumination is calculated by pixel on the object vertex rather than in the surface shader.
Final color modifier
You can use the final color modifier function to modify the final color computed by shader. Compilation instructions finalcolor:functionName
for surface shader用来实现它,其函数参数为Input IN, SurfaceOutput o, inout fixed4 color
。
Here's a simple shader to apply staining (tint) to the final color. This is different from just applying staining to the surface albedo color: This stain also affects any color from light maps, illumination probes, and similar external sources.
Shader "Example/tint Final Color" { Properties { _maintex ("Texture", 2D) = "White" {} _colortint ("T int ", Color) = (1.0, 0.6, 0.6, 1.0) } subshader { Tags {" Rendertype "=" Opaque " } cgprogram
#pragma surface surf Lambert finalcolor:mycolor struct
Input { float2 uv_maintex; }; Fixed4 _colortint; void MyColor (Input in, Surfaceoutput o, inout fixed4 color) {color *= _colortint;} sampler2d _maintex; void
Surf (Input in, InOut surfaceoutput o) {O.albedo =
tex2d (_maintex, In.uv_maintex). RGB; ENDCG} Fallback "Diffuse" }
Custom fog using the final color modifier
The final color modifier (see above) is typically used to fully implement a custom fog. Fog needs to affect the final computed pixel shader color, which is exactly what the final color modifier does.
The shader here uses fog staining based on distance from the center of the screen. It unites vertex modifiers and final color modifiers that own custom vertex data (fog). When the fog is used in the forward rendering of the additional channel, it needs to be hidden into black. This example deals with the situation and checks the Unity_pass_forwardadd well.
Shader "Example/fog via Final Color"{Properties {_maintex ("Texture", 2D) = "White"{} _fogcolor ("Fog color", color) = (0.3, 0.4, 0.7, 1.0} subshader {Tags {"rendertype" = "Opaque" } cgprogram #pragma surface surf Lambert final Color:mycolor vertex:myvert struct Input {float2 Uv_maintex; half fog; }; void Myvert (InOut appdata_full V, out Input data) {unity_initialize_output (input,data); Float4 hpos = Mul (UNITY _MATRIX_MVP, V.vertex); Data.fog = min (1, Dot (hpos.xy, hpos.xy) * 0.1);} fixed4 _fogcolor; void MyColor (Input in, Surfaceoutput o, inout fixed4 color) {fixed3 Fogcolor = _fogcolor.rgb; #ifdef Unity_pass_ Forwardadd fogcolor = 0; #endif Color.rgb = lerp (Color.rgb, Fogcolor, In.fog);} sampler2d _maintex; void
Surf (Input in, InOut surfaceoutput o) {O.albedo =
tex2d (_maintex, In.uv_maintex). RGB; ENDCG} Fallback "Diffuse" }
Linear fog
Shader "Example/linear Fog"{Properties {_maintex ("Base (RGB)", 2D) = "White"{}} subshader {Tags {"rendertype" = "Opaque"} LOD 200Cgprogram #pragma surface surf Lambert finalcolor:mycolor Vertex:myvertSampler2d _maintex; Uniform Half4 Unity_fogcolor; Uniform Half4 Unity_fogstart; Uniform Half4 unity_fogend; structinput {float2 uv_maintex; half fog;}; void Myvert (InOut appdata_full V, out Input data) {Unity_initialize_out PUT (Input,data); float pos = Length (mul (UNITY_MATRIX_MV, V.vertex). xyz); float diff = unity_fogend.x- unity_fogstart.x; float INV diff = 1.0f/ diff; data.fog = clamp ((unity_fogend.x-pos) * Invdiff, 0.0, 1.0);} void MyColor (Input in, S Urfaceoutput o, inout fixed4 color) {fixed3 Fogcolor = unity_fogcolor.rgb; #ifdef unity_pass_forwardadd fogcolor = 0< c8>; #endif Color.rgb = lerp (fogcolor, Color.rgb, In.fog), void surf (Input in, InOut surfaceoutput o) {Half4 c = tex2d (_maintex, In.uv_maintex); O.albedo = C.rgb; o.alpha = c.a;} ENDCG} FallBack "Diffuse"}
Unity shader--writing Surface Shaders (1)--surface Shader Examples