what’ s the relationship between surface shader and vertex/fragment shader.
when i read the blog posted from http://blog.csdn.net/candycat1992/article/details/39994049
i am puzzled by the generated code.
now, we will generate a very simple surface shader to see the essence of surface shader.
the simple surface shader is:
Shader "Course/SimpleSurface"
{
Properties
{
_MainTex("Main Texture", 2D)="white"{}
}
SubShader
{
CGPROGRAM
#pragma surface surf Lambert
struct Input
{
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf(Input IN, inout SurfaceOutput o)
{
half4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo += tex.rgb;
}
ENDCG
}
}
the effect of this shader is just paste a texture to the object.
then we generate and see the full code of the shader.
we choose the “Show generated Code” , not the Compile and Show code.
then we get:
Shader "Course/SimpleSurface"
{
Properties
{
_MainTex("Main Texture", 2D)="white"{}
}
SubShader
{
// ------------------------------------------------------------
// Surface shader code generated out of a CGPROGRAM block:
// ---- forward rendering base pass:
Pass {
Name "FORWARD"
Tags { "LightMode" = "ForwardBase" }
CGPROGRAM
// compile directives
#pragma vertex vert_surf
#pragma fragment frag_surf
#pragma multi_compile_fog
#pragma multi_compile_fwdbase
#include "HLSLSupport.cginc"
#include "UnityShaderVariables.cginc"
// Surface shader code generated based on:
// writes to per-pixel normal: no
// writes to emission: no
// writes to occlusion: no
// needs world space reflection vector: no
// needs world space normal vector: no
// needs screen space position: no
// needs world space position: no
// needs view direction: no
// needs world space view direction: no
// needs world space position for lighting: YES
// needs world space view direction for lighting: no
// needs world space view direction for lightmaps: no
// needs vertex color: no
// needs VFACE: no
// passes tangent-to-world matrix to pixel shader: no
// reads from normal: no
// 1 texcoords actually used
// float2 _MainTex
#define UNITY_PASS_FORWARDBASE
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#define INTERNAL_DATA
#define WorldReflectionVector(data,normal) data.worldRefl
#define WorldNormalVector(data,normal) normal
// Original surface shader snippet:
#line 7 ""
#ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
#endif
//#pragma surface surf Lambert
struct Input
{
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf(Input IN, inout SurfaceOutput o)
{
half4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo += tex.rgb;
}
// vertex-to-fragment interpolation data
// no lightmaps:
#ifdef LIGHTMAP_OFF
struct v2f_surf {
float4 pos : SV_POSITION;
float2 pack0 : TEXCOORD0; // _MainTex
half3 worldNormal : TEXCOORD1;
float3 worldPos : TEXCOORD2;
#if UNITY_SHOULD_SAMPLE_SH
half3 sh : TEXCOORD3; // SH
#endif
SHADOW_COORDS(4)
UNITY_FOG_COORDS(5)
#if SHADER_TARGET >= 30
float4 lmap : TEXCOORD6;
#endif
UNITY_INSTANCE_ID
};
#endif
// with lightmaps:
#ifndef LIGHTMAP_OFF
struct v2f_surf {
float4 pos : SV_POSITION;
float2 pack0 : TEXCOORD0; // _MainTex
half3 worldNormal : TEXCOORD1;
float3 worldPos : TEXCOORD2;
float4 lmap : TEXCOORD3;
SHADOW_COORDS(4)
UNITY_FOG_COORDS(5)
#ifdef DIRLIGHTMAP_COMBINED
fixed3 tSpace0 : TEXCOORD6;
fixed3 tSpace1 : TEXCOORD7;
fixed3 tSpace2 : TEXCOORD8;
#endif
UNITY_INSTANCE_ID
};
#endif
float4 _MainTex_ST;
// vertex shader
v2f_surf vert_surf (appdata_full v) {
UNITY_SETUP_INSTANCE_ID(v);
v2f_surf o;
UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
UNITY_TRANSFER_INSTANCE_ID(v,o);
o.pos = UnityObjectToClipPos(v.vertex);
o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
#if !defined(LIGHTMAP_OFF) && defined(DIRLIGHTMAP_COMBINED)
fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
#endif
#if !defined(LIGHTMAP_OFF) && defined(DIRLIGHTMAP_COMBINED)
o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
#endif
o.worldPos = worldPos;
o.worldNormal = worldNormal;
#ifndef DYNAMICLIGHTMAP_OFF
o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#endif
#ifndef LIGHTMAP_OFF
o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
#endif
// SH/ambient and vertex lights
#ifdef LIGHTMAP_OFF
#if UNITY_SHOULD_SAMPLE_SH
o.sh = 0;
// Approximated illumination from non-important point lights
#ifdef VERTEXLIGHT_ON
o.sh += Shade4PointLights (
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, worldPos, worldNormal);
#endif
o.sh = ShadeSHPerVertex (worldNormal, o.sh);
#endif
#endif // LIGHTMAP_OFF
TRANSFER_SHADOW(o); // pass shadow coordinates to pixel shader
UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
return o;
}
// fragment shader
fixed4 frag_surf (v2f_surf IN) : SV_Target {
UNITY_SETUP_INSTANCE_ID(IN);
// prepare and unpack data
Input surfIN;
UNITY_INITIALIZE_OUTPUT(Input,surfIN);
surfIN.uv_MainTex.x = 1.0;
surfIN.uv_MainTex = IN.pack0.xy;
float3 worldPos = IN.worldPos;
#ifndef USING_DIRECTIONAL_LIGHT
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
#else
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
#endif
#ifdef UNITY_COMPILER_HLSL
SurfaceOutput o = (SurfaceOutput)0;
#else
SurfaceOutput o;
#endif
o.Albedo = 0.0;
o.Emission = 0.0;
o.Specular = 0.0;
o.Alpha = 0.0;
o.Gloss = 0.0;
fixed3 normalWorldVertex = fixed3(0,0,1);
o.Normal = IN.worldNormal;
normalWorldVertex = IN.worldNormal;
// call surface function
surf (surfIN, o);
// compute lighting & shadowing factor
UNITY_LIGHT_ATTENUATION(atten, IN, worldPos)
fixed4 c = 0;
// Setup lighting environment
UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;
#if !defined(LIGHTMAP_ON)
gi.light.color = _LightColor0.rgb;
gi.light.dir = lightDir;
gi.light.ndotl = LambertTerm (o.Normal, gi.light.dir);
#endif
// Call GI (lightmaps/SH/reflections) lighting function
UnityGIInput giInput;
UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
giInput.light = gi.light;
giInput.worldPos = worldPos;
giInput.atten = atten;
#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
giInput.lightmapUV = IN.lmap;
#else
giInput.lightmapUV = 0.0;
#endif
#if UNITY_SHOULD_SAMPLE_SH
giInput.ambient = IN.sh;
#else
giInput.ambient.rgb = 0.0;
#endif
giInput.probeHDR[0] = unity_SpecCube0_HDR;
giInput.probeHDR[1] = unity_SpecCube1_HDR;
#if UNITY_SPECCUBE_BLENDING || UNITY_SPECCUBE_BOX_PROJECTION
giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
#endif
#if UNITY_SPECCUBE_BOX_PROJECTION
giInput.boxMax[0] = unity_SpecCube0_BoxMax;
giInput.probePosition[0] = unity_SpecCube0_ProbePosition;
giInput.boxMax[1] = unity_SpecCube1_BoxMax;
giInput.boxMin[1] = unity_SpecCube1_BoxMin;
giInput.probePosition[1] = unity_SpecCube1_ProbePosition;
#endif
LightingLambert_GI(o, giInput, gi);
// realtime lighting: call lighting function
c += LightingLambert (o, gi);
UNITY_APPLY_FOG(IN.fogCoord, c); // apply fog
UNITY_OPAQUE_ALPHA(c.a);
return c;
}
ENDCG
}
// ---- forward rendering additive lights pass:
Pass {
Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" }
ZWrite Off Blend One One
CGPROGRAM
// compile directives
#pragma vertex vert_surf
#pragma fragment frag_surf
#pragma multi_compile_fog
#pragma multi_compile_fwdadd
#pragma skip_variants INSTANCING_ON
#include "HLSLSupport.cginc"
#include "UnityShaderVariables.cginc"
// Surface shader code generated based on:
// writes to per-pixel normal: no
// writes to emission: no
// writes to occlusion: no
// needs world space reflection vector: no
// needs world space normal vector: no
// needs screen space position: no
// needs world space position: no
// needs view direction: no
// needs world space view direction: no
// needs world space position for lighting: YES
// needs world space view direction for lighting: no
// needs world space view direction for lightmaps: no
// needs vertex color: no
// needs VFACE: no
// passes tangent-to-world matrix to pixel shader: no
// reads from normal: no
// 1 texcoords actually used
// float2 _MainTex
#define UNITY_PASS_FORWARDADD
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#define INTERNAL_DATA
#define WorldReflectionVector(data,normal) data.worldRefl
#define WorldNormalVector(data,normal) normal
// Original surface shader snippet:
#line 7 ""
#ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
#endif
//#pragma surface surf Lambert
struct Input
{
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf(Input IN, inout SurfaceOutput o)
{
half4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo += tex.rgb;
}
// vertex-to-fragment interpolation data
struct v2f_surf {
float4 pos : SV_POSITION;
float2 pack0 : TEXCOORD0; // _MainTex
half3 worldNormal : TEXCOORD1;
float3 worldPos : TEXCOORD2;
SHADOW_COORDS(3)
UNITY_FOG_COORDS(4)
};
float4 _MainTex_ST;
// vertex shader
v2f_surf vert_surf (appdata_full v) {
v2f_surf o;
UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
o.pos = UnityObjectToClipPos(v.vertex);
o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = worldPos;
o.worldNormal = worldNormal;
TRANSFER_SHADOW(o); // pass shadow coordinates to pixel shader
UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
return o;
}
// fragment shader
fixed4 frag_surf (v2f_surf IN) : SV_Target {
// prepare and unpack data
Input surfIN;
UNITY_INITIALIZE_OUTPUT(Input,surfIN);
surfIN.uv_MainTex.x = 1.0;
surfIN.uv_MainTex = IN.pack0.xy;
float3 worldPos = IN.worldPos;
#ifndef USING_DIRECTIONAL_LIGHT
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
#else
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
#endif
#ifdef UNITY_COMPILER_HLSL
SurfaceOutput o = (SurfaceOutput)0;
#else
SurfaceOutput o;
#endif
o.Albedo = 0.0;
o.Emission = 0.0;
o.Specular = 0.0;
o.Alpha = 0.0;
o.Gloss = 0.0;
fixed3 normalWorldVertex = fixed3(0,0,1);
o.Normal = IN.worldNormal;
normalWorldVertex = IN.worldNormal;
// call surface function
surf (surfIN, o);
UNITY_LIGHT_ATTENUATION(atten, IN, worldPos)
fixed4 c = 0;
// Setup lighting environment
UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;
#if !defined(LIGHTMAP_ON)
gi.light.color = _LightColor0.rgb;
gi.light.dir = lightDir;
gi.light.ndotl = LambertTerm (o.Normal, gi.light.dir);
#endif
gi.light.color *= atten;
c += LightingLambert (o, gi);
c.a = 0.0;
UNITY_APPLY_FOG(IN.fogCoord, c); // apply fog
UNITY_OPAQUE_ALPHA(c.a);
return c;
}
ENDCG
}
// ---- deferred lighting base geometry pass:
Pass {
Name "PREPASS"
Tags { "LightMode" = "PrePassBase" }
CGPROGRAM
// compile directives
#pragma vertex vert_surf
#pragma fragment frag_surf
#pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2
#include "HLSLSupport.cginc"
#include "UnityShaderVariables.cginc"
// Surface shader code generated based on:
// writes to per-pixel normal: no
// writes to emission: no
// writes to occlusion: no
// needs world space reflection vector: no
// needs world space normal vector: no
// needs screen space position: no
// needs world space position: no
// needs view direction: no
// needs world space view direction: no
// needs world space position for lighting: YES
// needs world space view direction for lighting: no
// needs world space view direction for lightmaps: no
// needs vertex color: no
// needs VFACE: no
// passes tangent-to-world matrix to pixel shader: no
// reads from normal: YES
// 0 texcoords actually used
#define UNITY_PASS_PREPASSBASE
#include "UnityCG.cginc"
#include "Lighting.cginc"
#define INTERNAL_DATA
#define WorldReflectionVector(data,normal) data.worldRefl
#define WorldNormalVector(data,normal) normal
// Original surface shader snippet:
#line 7 ""
#ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
#endif
//#pragma surface surf Lambert
struct Input
{
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf(Input IN, inout SurfaceOutput o)
{
half4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo += tex.rgb;
}
// vertex-to-fragment interpolation data
struct v2f_surf {
float4 pos : SV_POSITION;
half3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
UNITY_INSTANCE_ID
};
// vertex shader
v2f_surf vert_surf (appdata_full v) {
UNITY_SETUP_INSTANCE_ID(v);
v2f_surf o;
UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
UNITY_TRANSFER_INSTANCE_ID(v,o);
o.pos = UnityObjectToClipPos(v.vertex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = worldPos;
o.worldNormal = worldNormal;
return o;
}
// fragment shader
fixed4 frag_surf (v2f_surf IN) : SV_Target {
UNITY_SETUP_INSTANCE_ID(IN);
// prepare and unpack data
Input surfIN;
UNITY_INITIALIZE_OUTPUT(Input,surfIN);
surfIN.uv_MainTex.x = 1.0;
float3 worldPos = IN.worldPos;
#ifndef USING_DIRECTIONAL_LIGHT
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
#else
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
#endif
#ifdef UNITY_COMPILER_HLSL
SurfaceOutput o = (SurfaceOutput)0;
#else
SurfaceOutput o;
#endif
o.Albedo = 0.0;
o.Emission = 0.0;
o.Specular = 0.0;
o.Alpha = 0.0;
o.Gloss = 0.0;
fixed3 normalWorldVertex = fixed3(0,0,1);
o.Normal = IN.worldNormal;
normalWorldVertex = IN.worldNormal;
// call surface function
surf (surfIN, o);
// output normal and specular
fixed4 res;
res.rgb = o.Normal * 0.5 + 0.5;
res.a = o.Specular;
return res;
}
ENDCG
}
// ---- deferred lighting final pass:
Pass {
Name "PREPASS"
Tags { "LightMode" = "PrePassFinal" }
ZWrite Off
CGPROGRAM
// compile directives
#pragma vertex vert_surf
#pragma fragment frag_surf
#pragma multi_compile_fog
#pragma multi_compile_prepassfinal
#include "HLSLSupport.cginc"
#include "UnityShaderVariables.cginc"
// Surface shader code generated based on:
// writes to per-pixel normal: no
// writes to emission: no
// writes to occlusion: no
// needs world space reflection vector: no
// needs world space normal vector: no
// needs screen space position: no
// needs world space position: no
// needs view direction: no
// needs world space view direction: no
// needs world space position for lighting: YES
// needs world space view direction for lighting: no
// needs world space view direction for lightmaps: no
// needs vertex color: no
// needs VFACE: no
// passes tangent-to-world matrix to pixel shader: no
// reads from normal: no
// 1 texcoords actually used
// float2 _MainTex
#define UNITY_PASS_PREPASSFINAL
#include "UnityCG.cginc"
#include "Lighting.cginc"
#define INTERNAL_DATA
#define WorldReflectionVector(data,normal) data.worldRefl
#define WorldNormalVector(data,normal) normal
// Original surface shader snippet:
#line 7 ""
#ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
#endif
//#pragma surface surf Lambert
struct Input
{
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf(Input IN, inout SurfaceOutput o)
{
half4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo += tex.rgb;
}
// vertex-to-fragment interpolation data
struct v2f_surf {
float4 pos : SV_POSITION;
float2 pack0 : TEXCOORD0; // _MainTex
float3 worldPos : TEXCOORD1;
float4 screen : TEXCOORD2;
float4 lmap : TEXCOORD3;
#ifdef LIGHTMAP_OFF
float3 vlight : TEXCOORD4;
#else
#ifdef DIRLIGHTMAP_OFF
float4 lmapFadePos : TEXCOORD4;
#endif
#endif
UNITY_FOG_COORDS(5)
#if !defined(LIGHTMAP_OFF) && defined(DIRLIGHTMAP_COMBINED)
fixed3 tSpace0 : TEXCOORD6;
fixed3 tSpace1 : TEXCOORD7;
fixed3 tSpace2 : TEXCOORD8;
#endif
UNITY_INSTANCE_ID
};
float4 _MainTex_ST;
// vertex shader
v2f_surf vert_surf (appdata_full v) {
UNITY_SETUP_INSTANCE_ID(v);
v2f_surf o;
UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
UNITY_TRANSFER_INSTANCE_ID(v,o);
o.pos = UnityObjectToClipPos(v.vertex);
o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
#if !defined(LIGHTMAP_OFF) && defined(DIRLIGHTMAP_COMBINED)
fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
#endif
#if !defined(LIGHTMAP_OFF) && defined(DIRLIGHTMAP_COMBINED)
o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
#endif
o.worldPos = worldPos;
o.screen = ComputeScreenPos (o.pos);
#ifndef DYNAMICLIGHTMAP_OFF
o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#else
o.lmap.zw = 0;
#endif
#ifndef LIGHTMAP_OFF
o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
#ifdef DIRLIGHTMAP_OFF
o.lmapFadePos.xyz = (mul(unity_ObjectToWorld, v.vertex).xyz - unity_ShadowFadeCenterAndType.xyz) * unity_ShadowFadeCenterAndType.w;
o.lmapFadePos.w = (-UnityObjectToViewPos(v.vertex).z) * (1.0 - unity_ShadowFadeCenterAndType.w);
#endif
#else
o.lmap.xy = 0;
float3 worldN = UnityObjectToWorldNormal(v.normal);
o.vlight = ShadeSH9 (float4(worldN,1.0));
#endif
UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
return o;
}
sampler2D _LightBuffer;
#if defined (SHADER_API_XBOX360) && defined (UNITY_HDR_ON)
sampler2D _LightSpecBuffer;
#endif
#ifdef LIGHTMAP_ON
float4 unity_LightmapFade;
#endif
fixed4 unity_Ambient;
// fragment shader
fixed4 frag_surf (v2f_surf IN) : SV_Target {
UNITY_SETUP_INSTANCE_ID(IN);
// prepare and unpack data
Input surfIN;
UNITY_INITIALIZE_OUTPUT(Input,surfIN);
surfIN.uv_MainTex.x = 1.0;
surfIN.uv_MainTex = IN.pack0.xy;
float3 worldPos = IN.worldPos;
#ifndef USING_DIRECTIONAL_LIGHT
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
#else
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
#endif
#ifdef UNITY_COMPILER_HLSL
SurfaceOutput o = (SurfaceOutput)0;
#else
SurfaceOutput o;
#endif
o.Albedo = 0.0;
o.Emission = 0.0;
o.Specular = 0.0;
o.Alpha = 0.0;
o.Gloss = 0.0;
fixed3 normalWorldVertex = fixed3(0,0,1);
// call surface function
surf (surfIN, o);
half4 light = tex2Dproj (_LightBuffer, UNITY_PROJ_COORD(IN.screen));
#if defined (SHADER_API_MOBILE)
light = max(light, half4(0.001, 0.001, 0.001, 0.001));
#endif
#ifndef UNITY_HDR_ON
light = -log2(light);
#endif
#if defined (SHADER_API_XBOX360) && defined (UNITY_HDR_ON)
light.w = tex2Dproj (_LightSpecBuffer, UNITY_PROJ_COORD(IN.screen)).r;
#endif
#ifndef LIGHTMAP_OFF
#ifdef DIRLIGHTMAP_OFF
// single lightmap
fixed4 lmtex = UNITY_SAMPLE_TEX2D(unity_Lightmap, IN.lmap.xy);
fixed3 lm = DecodeLightmap (lmtex);
light.rgb += lm;
#elif DIRLIGHTMAP_COMBINED
// directional lightmaps
fixed4 lmtex = UNITY_SAMPLE_TEX2D(unity_Lightmap, IN.lmap.xy);
half4 lm = half4(DecodeLightmap(lmtex), 0);
light += lm;
#elif DIRLIGHTMAP_SEPARATE
// directional with specular - no support
#endif // DIRLIGHTMAP_OFF
#else
light.rgb += IN.vlight;
#endif // !LIGHTMAP_OFF
#ifndef DYNAMICLIGHTMAP_OFF
fixed4 dynlmtex = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, IN.lmap.zw);
light.rgb += DecodeRealtimeLightmap (dynlmtex);
#endif
half4 c = LightingLambert_PrePass (o, light);
UNITY_APPLY_FOG(IN.fogCoord, c); // apply fog
UNITY_OPAQUE_ALPHA(c.a);
return c;
}
ENDCG
}
// ---- deferred shading pass:
Pass {
Name "DEFERRED"
Tags { "LightMode" = "Deferred" }
CGPROGRAM
// compile directives
#pragma vertex vert_surf
#pragma fragment frag_surf
#pragma exclude_renderers nomrt
#pragma multi_compile_prepassfinal
#pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2
#include "HLSLSupport.cginc"
#include "UnityShaderVariables.cginc"
// Surface shader code generated based on:
// writes to per-pixel normal: no
// writes to emission: no
// writes to occlusion: no
// needs world space reflection vector: no
// needs world space normal vector: no
// needs screen space position: no
// needs world space position: no
// needs view direction: no
// needs world space view direction: no
// needs world space position for lighting: YES
// needs world space view direction for lighting: no
// needs world space view direction for lightmaps: no
// needs vertex color: no
// needs VFACE: no
// passes tangent-to-world matrix to pixel shader: no
// reads from normal: YES
// 1 texcoords actually used
// float2 _MainTex
#define UNITY_PASS_DEFERRED
#include "UnityCG.cginc"
#include "Lighting.cginc"
#define INTERNAL_DATA
#define WorldReflectionVector(data,normal) data.worldRefl
#define WorldNormalVector(data,normal) normal
// Original surface shader snippet:
#line 7 ""
#ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
#endif
//#pragma surface surf Lambert
struct Input
{
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf(Input IN, inout SurfaceOutput o)
{
half4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo += tex.rgb;
}
// vertex-to-fragment interpolation data
struct v2f_surf {
float4 pos : SV_POSITION;
float2 pack0 : TEXCOORD0; // _MainTex
half3 worldNormal : TEXCOORD1;
float3 worldPos : TEXCOORD2;
float4 lmap : TEXCOORD3;
#ifdef LIGHTMAP_OFF
#if UNITY_SHOULD_SAMPLE_SH
half3 sh : TEXCOORD4; // SH
#endif
#else
#ifdef DIRLIGHTMAP_OFF
float4 lmapFadePos : TEXCOORD4;
#endif
#endif
UNITY_INSTANCE_ID
};
float4 _MainTex_ST;
// vertex shader
v2f_surf vert_surf (appdata_full v) {
UNITY_SETUP_INSTANCE_ID(v);
v2f_surf o;
UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
UNITY_TRANSFER_INSTANCE_ID(v,o);
o.pos = UnityObjectToClipPos(v.vertex);
o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = worldPos;
o.worldNormal = worldNormal;
#ifndef DYNAMICLIGHTMAP_OFF
o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#else
o.lmap.zw = 0;
#endif
#ifndef LIGHTMAP_OFF
o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
#ifdef DIRLIGHTMAP_OFF
o.lmapFadePos.xyz = (mul(unity_ObjectToWorld, v.vertex).xyz - unity_ShadowFadeCenterAndType.xyz) * unity_ShadowFadeCenterAndType.w;
o.lmapFadePos.w = (-UnityObjectToViewPos(v.vertex).z) * (1.0 - unity_ShadowFadeCenterAndType.w);
#endif
#else
o.lmap.xy = 0;
#if UNITY_SHOULD_SAMPLE_SH
o.sh = 0;
o.sh = ShadeSHPerVertex (worldNormal, o.sh);
#endif
#endif
return o;
}
#ifdef LIGHTMAP_ON
float4 unity_LightmapFade;
#endif
fixed4 unity_Ambient;
// fragment shader
void frag_surf (v2f_surf IN,
out half4 outDiffuse : SV_Target0,
out half4 outSpecSmoothness : SV_Target1,
out half4 outNormal : SV_Target2,
out half4 outEmission : SV_Target3) {
UNITY_SETUP_INSTANCE_ID(IN);
// prepare and unpack data
Input surfIN;
UNITY_INITIALIZE_OUTPUT(Input,surfIN);
surfIN.uv_MainTex.x = 1.0;
surfIN.uv_MainTex = IN.pack0.xy;
float3 worldPos = IN.worldPos;
#ifndef USING_DIRECTIONAL_LIGHT
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
#else
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
#endif
#ifdef UNITY_COMPILER_HLSL
SurfaceOutput o = (SurfaceOutput)0;
#else
SurfaceOutput o;
#endif
o.Albedo = 0.0;
o.Emission = 0.0;
o.Specular = 0.0;
o.Alpha = 0.0;
o.Gloss = 0.0;
fixed3 normalWorldVertex = fixed3(0,0,1);
o.Normal = IN.worldNormal;
normalWorldVertex = IN.worldNormal;
// call surface function
surf (surfIN, o);
fixed3 originalNormal = o.Normal;
half atten = 1;
// Setup lighting environment
UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;
gi.light.color = 0;
gi.light.dir = half3(0,1,0);
gi.light.ndotl = LambertTerm (o.Normal, gi.light.dir);
// Call GI (lightmaps/SH/reflections) lighting function
UnityGIInput giInput;
UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
giInput.light = gi.light;
giInput.worldPos = worldPos;
giInput.atten = atten;
#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
giInput.lightmapUV = IN.lmap;
#else
giInput.lightmapUV = 0.0;
#endif
#if UNITY_SHOULD_SAMPLE_SH
giInput.ambient = IN.sh;
#else
giInput.ambient.rgb = 0.0;
#endif
giInput.probeHDR[0] = unity_SpecCube0_HDR;
giInput.probeHDR[1] = unity_SpecCube1_HDR;
#if UNITY_SPECCUBE_BLENDING || UNITY_SPECCUBE_BOX_PROJECTION
giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
#endif
#if UNITY_SPECCUBE_BOX_PROJECTION
giInput.boxMax[0] = unity_SpecCube0_BoxMax;
giInput.probePosition[0] = unity_SpecCube0_ProbePosition;
giInput.boxMax[1] = unity_SpecCube1_BoxMax;
giInput.boxMin[1] = unity_SpecCube1_BoxMin;
giInput.probePosition[1] = unity_SpecCube1_ProbePosition;
#endif
LightingLambert_GI(o, giInput, gi);
// call lighting function to output g-buffer
outEmission = LightingLambert_Deferred (o, gi, outDiffuse, outSpecSmoothness, outNormal);
#ifndef UNITY_HDR_ON
outEmission.rgb = exp2(-outEmission.rgb);
#endif
UNITY_OPAQUE_ALPHA(outDiffuse.a);
}
ENDCG
}
// ---- meta information extraction pass:
Pass {
Name "Meta"
Tags { "LightMode" = "Meta" }
Cull Off
CGPROGRAM
// compile directives
#pragma vertex vert_surf
#pragma fragment frag_surf
#pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2
#pragma skip_variants INSTANCING_ON
#include "HLSLSupport.cginc"
#include "UnityShaderVariables.cginc"
// Surface shader code generated based on:
// writes to per-pixel normal: no
// writes to emission: no
// writes to occlusion: no
// needs world space reflection vector: no
// needs world space normal vector: no
// needs screen space position: no
// needs world space position: no
// needs view direction: no
// needs world space view direction: no
// needs world space position for lighting: YES
// needs world space view direction for lighting: no
// needs world space view direction for lightmaps: no
// needs vertex color: no
// needs VFACE: no
// passes tangent-to-world matrix to pixel shader: no
// reads from normal: no
// 1 texcoords actually used
// float2 _MainTex
#define UNITY_PASS_META
#include "UnityCG.cginc"
#include "Lighting.cginc"
#define INTERNAL_DATA
#define WorldReflectionVector(data,normal) data.worldRefl
#define WorldNormalVector(data,normal) normal
// Original surface shader snippet:
#line 7 ""
#ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
#endif
//#pragma surface surf Lambert
struct Input
{
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf(Input IN, inout SurfaceOutput o)
{
half4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo += tex.rgb;
}
#include "UnityMetaPass.cginc"
// vertex-to-fragment interpolation data
struct v2f_surf {
float4 pos : SV_POSITION;
float2 pack0 : TEXCOORD0; // _MainTex
float3 worldPos : TEXCOORD1;
};
float4 _MainTex_ST;
// vertex shader
v2f_surf vert_surf (appdata_full v) {
v2f_surf o;
UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
o.pos = UnityMetaVertexPosition(v.vertex, v.texcoord1.xy, v.texcoord2.xy, unity_LightmapST, unity_DynamicLightmapST);
o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = worldPos;
return o;
}
// fragment shader
fixed4 frag_surf (v2f_surf IN) : SV_Target {
// prepare and unpack data
Input surfIN;
UNITY_INITIALIZE_OUTPUT(Input,surfIN);
surfIN.uv_MainTex.x = 1.0;
surfIN.uv_MainTex = IN.pack0.xy;
float3 worldPos = IN.worldPos;
#ifndef USING_DIRECTIONAL_LIGHT
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
#else
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
#endif
#ifdef UNITY_COMPILER_HLSL
SurfaceOutput o = (SurfaceOutput)0;
#else
SurfaceOutput o;
#endif
o.Albedo = 0.0;
o.Emission = 0.0;
o.Specular = 0.0;
o.Alpha = 0.0;
o.Gloss = 0.0;
fixed3 normalWorldVertex = fixed3(0,0,1);
// call surface function
surf (surfIN, o);
UnityMetaInput metaIN;
UNITY_INITIALIZE_OUTPUT(UnityMetaInput, metaIN);
metaIN.Albedo = o.Albedo;
metaIN.Emission = o.Emission;
return UnityMetaFragment(metaIN);
}
ENDCG
}
// ---- end of surface shader generated code
#LINE 24
}
}
=================================================================
we will explain the full code segment by segment.
1/ 1~20
Shader "Course/SimpleSurface"
{
Properties
{
_MainTex("Main Texture", 2D)="white"{}
}
SubShader
{
// ------------------------------------------------------------
// Surface shader code generated out of a CGPROGRAM block:
// ---- forward rendering base pass:
Pass {
Name "FORWARD"
Tags { "LightMode" = "ForwardBase" }
CGPROGRAM
// compile directives
we fine a property called _MainTex. we use this texture to paste the surface. then we will see the generated code contains one key word. Pass.
the pass can not be find in surface shader. because in offical webiste says: code must be placed inside the SubShader block, but not inside Pass. and surface shader will compile into multiple passes itself.
then we can see the Name key word. Name is the unique word of the pass. we can use other shader’s pass by the UsePass keyword. this we will learn in the following step.
then we will see another key word Tags. we also know the key-value pairs should be appear in the Tags.
2/ 20~40
#pragma vertex vert_surf
#pragma fragment frag_surf
#pragma multi_compile_fog
#pragma multi_compile_fwdbase
#include "HLSLSupport.cginc"
#include "UnityShaderVariables.cginc"
// Surface shader code generated based on:
// writes to per-pixel normal: no
// writes to emission: no
// writes to occlusion: no
// needs world space reflection vector: no
// needs world space normal vector: no
// needs screen space position: no
// needs world space position: no
// needs view direction: no
// needs world space view direction: no
// needs world space position for lighting: YES
// needs world space view direction for lighting: no
// needs world space view direction for lightmaps: no
// needs vertex color: no
as we have already known, surface shader will compiled to vertex/fragment shader. now we see that the #pragma vertex vert_surf, and #pragma fragment frag_surf , these two line code shows the true fact.
we also see that, #pragma multi_complie_fog and #pragma multi_compile_fwdbase. i do not know what’s the meaning. but we can know from the website, that multi means many, that means compile one shader to different shader. how to implement this aim. we can learn from the website:http://blog.csdn.net/aa20274270/article/details/51910035.
now ,we ignore these two line. we will learn latter.
then, #include “HLSLSupport.cginc” and “UnityShaderVariables.cginc” these import the head file to the shader. 27~40 is annotation.
3/ 41~60
// needs VFACE: no
// passes tangent-to-world matrix to pixel shader: no
// reads from normal: no
// 1 texcoords actually used
// float2 _MainTex
#define UNITY_PASS_FORWARDBASE
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#define INTERNAL_DATA
#define WorldReflectionVector(data,normal) data.worldRefl
#define WorldNormalVector(data,normal) normal
// Original surface shader snippet:
#line 7 ""
#ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
#endif
//#pragma surface surf Lambert
4/ 62~76
struct Input
{
float2 uv_MainTex;
};
sampler2D _MainTex;
void surf(Input IN, inout SurfaceOutput o)
{
half4 tex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo += tex.rgb;
}
// vertex-to-fragment interpolation data
this block code is the same with the code we wrote in surface shader.
5/ 77~112
// no lightmaps:
#ifdef LIGHTMAP_OFF
struct v2f_surf {
float4 pos : SV_POSITION;
float2 pack0 : TEXCOORD0; // _MainTex
half3 worldNormal : TEXCOORD1;
float3 worldPos : TEXCOORD2;
#if UNITY_SHOULD_SAMPLE_SH
half3 sh : TEXCOORD3; // SH
#endif
SHADOW_COORDS(4)
UNITY_FOG_COORDS(5)
#if SHADER_TARGET >= 30
float4 lmap : TEXCOORD6;
#endif
UNITY_INSTANCE_ID
};
#endif
// with lightmaps:
#ifndef LIGHTMAP_OFF
struct v2f_surf {
float4 pos : SV_POSITION;
float2 pack0 : TEXCOORD0; // _MainTex
half3 worldNormal : TEXCOORD1;
float3 worldPos : TEXCOORD2;
float4 lmap : TEXCOORD3;
SHADOW_COORDS(4)
UNITY_FOG_COORDS(5)
#ifdef DIRLIGHTMAP_COMBINED
fixed3 tSpace0 : TEXCOORD6;
fixed3 tSpace1 : TEXCOORD7;
fixed3 tSpace2 : TEXCOORD8;
#endif
UNITY_INSTANCE_ID
};
#endif
this code means, we will choose one v2f_surf struct according to the key word LIGHTMAP_OFF is defined or not.
6/ 113~163
float4 _MainTex_ST;
// vertex shader
v2f_surf vert_surf (appdata_full v) {
UNITY_SETUP_INSTANCE_ID(v);
v2f_surf o;
UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
UNITY_TRANSFER_INSTANCE_ID(v,o);
o.pos = UnityObjectToClipPos(v.vertex);
o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
#if !defined(LIGHTMAP_OFF) && defined(DIRLIGHTMAP_COMBINED)
fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
#endif
#if !defined(LIGHTMAP_OFF) && defined(DIRLIGHTMAP_COMBINED)
o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
#endif
o.worldPos = worldPos;
o.worldNormal = worldNormal;
#ifndef DYNAMICLIGHTMAP_OFF
o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#endif
#ifndef LIGHTMAP_OFF
o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
#endif
// SH/ambient and vertex lights
#ifdef LIGHTMAP_OFF
#if UNITY_SHOULD_SAMPLE_SH
o.sh = 0;
// Approximated illumination from non-important point lights
#ifdef VERTEXLIGHT_ON
o.sh += Shade4PointLights (
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, worldPos, worldNormal);
#endif
o.sh = ShadeSHPerVertex (worldNormal, o.sh);
#endif
#endif // LIGHTMAP_OFF
TRANSFER_SHADOW(o); // pass shadow coordinates to pixel shader
UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
return o;
}
we now see the familar funciton——vertex function.
we also notice that the float4 _MainTex_ST, declares the _MainTex property.
本文通过一个简单的表面着色器示例,详细解释了表面着色器与顶点/片段着色器之间的关系,展示了表面着色器如何被编译为多个渲染通道,并逐段分析了生成的完整着色器代码。

1694

被折叠的 条评论
为什么被折叠?



