http://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html
最近具体联系了一下里面shader的基本写法,弄来个综合版本
然后就是最难看出差异的反射计算问题,顶点里面计算和片段里面计算的区别
使用的模型是这个,其中右边的是平滑法线后的模型
具体的差异可以看下面gif图 (可以看出)
下面是代码
//http://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html
Shader "Unlit/shenmifangkeShader"
{//http://blog.csdn.net/shenmifangke
Properties
{
_mode("mode", Range(0,12)) = 5
[NoScaleOffset]_MainTex("Texture", 2D) = "white" {}
// normal map texture on the material
// default to dummy "flat surface" normalmap
_Tiling("Tiling", Float) = 1.0//case 8
_BumpMap("Normal Map", 2D) = "bump" {}
_OcclusionMap("Occlusion", 2D) = "white" {}
}
SubShader
{
Tags{ "RenderType" = "Opaque" }
LOD 100
Pass
{
// indicate that our pass is the "base" pass in forward rendering pipeline. It gets ambient and main directional
// light data set up; light direction in _WorldSpaceLightPos0 and color in _LightColor0
Tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
// include file that contains UnityObjectToWorldNormal helper function
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc" // for _LightColor0
//接受影子必须有这个
// compile shader into multiple variants, with and without shadows
// (we don't care about any lightmaps yet, so skip these variants)
#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
// shadow helper functions and macros
#include "AutoLight.cginc"
float _mode;
sampler2D _MainTex;
float4 _MainTex_ST;//这里下面一张图也使用MainTex的uv 所以就不用再次声明了
sampler2D _OcclusionMap;
float _Tiling;//case 8
//顶点输入结构
struct appdata
{
float2 uv : TEXCOORD0;
float4 vertex : POSITION;
};
//顶点输出到片段函数 vertex shader outputs ("vertex to fragment")
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)//Used to pass fog amount around number should be a free texcoord.
float4 pos : SV_POSITION;// clip space position
half3 worldNormal : TEXCOORD1;
half3 worldRefl : TEXCOORD2;
float3 worldPos : TEXCOORD3;
//normal
//float3 worldPos : TEXCOORD0;
//these three vectors will hold a 3x3 rotation matrix
//that transforms from tangent to world space
half3 tspace0 : TEXCOORD4; // tangent.x, bitangent.x, normal.x
half3 tspace1 : TEXCOORD5; // tangent.y, bitangent.y, normal.y
half3 tspace2 : TEXCOORD6; // tangent.z, bitangent.z, normal.z
// texture coordinate for the normal map
//float2 uv : TEXCOORD7;
//float4 pos : SV_POSITION;
half3 objNormal : TEXCOORD7;//case 8
float3 coords : TEXCOORD8;//case 8
fixed4 diff : COLOR0; // diffuse lighting color case9
fixed3 ambient : COLOR1;
SHADOW_COORDS(9) // put shadows data into TEXCOORD9
};
// vertex shader now also needs a per-vertex tangent vector.
// in Unity tangents are 4D vectors, with the .w component used to
// indicate direction of the bitangent vector.
// we also need the texture coordinate.
// vertex shader: takes object space normal as input too 本来只有
v2f vert(
//物体输入属性,也可以写在appdata 但是必须用v.xxx来调用 有out修饰的必须写在这里 注意逗号和分号
float3 normal : NORMAL, //case 3,4,5
float4 tangent : TANGENT, //case 5
float2 uv : TEXCOORD0,//normal need//case 5
appdata v//case 1,3,4,5
)
{
v2f o;
//一些switch用到的定义 因为不能在case里面定义
float3 worldPos;//case 3
float3 worldViewDir;//case 3
float3 worldNormal;//case 3 8
half3 wNormal;//case 5 6
half3 wTangent;//case 5 6
half tangentSign;//case 5 6
half3 wBitangent;//case 5 6
half nl;//case 9
// transform position to clip space(multiply with model*view*projection matrix)
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//这句必须返回
UNITY_TRANSFER_FOG(o, o.vertex);//Compute fog amount from clip space position.
switch (_mode) {
//纯色
case 0:break;
//贴图
case 1:
//o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//这句必须返回
o.uv = TRANSFORM_TEX(v.uv, _MainTex);//有贴图的话这句也很必须
break;
//切空间法线
case 2:
//o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//这句必须返回
// UnityCG.cginc file contains function to transform
// normal from object to world space, use that
o.worldNormal = UnityObjectToWorldNormal(normal);
//o.worldNormal = UnityWorldSpaceViewDir(normal);
break;
case 3:
//天空盒顶点反射
//当然需要天空盒贴图
// compute world space position of the vertex
worldPos = mul(_Object2World, v.vertex).xyz;
// compute world space view direction
worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));//顶点里处理
// world space normal
worldNormal = UnityObjectToWorldNormal(normal);//顶点里处理
// world space reflection vector
o.worldRefl = reflect(-worldViewDir, worldNormal);
break;
case 4:
//天空盒片段反射
//o.pos = mul(UNITY_MATRIX_MVP, vertex);
o.worldPos = mul(_Object2World, v.vertex).xyz;//同上
o.worldNormal = UnityObjectToWorldNormal(normal);//同上
break;
case 5://天空盒法线反射
case 6://天空盒法线反射+贴图
o.worldPos = mul(_Object2World, v.vertex).xyz;
wNormal = UnityObjectToWorldNormal(normal);
wTangent = UnityObjectToWorldDir(tangent.xyz);
// compute bitangent from cross product of normal and tangent
tangentSign = tangent.w * unity_WorldTransformParams.w;
wBitangent = cross(wNormal, wTangent) * tangentSign;
// output the tangent space matrix
o.tspace0 = half3(wTangent.x, wBitangent.x, wNormal.x);
o.tspace1 = half3(wTangent.y, wBitangent.y, wNormal.y);
o.tspace2 = half3(wTangent.z, wBitangent.z, wNormal.z);
o.uv = uv;
break;
case 7:
//棋盘格
o.uv = uv * 30;
break;
case 8:
//Tri-planar Texturing 投影贴图 主要用于生成的简单物体的材质贴图
o.coords = v.vertex.xyz * _Tiling;
o.objNormal = normal;//传递物体法线
o.uv = uv;
return o;
break;
case 9:
//Simple Diffuse Lighting 当然需要一个方向光源
//o.uv = v.texcoord;
o.uv = v.uv;
// get vertex normal in world space
worldNormal = UnityObjectToWorldNormal(normal);
// dot product between normal and light direction for
// standard diffuse (Lambert) lighting
nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
// factor in the light color
o.diff = nl * _LightColor0;//内部变量包含在UnityLightingCommon.cginc里面
return o;
break;
case 10:
//Diffuse Lighting with Ambient 可以调节在lighting里面的光照强度
o.uv = v.uv;
worldNormal = UnityObjectToWorldNormal(normal);
nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
o.diff = nl * _LightColor0;
// the only difference from previous shader:
// in addition to the diffuse lighting from the main light,
// add illumination from ambient or light probes
// ShadeSH9 function from UnityCG.cginc evaluates it,
// using world space normal
o.diff.rgb += ShadeSH9(half4(worldNormal, 1));
break;
case 11:
//接受投影
o.uv = v.uv;
worldNormal = UnityObjectToWorldNormal(normal);
nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
o.diff = nl * _LightColor0.rgba;
o.ambient = ShadeSH9(half4(worldNormal, 1));
// compute shadows data
TRANSFER_SHADOW(o)
break;
default:
return o;
}
return o;
}
// normal map texture from shader properties
sampler2D _BumpMap;
fixed4 frag(v2f i) : SV_Target
{
// sample the texture
fixed4 mode_1 = tex2D(_MainTex, i.uv);
// Apply fog (additive pass are automatically handled)
UNITY_APPLY_FOG(i.fogCoord, mode_1);
//to handle custom fog color another option would have been
//#ifdef UNITY_PASS_FORWARDADD
// UNITY_APPLY_FOG_COLOR(i.fogCoord, color, float4(0,0,0,0));
//#else
// fixed4 myCustomColor = fixed4(0,0,1,0);
// UNITY_APPLY_FOG_COLOR(i.fogCoord, color, myCustomColor);
//#endif
fixed4 c;
half4 skyData;//case 3,4,5 6
half3 skyColor;//case 3,4,5 6
half3 worldViewDir;//case 4,5 6
half3 worldRefl;//case 4,5 6
half3 tnormal;//case 5 6
half3 worldNormal;//case 5 6
fixed3 baseColor;//case 6
fixed occlusion;//case 6
half3 blend;//case 8
fixed4 cx;//case 8
fixed4 cy;//case 8
fixed4 cz;//case 8
fixed shadow;//case 11
fixed3 lighting;//case 11
//case当中不要定义
switch (_mode) {
//纯色
case 0:return fixed4(1, 1, 1, 1); break;
//普通贴图
case 1:return mode_1; break;
case 2:
//切空间法线
// normal is a 3D vector with xyz components; in -1..1
// range. To display it as color, bring the range into 0..1
// and put into red, green, blue components
c.gbr = i.worldNormal*0.5 + 0.5;
return c;
break;
case 3:
//天空盒顶点反射
// sample the default reflection cubemap, using the reflection vector
skyData = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, i.worldRefl);//sample a cubemap
// decode cubemap data into actual color
skyColor = DecodeHDR(skyData, unity_SpecCube0_HDR);
c.rgb = skyColor;
break;
case 4:
//天空盒片段反射
// compute view direction and reflection vector
//把反射光计算放在这里看起来只是提高了一点效果 但是速度更慢了 为了要进行法线贴图计算
// per-pixel here
worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));//改成在片段里面处理
worldRefl = reflect(-worldViewDir, i.worldNormal);//改成在片段里面处理
skyData = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, worldRefl);//同上
skyColor = DecodeHDR(skyData, unity_SpecCube0_HDR);//同上
c.rgb = skyColor;//同上
break;
case 5:
//天空盒法线反射
// sample the normal map, and decode from the Unity encoding
tnormal = UnpackNormal(tex2D(_BumpMap, i.uv));
// transform normal from tangent to world space
worldNormal.x = dot(i.tspace0, tnormal);
worldNormal.y = dot(i.tspace1, tnormal);
worldNormal.z = dot(i.tspace2, tnormal);
// rest the same as in previous shader
worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
worldRefl = reflect(-worldViewDir, worldNormal);
skyData = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, worldRefl);
skyColor = DecodeHDR(skyData, unity_SpecCube0_HDR);
c.rgb = skyColor;
break;
case 6://天空盒法线反射+贴图
// same as from previous shader...
tnormal = UnpackNormal(tex2D(_BumpMap, i.uv));
worldNormal.x = dot(i.tspace0, tnormal);
worldNormal.y = dot(i.tspace1, tnormal);
worldNormal.z = dot(i.tspace2, tnormal);
worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
worldRefl = reflect(-worldViewDir, worldNormal);
skyData = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, worldRefl);
skyColor = DecodeHDR(skyData, unity_SpecCube0_HDR);
c.rgb = skyColor;
// modulate sky color with the base texture, and the occlusion map
baseColor = tex2D(_MainTex, i.uv).rgb;
occlusion = tex2D(_OcclusionMap, i.uv).r;
c.rgb *= baseColor;
c.rgb *= occlusion;
break;
case 7:
//棋盘格
c = fixed4(i.uv,0,0);
c = floor(c) / 2;
return frac(c.x + c.y) * 2;
break;
case 8:
// use absolute value of normal as texture weights
blend = abs(i.objNormal);
// make sure the weights sum up to 1 (divide by sum of x+y+z)
blend /= dot(blend, 1.0);
// read the three texture projections, for x,y,z axes
cx = tex2D(_MainTex, i.coords.yz);
cy = tex2D(_MainTex, i.coords.xz);
cz = tex2D(_MainTex, i.coords.xy);
// blend the textures based on weights
c = cx * blend.x + cy * blend.y + cz * blend.z;
// modulate by regular occlusion map
c *= tex2D(_OcclusionMap, i.uv);
return c;
break;
case 9:
// sample texture
//fixed4 col = tex2D(_MainTex, i.uv);
// multiply by lighting
//col *= i.diff;
return tex2D(_MainTex, i.uv)*i.diff;
break;
case 10:
return tex2D(_MainTex, i.uv)*i.diff;
break;
case 11:
c = tex2D(_MainTex, i.uv);
// compute shadow attenuation (1.0 = fully lit, 0.0 = fully shadowed)
shadow = SHADOW_ATTENUATION(i);
shadow = floor(shadow * 5)/ 6;//add by myself
// darken light's illumination with shadow, keep ambient intact
lighting = i.diff * shadow + i.ambient;
c.rgb *= lighting;
return c;
break;
default: return mode_1;
}
return c;
}
ENDCG
}
/*
//投影必须
// shadow caster rendering pass, implemented manually
// using macros from UnityCG.cginc
Pass
{
Tags{ "LightMode" = "ShadowCaster" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#include "UnityCG.cginc"
struct v2f {
V2F_SHADOW_CASTER;
};
v2f vert(appdata_base v)
{
v2f o;
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
return o;
}
float4 frag(v2f i) : SV_Target
{
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
*/
// shadow casting support 相当于上面一段的无设置写法
UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
}
}