一個滑鼠點選水波紋理shader
阿新 • • 發佈:2019-01-01
一張圖片,通過滑鼠點選產生水波紋理,shader比較簡單,演算法主要在C#那邊,多執行緒優化計算
用下面shader建立一個材質,建立一個面片或Cube並掛上下面C#指令碼,設定圖片畫素,預設是256*256,賦值材質圖片紋理,執行,點選滑鼠即可看到效果
shader
Shader "Zon/WaveTexture" { Properties { _MainTex ("水波紋理", 2D) = "" {} } SubShader { pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; sampler2D _WaveTex; struct v2f { float4 pos:POSITION; float2 uv:TEXCOORD0; }; v2f vert(appdata_full v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord.xy; return o; } fixed4 frag (v2f IN) : COLOR { float2 uv = tex2D(_WaveTex, IN.uv).xy; uv = uv * 2 - 1; //把0~1轉成-1~1 uv *= 0.025; IN.uv += uv; fixed4 color = tex2D(_MainTex, IN.uv); return color; } ENDCG } } }
C#指令碼
using UnityEngine; using System.Collections; using System.Threading; public class WaveTexture : MonoBehaviour { public int waveWidth; public int waveHeight; float[,] waveA; float[,] waveB; Color[] colorBuffer; Texture2D tex_uv; bool isRun = true; int sleepTime; // Use this for initialization void Start () { waveA = new float[waveWidth, waveHeight]; waveB = new float[waveWidth, waveHeight]; colorBuffer = new Color[waveWidth * waveHeight]; tex_uv = new Texture2D (waveWidth, waveHeight); GetComponent<Renderer> ().material.SetTexture ("_WaveTex", tex_uv); Thread th = new Thread (new ThreadStart(ComputeWave)); th.Start (); //Putpop (); //PutDrop(64,64); } // Update is called once per frame void Update () { sleepTime = (int)(Time.deltaTime * 1000); tex_uv.SetPixels (colorBuffer); tex_uv.Apply (); if (Input.GetMouseButton(0)) { RaycastHit hit; Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition); if (Physics.Raycast (ray, out hit)) { Vector3 pos = transform.worldToLocalMatrix.MultiplyPoint(hit.point);//把世界座標轉換成圖片畫素座標 //Debug.Log(pos);//pos = -0.5 ~ 0.5 int w = (int)((pos.x + 0.5) * waveWidth); int h = (int)((pos.y + 0.5) * waveHeight); PutDrop (w, h); } } //ComputeWave (); } void Putpop() { //能量置1 waveA [waveWidth / 2, waveHeight / 2] = 1;//中間點 waveA [waveWidth / 2 - 1, waveHeight / 2] = 1;//左 waveA [waveWidth / 2 + 1, waveHeight / 2] = 1;//右 waveA [waveWidth / 2, waveHeight / 2 - 1] = 1;//下 waveA [waveWidth / 2, waveHeight / 2 + 1] = 1;//上 waveA [waveWidth / 2 - 1, waveHeight / 2 - 1] = 1;//左下 waveA [waveWidth / 2 - 1, waveHeight / 2 + 1] = 1;//左上 waveA [waveWidth / 2 + 1, waveHeight / 2 - 1] = 1;//右下 waveA [waveWidth / 2 + 1, waveHeight / 2 + 1] = 1;//右上 } void PutDrop(int x, int y) { int radius = 20; float dist; for (int i = -radius; i <= radius; i++) { for (int j = -radius; j <= radius; j++) { if (((x + i >= 0) && (x + i < waveWidth - 1)) && ((y + j >= 0) && (y + j < waveHeight - 1))) { dist = Mathf.Sqrt (i * i + j * j); if (dist < radius) waveA [x + i, y + j] = Mathf.Cos (dist * Mathf.PI / radius); } } } } void ComputeWave() { while (isRun) { for (int w = 1; w < waveWidth - 1; w++) { for (int h = 1; h < waveHeight - 1; h++) { //8個方向計算 waveB [w, h] = (waveA [w - 1, h] + waveA [w + 1, h] + waveA [w, h - 1] + waveA [w, h + 1] + waveA [w - 1, h - 1] + waveA [w + 1, h - 1] + waveA [w - 1, h + 1] + waveA [w + 1, h + 1]) / 4 - waveB [w, h]; //能量限制 float value = waveB [w, h]; if (value > 1) waveB [w, h] = 1; if (value < -1) waveB [w, h] = -1; float offset_u = (waveB [w - 1, h] - waveB [w + 1, h]) / 2; float offset_v = (waveB [w, h - 1] - waveB [w, h + 1]) / 2; float r = offset_u / 2 + 0.5f; float g = offset_v / 2 + 0.5f; //tex_uv.SetPixel (w, h, new Color (r, g, 0)); colorBuffer [w + waveWidth * h] = new Color (r, g, 0); waveB [w, h] -= waveB [w, h] * 0.0025f;//能量衰減計算 } } //tex_uv.Apply (); float[,] temp = waveA; waveA = waveB; waveB = temp; Thread.Sleep (sleepTime); } } void OnDestroy() { isRun = false; } }