shader入门精要读书笔记26 顶点动画

一、流动河流

Shader "Unity Shaders Book/Chapter 11/Water" {
	Properties {
		_MainTex ("Main Tex", 2D) = "white" {}		//主纹理
		_Color ("Color Tint", Color) = (1, 1, 1, 1)		//整体颜色
		_Magnitude ("Distortion Magnitude", Float) = 1		//控制水流波动幅度
 		_Frequency ("Distortion Frequency", Float) = 1		//控制波动频率
 		_InvWaveLength ("Distortion Inverse Wave Length", Float) = 10		//控制波长的倒数
 		_Speed ("Speed", Float) = 0.5		//河流纹理的移动速度
	}
	SubShader {
		// Need to disable batching because of the vertex animation
		Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}
		//DisableBatching:批处理合并所有模型,会使各自的模型空间丢失,我们在进行顶点动画时,需要使用到模型空间的变换,所以需要关闭批处理。

		Pass {
			Tags { "LightMode"="ForwardBase" }
			
			ZWrite Off	//关闭深度写入
			Blend SrcAlpha OneMinusSrcAlpha		//开启混合模式
			Cull Off		//关闭了剔除功能
				
			CGPROGRAM  
			#pragma vertex vert 
			#pragma fragment frag
			
			#include "UnityCG.cginc" 
			
			sampler2D _MainTex;
			float4 _MainTex_ST;
			fixed4 _Color;
			float _Magnitude;
			float _Frequency;
			float _InvWaveLength;
			float _Speed;
			
			struct a2v {
				float4 vertex : POSITION;
				float4 texcoord : TEXCOORD0;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
			};
			
			v2f vert(a2v v) {
				v2f o;
				
				float4 offset;		//顶点的位移量
				offset.yzw = float3(0.0, 0.0, 0.0);		//yzw都为0,
				offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude;
				//书上说,用_Frequency乘时间来模拟频率,为了让不同位置有不同位移,我们对上述结果加上了模型空间的位置分量,×_InvWaveLength来控制波长。_Magnitude来控制幅度。
				//可以看下物体模型的坐标系,上下运动对应着模型空间的x轴,所以我们才更改x轴。

				o.pos = UnityObjectToClipPos(v.vertex + offset);   //加上偏移
				
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);		//计算偏移和缩放
				o.uv +=  float2(0.0, _Time.y * _Speed); //水平移动,如果不是河流只是飘动效果,那这个可以去掉
				
				return o;
			}
			
			fixed4 frag(v2f i) : SV_Target {
				fixed4 c = tex2D(_MainTex, i.uv);
				c.rgb *= _Color.rgb;
				
				return c;
			} 
			
			ENDCG
		}
	}
	FallBack "Transparent/VertexLit"
}

二、广告牌技术

广告牌技术 : 会根据视角方向旋转一个被纹理着色的多边形(通常为简单的四边形,这个多边形就是广告牌),使得多边形看起来好像总是面对着摄像机。

应用:渲染一些烟雾、云朵、闪光效果等等。

广告牌技术的本质就是构造旋转矩阵,广告牌技术使用的三个基向量是表面法线、向上的方向、向右的方向,除此之外还需要一个锚点。锚点不变用来确定位置。

广告牌要按照需求来构建三个相互正交的基向量:

我们首先可以确定一个方向,比如草丛的上方向是不变的(0,1,0),法线方向不变,比如粒子效果,法线方向固定一直指向视角方向,指向上的方向是变化的。
我们假定法线方向固定,用法线方向和向上的方向叉乘计算right方向(此时法线和向上的方向并不垂直,但right方向和这两个其中之一肯定是垂直的),然后我们再用right和法线来计算up方向,这样确定的法线、right、up两两之间都垂直,就构建出了基向量。

感觉书作者的代码有些难理解的地方,研究了好久才懂,在代码中注释了。

Shader "Unity Shaders Book/Chapter 11/Billboard" {
	Properties {
		_MainTex ("Main Tex", 2D) = "white" {}   //广告牌的透明纹理
		_Color ("Color Tint", Color) = (1, 1, 1, 1)		//整体颜色
		_VerticalBillboarding ("Vertical Restraints", Range(0, 1)) = 1		//调整是固定法线还是固定指向上方向,就是控制约束垂直方向的程度。
	}
	SubShader {
		// Need to disable batching because of the vertex animation
		Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}
		//一样还是取消批处理,因为我们需要模型空间来操作(需要得到模型空间的中心锚点)。

		Pass { 
			Tags { "LightMode"="ForwardBase" }
			
			ZWrite Off							//这三个没变化
			Blend SrcAlpha OneMinusSrcAlpha
			Cull Off
		
			CGPROGRAM
			
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			
			sampler2D _MainTex;
			float4 _MainTex_ST;
			fixed4 _Color;
			fixed _VerticalBillboarding;
			
			struct a2v {
				float4 vertex : POSITION;
				float4 texcoord : TEXCOORD0;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
			};
			
			v2f vert (a2v v) {
				v2f o;
				
				float3 center = float3(0, 0, 0);		//确定锚点
				float3 viewer = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos, 1));		//获得模型空间中的视角方向
					
				float3 normalDir = viewer - center;		//法线方向确定
				
				normalDir.y =normalDir.y * _VerticalBillboarding;		//使用_VerticalBillboarding控制垂直方向上的约束度,
				//当_VerticalBillboarding为1时,意味着法线方向固定为视角方向。
				//当_VerticalBillboarding为0时,意味着法线y方向为0,也就是说广告牌的上方向为(0,1,0)

				normalDir = normalize(normalDir);		//进行归一化
				
				float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3(0, 1, 0);		
				//用于防止法线的方向和向上方向平行,

				float3 rightDir = normalize(cross(upDir, normalDir));		//这里是粗略的upDir
				upDir = normalize(cross(normalDir, rightDir));		//重新计算精确的
				
				float3 centerOffs = v.vertex.xyz - center;		//获得原来的偏移
				float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z;	
				
				//也就是说进行一个坐标的转换,原来是普通的x、y、z轴,
				//现在呢,我们把原来的z轴当成了法线方向,y轴当成了upDir,x轴当成了 负的rightDir
				//这里我没有理解错的话,应该是:
				//float3 localPos = center - rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z;
				//因为我们构建的是右手坐标系,所以x轴进行翻转后,才能模拟出坐标轴变换的效果,这样才能根据顶点和锚点的偏移量进行转换。
				//举个例子原来 坐标轴 顶点和锚点的偏移是(1,1,1),那么我们在新的坐标轴就也要有(1,1,1)的偏移,
				//所以就要求我们要使用相同类型的坐标系(指左手右手),计算就是在新的坐标轴方向上加上偏移。

				//之所以书中作者在这里使用的是加法,因为项目中的纹理,x轴的正负并不能影响实际效果,是对称的。
				//我觉得还是要使用减法更加严谨。

				//或许我们可以直接建立左手坐标系的基向量,这样会更好理解。。

				o.pos = UnityObjectToClipPos(float4(localPos, 1));		//转换到裁剪空间
				o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);		//进行便宜缩放的计算

				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target {
				fixed4 c = tex2D (_MainTex, i.uv);		//采样
				c.rgb *= _Color.rgb;
				
				return c;
			}
			
			ENDCG
		}
	} 
	FallBack "Transparent/VertexLit"
}

我们使用的是(Quad),而不可以是(Plane),因为我们的代码是建立在数值摆放的多边形基础上,
我们使用的多边形的定点结构要满足在模型空间下竖直排列。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值