三、效果实现:8、水(1)波浪起伏

一、首先建立一个最基本的最简单的Shader
Shader "Customer/Water01"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            Name "FORWARD"
            Tags 
            {
                "LightMode"="ForwardBase"
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0
            // 输入结构
            struct appdata
            {
                float4 vertex : POSITION;
            };
            // 输出结构
            struct v2f
            {
                float4 pos : SV_POSITION;   // 由模型顶点信息换算而来的顶点屏幕位置
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            // 输入结构>>>顶点Shader>>>输出结构
            v2f vert (appdata v)
            {
                v2f o = (v2f)0;// 新建一个输出结构
                o.pos = UnityObjectToClipPos(v.vertex);// 变换顶点信息 并将其塞给输出结构
                return o;   // 将输出结构 输出
            }
            // 输出结构>>>像素
            fixed4 frag (v2f i) : COLOR
            {
                return float4(0.0, 1.0, 0.0, 1.0);
            }
            ENDCG
        }
    }
}

这时候场景中shader的输出是绿色的。

二、分析做流水的思路

首先是要达到的效果:

  • 可以设置水的颜色。比如河流多是浅绿色,海和池塘多事蓝色。
  • 波浪效果
    思路:UV顶点位置随时间做波形变化
  • 水的透明效果
    思路:对背景采样。
  • 可以设置波浪形状。比如海浪,河浪,溪流波纹,池塘波纹等。
    思路:采样波浪纹理。
  • 有泡沫
    思路:采样噪声
  • 波纹扰动
    思路:采样波纹纹理,并让波纹纹理流动起来
  • 水的倒影(折射)
  • 水的菲尼尔现象(反射)
  • 岸边的边界线或者和物体接触的边界线
  • 水的浮力(深度计算,暂时不做)

1、水的颜色这个很好做,开放一个可以设置颜色的参数即可。
2、波浪效果。
如果简单得用一个正弦波表示波形,那么波形就会显得比较单调,更好的做法就是采样一张波形纹理法线,用颜色的深度表示作为波浪的高度。然后让高度值随时间做一个波形变化即可达成。这里引出一个问题就是,波形能变动了,但是变动后的波形的光照效果如何做。这里需要用到的原理可以参照Unity自带的凹凸漫反射Shader做法。放到第二篇去做像素shader的内容。

Shader "Customer/Water01"
{
    Properties
    {
        _Color("Color水颜色", color) = (0,0,0.8,0.5)
        _WaveNormalMap("Wave Normal Map", 2D) = "bump"{}
        _WaveHeight("Wave Height",Range(0,1)) = 0.1
        _WaveNormalScale("Wave Scale", float) = 10.0
        _WaveNormalSpeed("Wave Speed", float) = 1.0
        _waveNumber("Wave Number",float) = 4
        _WaveTex("Wave Tex", 2D) = "black" {}
        _BigWaveSpeed("Big Wave Speed",float) = 10
        _BigWaveHeight("Big Wave Height",float) = 0.5
        _BigWaveNumber("Big Wave Number",float) = 10
    }
    SubShader
    {
        Tags
        {
            "Queue" = "Transparent"
            "RenderType" = "Transparent"
        }
        GrabPass{
            "_GrabPassTex"
        }
        LOD 100

        Pass
        {
            Name "FORWARD"
            Tags 
            {
                "LightMode"="ForwardBase"
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
             #include "Lighting.cginc" 
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0

            float4 _Color;
            sampler2D _WaveNormalMap;
            fixed _WaveHeight;
            float _WaveNormalScale;
            fixed _WaveNormalSpeed;
            fixed _waveNumber;

            fixed _dividHeight;
            fixed _BigWaveSpeed;
            fixed _BigWaveHeight;
            fixed _BigWaveNumber;

            // 输入结构
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal:NORMAL;//法线通常都是必须的
                float4 tangent : TANGENT;
                float3 color:COLOR0;
            };
            // 输出结构
            struct v2f
            {
                float4 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;   // 由模型顶点信息换算而来的顶点屏幕位置
                float depth : TEXCOORD2;
                float3 normal:NORMAL;//法线通常都是必须的
                float4 lightDir_Tangent:TEXCOORD5;
                float4 screenuv:TEXCOORD1;
                float3 viewDir:TEXCOORD3;
                float4 vertex_Local : TEXCOORD4;
                float3 color:COLOR0;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            // 输入结构>>>顶点Shader>>>输出结构
            v2f vert (appdata v)
            {
                v2f o;
                UNITY_INITIALIZE_OUTPUT(v2f, o);
                //获取自身深度值
                COMPUTE_EYEDEPTH(o.depth);

                float2 flow = float2(_Time.x*_WaveNormalSpeed, _Time.z*1.215*_WaveNormalSpeed);

                fixed3 n = UnpackNormal(tex2Dlod(_WaveNormalMap, float4(v.uv.xy*_WaveNormalScale + flow, 0, 0))).xyz;

                float height = 0;

                fixed wavebevel = 5;

                fixed attenuation = (1.0 - v.uv.y);

                fixed b = 0.8;
                fixed x = v.uv.y + b * sin(v.uv.y);
                if (v.vertex.y > _dividHeight)
                {
                    height = (cos(x*_BigWaveNumber - _Time.z*_BigWaveSpeed + v.uv.x*wavebevel) + 1)*0.5*_BigWaveHeight*attenuation;
                    height += (cos(x*_BigWaveNumber - _Time.z*_BigWaveSpeed + (1.0 - v.uv.x)*wavebevel) + 1)*0.5*_BigWaveHeight*attenuation;
                }
                v.vertex.y = v.vertex.y + n * _WaveHeight + height;

                if (v.vertex.y > _dividHeight)
                    v.vertex.z -= height * 0.1;

                o.vertex = UnityObjectToClipPos(v.vertex);
                                _FOG(o, o.vertex);
                return o;
            }
            // 输出结构>>>像素
            fixed4 frag (v2f i) : COLOR
            {
                float4 finalCol = _Color;
                //return finalCol;
                return float4(0.0, 1.0, 0.0, 1.0);
            }
            ENDCG
        }
    }
}

其中采用噪声纹理产生高度的代码是这句。
fixed3 n = UnpackNormal(tex2Dlod(_WaveNormalMap, float4(v.uv.xy*_WaveNormalScale + flow, 0, 0))).xyz;
(注:DepthMap纹理的采样通常用tex2Dlod)

float2 flow = float2(_Time.x_WaveNormalSpeed, _Time.z1.215_WaveNormalSpeed);
是为了让采样到的纹理值能随时间变动。
另外不用UnpackNormal这个反映射方法,用下面这种写法也是可以的:
//float tempN = tex2Dlod(_WaveNormalMap, float4(v.uv.xy
_WaveNormalScale + flow, 0, 0)).g;这种写法也
//v.vertex.y = v.vertex.y + tempN * _WaveHeight + height;

通过采用深度,并做随时间上的变化,已经有了波浪的效果。波形随时间变化部分参照网上其他人的经验做法。


1.gif

波形的一些控制参数


image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容