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。