1. 程式人生 > >Unity&Shader基礎篇-常用函式的使用與案例

Unity&Shader基礎篇-常用函式的使用與案例

Shader "Unlit/Chapter6-Animations"
{
	Properties
	{
		_SpeedY("第一部分的速度",Range(0,3)) = 1
		_Amplitude("第二部分的振幅",Range(0,1)) = 0.8
		_RSpeedX("圓周運動X方向的速度",Range(0,10)) = 5
		_RSpeedY("圓周運動Y方向的速度",Range(0,10)) = 5
		_RAmplitudeY("圓周運動Y方向的幅度",Range(0,1)) = 0.1
		_RAmplitudeX("圓周運動X方向的幅度",Range(0,1)) = 0.1
		_ChainAnimSpeed("鏈條運動的速度",Range(0,10)) = 5
		_ChainAnimRotaSpeed("鏈條運動的旋轉速度",Range(0,10)) = 3
		_JumpSpeed("跳躍運動的速度",Range(0,10))=2

	}
	SubShader
	{
		// No culling or depth
		Cull Off ZWrite Off ZTest Always
		CGINCLUDE
		#define PI 3.1415926

		// 通過函式來畫網格
		float coordinateGrid(float2 r) {
		float3 axisCol = float3(0.0, 0.0, 1.0);
		float3 gridCol = float3(0.5, 0.5, 0.5);
		float ret = 0.0;

		// 畫網線
		const float tickWidth = 0.1;
		for (float i = -2.0; i<2.0; i += tickWidth) {
			ret += 1.0 - smoothstep(0.0, 0.008, abs(r.x - i));
			ret += 1.0 - smoothstep(0.0, 0.008, abs(r.y - i));
		}

		// 畫座標軸
		ret += 1.0 - smoothstep(0.001, 0.015, abs(r.x));
		ret += 1.0 - smoothstep(0.001, 0.015, abs(r.y));
		return ret;
	}

		// 圓內的返回1
		float disk(float2 r, float2 center, float radius) 
		{
			return 1.0 - smoothstep(radius - 0.005, radius + 0.005, length(r - center));
		}

	// 在長方形內返回1
		float rectangle(float2 r, float2 bottomLeft, float2 topRight) 
		{
			float ret;
			float d = 0.005;
			ret = smoothstep(bottomLeft.x - d, bottomLeft.x + d, r.x);
			ret *= smoothstep(bottomLeft.y - d, bottomLeft.y + d, r.y);
			ret *= 1.0 - smoothstep(topRight.y - d, topRight.y + d, r.y);
			ret *= 1.0 - smoothstep(topRight.x - d, topRight.x + d, r.x);
			return ret;
		}
		float mod(float  a, float  b) 
		{ 
			return a - b*floor(a / b); 
		}
	ENDCG


	Pass
	{
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag

		#include "UnityCG.cginc"
		uniform float _Amplitude;
		uniform float _SpeedY;
		uniform float _RSpeedX;
		uniform float _RSpeedY;
		uniform float _RAmplitudeY;
		uniform float _RAmplitudeX;
		uniform float _ChainAnimSpeed;
		uniform float _ChainAnimRotaSpeed;
		uniform float _JumpSpeed;

		struct appdata
		{
			float4 vertex : POSITION;
			float2 uv : TEXCOORD0;
		};

		struct v2f
		{
			float2 uv : TEXCOORD0;
			float4 vertex : SV_POSITION;
		};

		v2f vert(appdata v)
		{
			v2f o;
			o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
			o.uv = v.uv;
			o.uv.y = 1 - o.uv.y;
			return o;
		}

	//動畫,使用到了Unity內建的變數_Time 四維向量(t/20, t, t*2, t*3),_Time.y=t;
	fixed4 frag(v2f i) : SV_Target
	{
		float2 r = 2.0 * (i.uv - 0.5);
		float aspectRatio = _ScreenParams.x / _ScreenParams.y;
		r.x *= aspectRatio;

		fixed3 bgCol = float3(1.0, 1.0, 1.0); // white

		fixed3 col1 = float3(0.216, 0.471, 0.698); // blue
		fixed3 col2 = float3(1.00, 0.329, 0.298); // red
		fixed3 col3 = float3(0.867, 0.910, 0.247); // yellow

		fixed3 ret;
		ret = bgCol;

		

		//第一部分,迴圈向上運動
		if (i.uv.x < 1.0 / 5.0) 
		{
			float2 q = r + float2(aspectRatio*4.0 / 5.0, 0);

			ret = fixed3(0.3, 0.3, 0.3);
			//unity內建的時間向量
			float y = _SpeedY*_Time.y;

			//使得y在-1到1之間
			y = mod(y,2.0) - 1.0;
			ret = lerp(ret, col1, disk(q, float2(0.0, y), 0.1));
		}
		//第二部分,迴圈來回並縮放運動
		else if (i.uv.x < 2.0 / 5.0) 
		{
			float2 q = r + float2(aspectRatio*2.0 / 5.0, 0);
			ret = fixed3(0.4, 0.4, 0.4);
			//新增振幅
			float y = _Amplitude * sin(0.5*_Time.y* 2.0 * PI);
			float radius = 0.15 + 0.05 * sin(_Time.y * 8.0);
			ret = lerp(ret, col1, disk(q, float2(0.0, y), radius));
		}
		//第三部分,圓周運動並變換顏色
		else if (i.uv.x < 3.0 / 5.0) 
		{
			float2 q = r + float2(aspectRatio * 0 / 5.0, 0);
			ret = float3(0.5, 0.5, 0.5);

			float x = _RAmplitudeX*cos(_Time.y*_RSpeedX);
			float y = _RAmplitudeY*sin(_Time.y*_RSpeedY);
			float radius = 0.2 + 0.1*sin(_Time.y*2.0);
			fixed3 color = lerp(col1, col2, sin(_Time.y)*0.5 + 0.5);
			ret = lerp(ret, color, rectangle(q, float2(x - 0.1, y - 0.1), float2(x + 0.1, y + 0.1)));
		}
		//第四部分,鏈條運動
		else if (i.uv.x < 4.0 / 5.0) 
		{
			float2 q = r + float2(-aspectRatio*2.0 / 5.0, 0);
			ret = float3(0.4, 0.4, 0.4);

			for (float i = -1.0; i<1.0; i += 0.2)
			{
				float x = 0.2 * cos(_Time.y*_ChainAnimSpeed + i*PI);
				float y = i;

				float2 s = q - float2(x, y);
				float angle = _Time.y * _ChainAnimRotaSpeed + i;
				float2x2 rot = float2x2(cos(angle), -sin(angle),
					sin(angle),  cos(angle));
				s = mul(rot, s);
				ret = lerp(ret, col1, rectangle(s, float2(-0.06, -0.06), float2(0.06, 0.06)));
			}
		}
		//第五部分,跳躍運動
		else if (i.uv.x < 5.0 / 5.0) 
		{
			float2 q = r + float2(-aspectRatio*4.0 / 5.0, 0);
			ret = float3(0.3, 0.3, 0.3);

			float speed = _JumpSpeed;
			float t = _Time.y * speed;
			float stopEveryAngle = PI / 2.0;
			float stopRatio = 0.5;
			//floor(x):返回小於等於t的最大整數     frac(x):返回x的小數部分
			float t1 = (floor(t) + smoothstep(0.0, 1.0 - stopRatio, frac(t)))*stopEveryAngle;

			float x = -0.2*cos(t1);
			float y = 0.3 * sin(t1);
			float dx = 0.1 + 0.03 * sin(t*10.0);
			float dy = 0.1 + 0.03 * sin(t*10.0 + PI);
			ret = lerp(ret, col1, rectangle(q, float2(x - dx, y - dy), float2(x + dx, y + dy)));


		}


		fixed3 pixel = ret;
		return fixed4(pixel, 1.0);
	}


		ENDCG
	}
	}
}
程式碼中使用到了“_Time”變數,這個是Unity內建的四維向量,(t/20,t,t*2,t*3)因此“_Time.y=t”即獲得系統的渲染的單位時間。
2、等離子流動效果,效果圖如圖所示: