unity中顶点片段shader环境反射

46 篇文章 2 订阅
14 篇文章 0 订阅

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"








	}
}




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值