Cg入门27:Fragment shader – 程序纹理水波仿真

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/aa4790139/article/details/50965153
效果:

Quad和Cube 波纹起始点为啥不一样了,返回都是[-0.5,0.5],坐标中心为模型中心。
原因:估计模型网格数据的UV起始点是不一样的

优化方案说明:由1-3逐渐增加,1和2配套使用

优化方案1:开启单独线程,进行uv水波纹理计算


源代码:
Shader "Sbin/WaveAnimShader"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_WaveTex ("Texture",2D) = "white"{}
	}
	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_base v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = v.texcoord.xy;
				return o;
			}

			fixed4 frag (v2f v) : COLOR
			{
				float2 uv = tex2D(_WaveTex, v.uv);
				uv = uv*2-1;//[-1,1]
				uv *=0.25;
				
				v.uv +=uv;

				fixed4 col = tex2D(_MainTex, v.uv);
				return col;
			}
			ENDCG
		}
	}
}

using UnityEngine;
using System.Collections;
using System.Threading;

public class WaveAnim : MonoBehaviour
{
    public int waveWidth = 128;
    public int waveHeight = 128;

    float[,] waveA;
    float[,] waveB;

    bool isRun = true;
    float sleepTime;
    Color[] colorBuffer;

    Texture2D tex_uv;

    void Start()
    {
        waveA = new float[waveWidth, waveHeight];
        waveB = new float[waveWidth, waveHeight];

        tex_uv = new Texture2D(waveWidth, waveHeight);
        colorBuffer = new Color[waveWidth * waveHeight];

        GetComponent<Renderer>().material.SetTexture("_WaveTex", tex_uv);

        Thread th = new Thread(new ThreadStart(ComputeWave));
        th.Start();
    }

    void Update()
    {
        sleepTime = 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 = hit.point;
                //获取点击模型的本地坐标
                pos = transform.worldToLocalMatrix.MultiplyPoint(pos);

                //将本地坐标转成UV坐标
                int w = (int)((pos.x + 0.5) * waveWidth);
                int h = (int)((pos.y + 0.5) * waveHeight);

                PutPop(w, h);
            }
        }
        //ComputeWave();    
    }

    //放置起波点
    private void PutPop(int x, int y)
    {
        int radius = 20;
        float dist;

        for (int i = -radius; i < radius; i++)
        {
            for (int j = -radius; j < radius; j++)
            {
                //控制在uv纹理范围内
                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);
                    }
                }
            }
        }
    }

    /// <summary>
    /// 波纹的UV计算
    /// </summary>
    private void ComputeWave()
    {
        while (isRun)
        {
            for (int w = 1; w < waveWidth - 1; w++)
            {
                for (int h = 1; h < waveHeight - 1; h++)
                {
                    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];

                    waveB[w, h] = waveB[w, h] > 1 ? 1 : waveB[w, h];
                    waveB[w, h] = waveB[w, h] < -1 ? -1 : waveB[w, h];

                    //控制范围[-1,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_v / 2 + 0.5f;
                    float g = offset_u / 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.025f;
                }
            }

            //tex_uv.Apply();

            float[,] temp = waveA;
            waveA = waveB;
            waveB = temp;

            Thread.Sleep((int)sleepTime);
        }
    }

    void OnDestory()
    {
        isRun = false;
    }
}



优化方案2:关闭垂直同步
打开:Edit->Project Setting->Quality,然后选择V Sysnc Count 为Don't Sync

优化方案3:compute Shader 利用GUP才进行计算,GUP计算特点:并行处理效果高
compute Shader  不了解

猜你喜欢

转载自blog.csdn.net/aa4790139/article/details/50965153