一些通过uv纹理坐标实现的简单shader(上)
发表于2018-07-26
分两篇文章给大家介绍通过uv纹理坐标实现的简单shader,这篇先来说下如何实现简单的波动效果。
所谓纹理,简单说就是一张图片,通过规定好的原点和二维坐标(一般称为uv坐标),就可以获得图片任意像素的颜色信息。
三维建模时,为了控制模型外观,我们会通过纹理映射技术将图片“黏”在模型表面。在模型的每个顶点上,一般会存储一个 二维坐标信息,其对应的就是纹理图片的uv坐标,通过这个坐标,就可以确定每个顶点的颜色。当然,也可以通过纹理图片的像素存储其他信息,比如 模型顶点的法线等。
一般而言,为了显示正确的效果,模型顶点存储的uv坐标确定的而通过改变uv的值,我们就能够做出一些简单的效果,下面就来演示一个很常见波纹效果,其效果如下:
我们使用的是unity的顶点与片段着色器,首先是一些准备工作,如下:
Shader "Custom/Ripple" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 200 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; float4 _MainTex_ST; struct v2f { float4 pos : POSITION; float2 uv : TEXCOORD0; }; v2f vert(appdata_full v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } float4 frag(v2f i) : COLOR { //to do something } ENDCG } } FallBack "Diffuse" }
为了得到上图的效果,我们需要在片段着色器中对uv做相应的处理。 先看图, 想要产生这种类似于水面的波动效果,最简单的就是让图片的每一个像素沿着某个方向周期性的往复运动, 像下面这样:这种运动可以通过平面简谐波进行模拟,其波函数我们简写为y=Acos(at+bx),其中t为时间,x为与原点(已知振动方程的点)的距离。在我们的shader中, t很容易用_Time[1]表示,距离我们可以取uv.x(即u相同让它有相同的运动),同时为了方便调整其他参数,我们先在Properties里添加如下定义:
_Scale("Scale", Range(0,500.0)) = 3.0 _Speed("Speed", Range(-50,50.0)) = 1.0 _Identity("Identity",Range(50,100.0))=80
然后在片段着色器中做如下处理:
float4 frag(v2f i) : COLOR { float4 o; half2 uv = i.uv; half r = uv.x;//sqrt(uv.x*uv.x + uv.y*uv.y); half z = cos(_Scale*r + _Time[1] * _Speed) /_Identity; o.rgb = tex2D(_MainTex, uv+ float2(z,0)).rgb; o.a =1; return o; }
运行,调整一下参数,可以得到下面这样的效果, 可以清晰的感觉到像素在沿着x轴进行波动。
当然,为了效果好一点,我们可以作如下修改:
void surf(Input IN, inout SurfaceOutput o) { half2 uv = IN.uv_MainTex; half r =sqrt(uv.x*uv.x + uv.y*uv.y); half z = cos(_Scale*r+_Time[1] * _Speed)/80; o.Albedo = _Color.rgb * tex2D(_MainTex, IN.uv_MainTex + float2(z,z)).rgb; o.Alpha = _Color.a; }
这里像素会沿着原点与该点的向量方向进行往复运动,因此与原点距离相同的圆上的点都有着相似的运动,其效果如下:
来自:https://blog.csdn.net/dark00800/article/details/58640983