PISCOnoob

导航

Simple Vertex Displacement

写在前面:

本文章为个人学习笔记,方便以后自己复习,也希望能帮助到他人。

由于本人水平有限难免出现错误,还请评论区指出,多多指教。

部分图元和素材来源于网络,如有侵权请联系本人删除。

参考资料与链接会在文章末尾贴出。

=======================================================================

之前我们一直在fragment shader里玩花样,而在vertex shader里面只做了坐标位置的变换,这次我们尝试在vertex shader里搞点小花样。

先简单写个halfLambert + blinPhong的shader,当然也可以用unity自带的surface shader,个人习惯是自己写光照模型存起来以后复制粘贴就好了。

1.先尝试点简单的操作:

我们在vertex shader里面将所有顶点乘2,相当于所有顶点外扩了:

让顶点的y坐标随着x不同而不同:

我们可以为这个sin函数加上振幅和频率:

2.法线问题

虽然在上文我们改变了顶点的位置,但实际上我们改变后的模型的法线是错的,因为我们只改变过顶点位置却没随之调整法线。

比较简单灵活一种计算法线的方式:计算变形后某一点邻近点的信息,并根据此信息再重新计算原来点的法线。

我们可以沿着表面某一点的tangent和bitangent来计算得到邻近的点。normal,tangent和bitangent三者是相互垂直的,如下图,蓝色是normal,黄色是tangent,红色是bitangent:

tangent已然储存在了模型数据中,我们可以直接使用;而bitangent并没有,但我们亦可以通过计算normal和tangent的叉乘轻松求出。

在我们获得bitangent之后,我们在几乎与原顶点相同的位置上创建两个点,不过给他们一点点偏移,且用他们做同样的sin函数计算。

       struct a2v
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
                float3 tangent : TANGENT;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;             
                float4 pos : SV_POSITION;
                float4 posWS : TESSFACTOR1;
                float3 normal : TEXCOORD2;
                float3 tangent : TEXCOORD3;
                float3 bitangent : TEXCOORD4;
                float3 normalWS : TEXCOORD5;
            };
           

            v2f vert (a2v v)
            {
                v2f o;

                float4 modifiedPos = v.vertex;
                modifiedPos.y +=sin(v.vertex.x * _Frequency) * _Amplitude;

                float3 posPlusTangent = v.vertex + v.tangent * 0.01;
                posPlusTangent.y += sin(posPlusTangent.x * _Frequency) * _Amplitude;

                float3 bitangent = cross(v.normal,v.tangent);
                float3 posPlusBitangent = v.vertex + bitangent * 0.01;
                posPlusBitangent.y += sin(posPlusBitangent.x * _Frequency) * _Amplitude;

                float3 modifiedTangent = posPlusTangent - modifiedPos;
                float3 modifiedBitangent = posPlusBitangent - modifiedPos;

                float3 modifiedNormal = normalize(cross(modifiedTangent, modifiedBitangent));

                o.pos = UnityObjectToClipPos(modifiedPos);
                o.posWS = mul(unity_ObjectToWorld,modifiedPos);
                o.normalWS = UnityObjectToWorldNormal(modifiedNormal);
                return o;
            }

需要注意的是偏移点的计算是在object space,而最后仍要计算clip pos和世界空间下的顶点位置和法线。

最后我们可以加入时间变量让模型动起来,在unity官方文档中可以找到一些shaderlab内置的变量,包括我们等下用使用的_Time。

Built-in shader variables

 

posted on 2022-11-02 09:56  PISCOnoob  阅读(27)  评论(0编辑  收藏  举报