1. 程式人生 > >【Unity】【Shader】寫一個初步的水波模擬Gerstner Waves

【Unity】【Shader】寫一個初步的水波模擬Gerstner Waves

最近看《GPU Gems》,第一章講解了自然中水波的模擬:https://developer.nvidia.com/gpugems/GPUGems/gpugems_ch01.html,其中提到了廣泛使用(沒看之前我也是不懂哈哈)的Gerstner Waves,在正弦波的基礎上,這個函式能模擬出水波的尖銳波峰效果

下面是我初步模擬出的結果


數學及物理理論可以自己看網站,這邊只需瞭解一點:水波是由N個單一的波疊加形成的,每個點的振幅都需要做高度疊加。

直接上函式及實現:


計算某一個點的水波的高度

其中,x,y即水平座標(注意:如果使用物體空間座標,系統自帶的Panel的話,水平方向的軸其實是x跟z,豎直方向是y);t即時間,我們使用自帶時間變數_Time.x即即可;

Qi:波的陡度引數,0得到正弦波,取 1 / wi × Ai 則為尖銳的波。

Ai:波的振幅

Di:波方向。對於單向波,方向是固定的。對於圓形波,每個點的方向都需要獨立計算。 

Di.x ;Di.y 即方向的x分量或y分量

ωi:控制波長的引數

Di.(x,y):方向點乘座標(x,y)

φi:波的初相。這邊控制波的抖動頻率。


計演算法線,引數意義同上

知道了這些,其實就明白怎麼做了。我們取一個Panel,由於要計算光照,使用SurfaceShader比較方便,加入半透明支援

Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
以及
#pragma surface surf Standard  vertex:vert alpha:fade  

下面的完整的Shader,我使用了3個圓形波的疊加:

Shader "Custom/WaveGPUSurface" {
	Properties {
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" {}
		//_Glossiness ("Smoothness", Range(0,1)) = 0.5
		//_Metallic ("Metallic", Range(0,1)) = 0.0
		_RefTxu("Ref", 2D) = "white"{}

		_SunPower("Sun Power", Float) = 1.0

		_SunDir("Sun Dir", Vector) = (1,1,1,1)
		_SunColor("Sun Color", Color) = (1,1,1,1)
		//(A,W,Q,Steep)
		_Wave1("Wave1",Vector) = (1,1,0.5,0.1)
		_Wave2("Wave1",Vector) = (1,1,0.5,0.1)
		_Wave3("Wave1",Vector) = (1,1,0.5,0.1)
		_StartX("startX", Float) = 0

		_C1("WaveC1", Vector) = (1,1,1,1)
		_C2("WaveC2", Vector) = (1,1,1,1)
		_C3("WaveC3", Vector) = (1,1,1,1)
	}
	SubShader {
		Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
			LOD 200
			CGPROGRAM
			// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard  vertex:vert alpha:fade  

			// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0

		sampler2D _MainTex;
		sampler2D _RefTxu;

		struct Input {
			float2 uv_MainTex;
			float3 normal;
			float3 worldPos;
		};

		half _Glossiness;
		half _Metallic;
		fixed4 _Color;

		float _SunPower;
		float4 _SunDir;
		float4 _SunColor;
		float4 _Wave1;
		float4 _Wave2;
		float4 _Wave3;
		float _StartX;
		float4 _C1;
		float4 _C2;
		float4 _C3;

		float4 DisVec(float4 v, fixed i)
		{

			if (i == 1)
			{
				return normalize(v - _C1);
			}
			else if (i == 2)
			{
				return normalize(v - _C2);
			}
			else if (i == 3)
			{
				return normalize(v - _C3);
			}

		}

		float DiDotXY(float4 v, fixed i)
		{
			return dot(DisVec(v, i), v);
		}

		float4 GerstnerWave(float4 v, float t, out float3 normal)
		{
			fixed A = 0;//振幅
			fixed W = 1;//角速度
			fixed Q = 2;//初相
			fixed Step = 3;//陡度控制

			float CT1 = cos(_Wave1[W] * DiDotXY(v, 1) + _Wave1[Q] * t);
			float CT2 = cos(_Wave2[W] * DiDotXY(v, 2) + _Wave2[Q] * t);
			float CT3 = cos(_Wave3[W] * DiDotXY(v, 3) + _Wave3[Q] * t);

			float xT = v.x + _Wave1[Step] * _Wave1[A] * DisVec(v, 1).x * CT1
				+ _Wave2[Step] * _Wave2[A] * DisVec(v, 2).x * CT2
				+ _Wave3[Step] * _Wave3[A] * DisVec(v, 3).x * CT3;

			float yT = _Wave1[A] * sin(_Wave1[W] * DiDotXY(v, 1) + _Wave1[Q] * t)
				+ _Wave2[A] * sin(_Wave2[W] * DiDotXY(v, 2) + _Wave2[Q] * t)
				+ _Wave3[A] * sin(_Wave3[W] * DiDotXY(v, 3) + _Wave3[Q] * t);

			float zT = v.z + _Wave1[Step] * _Wave1[A] * DisVec(v, 1).z * CT1
				+ _Wave2[Step] * _Wave2[A] * DisVec(v, 2).z * CT2
				+ _Wave3[Step] * _Wave3[A] * DisVec(v, 3).z * CT3;

			float4 P = float4(xT, yT, zT, v.w);

			//法線計算
			float DP1 = dot(DisVec(v, 1), P);
			float DP2 = dot(DisVec(v, 2), P);
			float DP3 = dot(DisVec(v, 3), P);

			float C1 = cos(_Wave1[W] * DP1 + _Wave1[Q] * t);
			float C2 = cos(_Wave2[W] * DP2 + _Wave2[Q] * t);
			float C3 = cos(_Wave3[W] * DP3 + _Wave3[Q] * t);

			float nXT = -1 * (DisVec(v, 1).x * _Wave1[W] * _Wave1[A] * C1)
				- (DisVec(v, 2).x * _Wave2[W] * _Wave2[A] * C2)
				- (DisVec(v, 3).x * _Wave3[W] * _Wave3[A] * C3);

			float nYT = 1 - _Wave1[Step] * _Wave1[W] * _Wave1[A] * sin(_Wave1[W] * DP1 + _Wave1[Q] * t)
				- _Wave2[Step] * _Wave2[W] * _Wave2[A] * sin(_Wave2[W] * DP2 + _Wave2[Q] * t)
				- _Wave3[Step] * _Wave3[W] * _Wave3[A] * sin(_Wave3[W] * DP3 + _Wave3[Q] * t);

			float nZT = -1 * (DisVec(v, 1).z * _Wave1[W] * _Wave1[A] * C1)
				- (DisVec(v, 2).z * _Wave2[W] * _Wave2[A] * C2)
				- (DisVec(v, 3).z * _Wave3[W] * _Wave3[A] * C3);

			normal = float3(nXT, nYT, nZT);

			return P;
		}

		float fresnel(float3 V, float3 N)
		{

			half NdotL = max(dot(V, N), 0.0);
			half fresnelBias = 0.4;
			half fresnelPow = 5.0;
			fresnelPow = _SunPower;

			half facing = (1.0 - NdotL);
			return max(fresnelBias + (1 - fresnelBias) * pow(facing, fresnelPow), 0.0);
		}

		float3 computeSunColor(float3 V, float3 N)
		{
			float3 HalfVector = normalize(abs(V + (_SunDir)));

			return _SunColor * pow(abs(dot(HalfVector, N)), _SunPower) * _SunColor.a;
		}

		void vert(inout appdata_full v, out Input o)
		{
			float3 normal = float3(1,1,1);
			v.vertex = GerstnerWave(v.vertex, _Time.x, normal);
			UNITY_INITIALIZE_OUTPUT(Input, o);
			o.normal = normal;
		}

		void surf(Input IN, inout SurfaceOutputStandard o) {

			fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;

			float3 N = IN.normal;

			o.Albedo = c.rgb;
			o.Alpha = _Color.a;
			o.Normal = N;

			float3 vDir = normalize(_WorldSpaceCameraPos - IN.worldPos);

			float fr = fresnel(vDir, N);

			//float3 skyColor = texCUBE(_ReflMap, WorldReflectionVector(IN, o.Normal)).rgb * _ReflecTivity;//* _ReflecTivity;

			float3 sunColor = computeSunColor(vDir, N);

			o.Emission = fr * c + sunColor;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

其他效果有待加強~希望能在實踐中幫到大家。有錯誤地方歡迎指出:)

相關推薦

UnityShader一個初步水波模擬Gerstner Waves

最近看《GPU Gems》,第一章講解了自然中水波的模擬:https://developer.nvidia.com/gpugems/GPUGems/gpugems_ch01.html,其中提到了廣泛使用(沒看之前我也是不懂哈哈)的Gerstner Waves,在正弦波的基礎

教程如何正確的一個Lemon/Cena的SPJ(special judge)

Special Judge:當正確的輸出結果不唯一的時候需要的自定義校驗器 首先有個框架 #include<fstream> ifstream fin,fout,fstd ofstream fscore,freport; double J

區塊鏈從零開始一個區塊鏈遊戲--水果機

機器環境 win10 nodev8.9.4 npm install -g truffle npm install -g ganache-cli Github地址 效果 初始化專

Unity UGUI有趣應用 (三)-------------------- 揹包系統(上)之簡易單頁揹包系統及檢索功能的實現

揹包系統,無論是遊戲還是應用,都是常常見到的功能,其作用及重要性不用我多說,玩過遊戲的朋友都應該明白。 在Unity中實現一個簡易的揹包系統其實並不是太過複雜的事。本文要實現的是一個帶檢索功能的揹包系統。先看一下我們要完成的效果 。由於上傳的gif圖不能大於5M,所以錄製

unity系統模組開發Unity5.5.2UI打包AssetBundle

之前已經有幾篇文章寫打包AssetBundle,但畢竟沒有實際在專案中寫過都寫的比較淺。 剛好最近專案更新Unity5.5.2就順便由我來更新ui打包流程 這裡就把這次的經驗寫一下 這裡還是稍微解釋一下打包的基本目的: 打包ui就是把你做的介面打包出來成assetbund

Unity 3D 遊戲開發Unity3D 入門

一. 工作區域詳解1. Scence檢視 (場景設計面板)scence檢視簡介 : 展示建立的遊戲物件, 可以對所有的遊戲物件進行 移動, 操作 和 放置;-- 示例 : 建立一個球體, 控制攝像機,

unity編輯器拓展使用指令碼新增Prefab到場景中

 有時候想自動將預製新增到場景中,但是又不想破壞預製的連結關係,這時候可以使用PrefabUtility類進行操作。 1、使用AssetDatabase.GetAssetPath獲取預製路徑 fore

Unity實用小方法判斷貼圖是否為透明貼圖

private bool JudgeTransparentPic(TextureFormat format) { //所有貼圖格式帶alpha通道的格式,帶alpha通

Unity學習第二天滾球遊戲學習(Roll A Ball)

基本流程 ** 0、在基礎的地面上會有一個小球,通過控制小球的滾動,吞吃地面上的一些小塊。 1、建立基礎場景,包括地面,主角,觸碰小塊。 ① 通過材質設定修改相關物體的顏色/光滑度等顯示。 ② 重複出現的遊戲物體最好設定成prefab,以方便修改。

Unity實用小方法開啟遊戲時播放一段動畫

// 不顯示任何視訊控制元件,當點選螢幕發生輸入之後會跳過動畫的播放 // 一般遊戲中的開場動畫使用這種播放方式   Handheld.PlayFullScreenMovie("test.mp4"

涼鞋:我所理解的框架 Unity 遊戲框架搭建

前言 架構和框架這些概念聽起來很遙遠,讓很多初學者不明覺厲。會產生“等自己技術牛逼了再去做架構或者搭建框架”這樣的想法。在這裡筆者可以很肯定地告訴大家,初學者是完全可以去做這些事情的。 初識架構和框架 架構和框架是非常接地氣的,離我們其實並不遙遠。 什麼是架構? 架構是一個約定,一個規則,一個大家都懂得遵守

山科java實驗4-3 一個彩票的模擬程式:30選7。

寫一個彩票的模擬程式:30選7。隨機(1~30之間)生成7個隨機數,注意不能重複。然後從鍵盤輸入7個數,對比7個數是否與隨機數有相同的。最後顯示“中了幾個號”。同時,如果中了7個號,顯示一等獎;如果中了6個號,顯示二等獎;如果中了5個號,顯示三等獎。要求:首先在註釋中寫出程式的實現思想,特別是程

JAVA實驗四:一個彩票的模擬程式

題目 寫一個彩票的模擬程式:30選7。隨機(1~30之間)生成7個隨機數,注意不能重複。然後從鍵盤輸入7個數,對比7個數是否與隨機數有相同的。最後顯示“中了幾個號”。同時,如果中了7個號,顯示一等獎;如果中了6個號,顯示二等獎;如果中了5個號,顯示三等獎。要求:首先在註釋中寫出程式的實現思想

Unity ShadersMobile Shader Adjustment—— 什麽是高效的Shader

ria 類型 告訴 菜單 inline 反射 當我 自己的 html http://blog.csdn.net/candycat1992/article/details/38358773 本系列主要參考《Unity Shaders and Effects Cookboo

Unity Shader--入門知識點

一個 個數 精確 option cas 反射 性能 hit nor 著色器聲明(“名字”)Shader "ShaderDiffuseExample" { 一、屬性定義(作用:外部傳入參數) 屬性定義語法:PropName("DisplayName",PropType) =

Unity Shader--- 準確認識SubShader語義塊結構、渲染狀態設定、Tags標簽

strong blend 渲染引擎 引擎 語法 always 加載 setup 使用 一【SubShader】   每個UnityShader文件可以包含多個SubShader語義塊,但至少要有一個。當Unity需要加載這個UnityShader時,Unity會掃描所有的S

Unity Shader---基礎光照

【Unity Shader】---基礎光照

一個通用的事件偵聽器函數

else arguments handle 加載完成 || document 完成 amp 能力 // event(事件)工具集,來源:github.com/markyun markyun.Event = { // 頁面加載完成後

python學習使用python一個2048小遊戲

ast stc 遊戲 多少 wan nbsp 小遊戲 效果 參考 個人博客:jerwang.cn 沒有參考其他代碼,效果圖: 話不多少,源代碼: https://github.com/jerustc/Python/blob/master/2048.py【python學

Unity-ShaderLab入門 Shader是什麽?

shade 一個 片元 fragment 時也 器) 變量 時間 gin ShaderLab 是Unity3d自己封裝的一個調用CG/HLSL/GLSL的接口。 Shader相關文件(擴展名): shader - 著色器的主要文件 cg/cginc - 著色器的公用文