【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" }
其他效果有待加強~希望能在實踐中幫到大家。有錯誤地方歡迎指出:)
相關推薦
【Unity】【Shader】寫一個初步的水波模擬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 Shaders】Mobile 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 - 著色器的公用文