unity中一个类似纪念碑谷里的三角图形组成的海面效果

10 篇文章 1 订阅

想要实现一个纪念碑谷中的海面效果,最初的设想是在vertex中,修改顶点坐标来实现,而且也实现出来了,代码:

v2f vert(a2v v) {
                v2f o;
                float4 offset;
                offset.xyzw = float4(0,0,0,0);

                float sinx = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength);
                offset.y = sinx * _Magnitude;

                o.pos = UnityObjectToClipPos(v.vertex+offset);

                o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);

                o.norm = sinx;

                o.worldPos =  mul(unity_ObjectToWorld,v.vertex).xyz;

                o.sinx = sinx;

                return o;
            }


但是效果看上去总是怪怪的:



想了老半天哪里怪,为啥跟想象中的不一样呢....我们看一下纪念碑谷中的效果:


这差距也太大了吧...很明显,没有光效啊,那好,加上光效看看效果:


结果还是一样,这是因为我们虽然处理的光,但是顶点的法线却并没有改变,不管顶点怎么变,亮度都是不会改变的,所以我们还需要计算一下法线,法线的计算我们要放在geometry中进行:

[maxvertexcount(3)]
            void geom(triangle v2f IN[3], inout TriangleStream<v2f> triStream)
            {
                float3 v0 = IN[0].pos.xyz;
                float3 v1 = IN[1].pos.xyz;
                float3 v2 = IN[2].pos.xyz;

                float3 vn = normalize(cross(v1 - v0, v2 - v0));

                vn = UnityObjectToWorldNormal(vn);

                v2f OUT;
                OUT.pos = IN[0].pos;
                OUT.worldNormal = vn;
                OUT.worldPos = IN[0].worldPos;
                OUT.uv = IN[0].uv;
                triStream.Append(OUT);

                OUT.pos = IN[1].pos;
                OUT.worldNormal = vn;
                OUT.worldPos = IN[1].worldPos;
                OUT.uv = IN[1].uv;
                triStream.Append(OUT);

                OUT.pos = IN[2].pos;
                OUT.worldNormal = vn;
                OUT.worldPos = IN[2].worldPos;
                OUT.uv = IN[2].uv;
                triStream.Append(OUT);

            }
normalize(cross(v1 - v0, v2 - v0));这里对三角形的两条边做叉积,就得到了平面的法线。

看看现在的效果:


这次有点接近了,但是没有变化,我们加点变化来看看,在vert中加上如下2句,对顶点的xz坐标也加上位移:

                offset.x =  sin(_Frequency * _Time.y + v.vertex.x);
                offset.z =  sin(_Frequency * _Time.y  + v.vertex.z);
再来看看:



总算是差不多了,想要达到更好的效果还需要进行一些细节的处理,有兴趣的朋友可以自己尝试.


上完整shader:

Shader "Custom/Water" {
	Properties {
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Main Tex", 2D) = "white" {}
        _Magnitude ("Distortion Magnitude" , Float) = 1
        _Frequency ("Distortion Frequency" , Float) = 1
        _InvWaveLength("Distortion Inverse Wave Length",Float) = 10
        _Speed("Speed",Float) = 0.5
	}
	SubShader {
        Tags{"IgnoreProjector"="True"  "Queue"="Transparent" "RenderType"="Transparent"}
		
        Pass{
            CGPROGRAM

            #pragma vertex vert
            #pragma geometry geom
            #pragma fragment frag

            #include "Lighting.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _Color;
            float _Magnitude;
            float _Frequency;
            float _InvWaveLength;
            float _Speed;

            struct a2v{
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 texcoord : TEXCOORD0;
            };

            struct v2f {
                float4 pos : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
                float2 uv : TEXCOORD2;
            };

            v2f vert(a2v v) {
                v2f o;
                float4 offset;
                offset.xyzw = float4(0,0,0,0);

                float sinx = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength);
                offset.y = sinx * _Magnitude;
                offset.x =  sin(_Frequency * _Time.y + v.vertex.x);
                offset.z =  sin(_Frequency * _Time.y  + v.vertex.z);


                o.pos = UnityObjectToClipPos(v.vertex+offset);
                o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
                o.worldPos =  mul(unity_ObjectToWorld,v.vertex).xyz;

                return o;
            }

            [maxvertexcount(3)]
            void geom(triangle v2f IN[3], inout TriangleStream<v2f> triStream)
            {
                float3 v0 = IN[0].pos.xyz;
                float3 v1 = IN[1].pos.xyz;
                float3 v2 = IN[2].pos.xyz;

                float3 vn = normalize(cross(v1 - v0, v2 - v0));

                vn = UnityObjectToWorldNormal(vn);

                v2f OUT;
                OUT.pos = IN[0].pos;
                OUT.worldNormal = vn;
                OUT.worldPos = IN[0].worldPos;
                OUT.uv = IN[0].uv;
                triStream.Append(OUT);

                OUT.pos = IN[1].pos;
                OUT.worldNormal = vn;
                OUT.worldPos = IN[1].worldPos;
                OUT.uv = IN[1].uv;
                triStream.Append(OUT);

                OUT.pos = IN[2].pos;
                OUT.worldNormal = vn;
                OUT.worldPos = IN[2].worldPos;
                OUT.uv = IN[2].uv;
                triStream.Append(OUT);

            }
            fixed4 frag(v2f i) : SV_Target {
                //获取法线方向
                fixed3 worldNormal = normalize(i.worldNormal);
                //灯光方向
                fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed4 c = tex2D(_MainTex,i.uv) * dot(worldNormal,worldLightDir);

                return c;
            }
            ENDCG
        }
	}
	FallBack "Transparent/VertexLit"
}



  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值