前言
前面两篇文章说的都是对UV进行修改实现shader的动态效果,这一篇来说一下通过顶点的偏移实现动态shader。
对于顶点常用的偏移操作有移动、旋转、缩放这三种,下面分别来介绍。
顶点移动
顶点的移动比较简单,就是在顶点shader中,直接对顶点位置进行偏移,下面的代码是一个y轴上下移动的shader。
// shader的路径和名称 Shader "Shader Forge/VertixTranslation" { // 暴露属性到面板 Properties { _MainTex("RGB: Color A:Alpha", 2d) = "gray"{} _Opacity("Opacity", range(0.0, 1.0)) = 1.0 _MoveRange("Move Range", range(0.0, 2.0)) = 1.0 _MoveSpeed("Move Speed", range(0.0, 3.0)) = 1.0 } SubShader { Tags { "Queue"="Transparent" //调整渲染顺序 "RenderType"="Transparent" //改为对应的 "ForceNoShadowCasting"="True" //关闭阴影投射 "IgnoreProjector"="True" //不响应投射器 } Pass { Name "FORWARD" Tags { "LightMode"="ForwardBase" } Blend One OneMinusSrcAlpha //修改混合模式 Cull Off //双面显示 CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #pragma multi_compile_fwdbase_fullshadows #pragma target 3.0 // 声明变量 uniform sampler2D _MainTex; uniform float4 _MainTex_ST; //支持UV TillingOffset uniform half _Opacity; uniform half _MoveRange; uniform half _MoveSpeed; // 输入结构 struct VertexInput { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; // 输出结构 struct VertexOutput { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; // 声明常量 #define TwoPi 6.283185 // 顶点动画方法 void Translation(inout float3 vertex){ //inout表示在函数内直接修改此传入变量 vertex.y += _MoveRange * sin(frac(_Time.z * _MoveSpeed) * TwoPi); //sin()用于产生周期波动,sin()的完整周期是0到2π,frac()取余的值域是0到1,因此需要乘TwoPi } // 顶点shader VertexOutput vert (VertexInput v) { VertexOutput o = (VertexOutput)0; Translation(v.vertex.xyz); o.pos = UnityObjectToClipPos( v.vertex ); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } // 像素shader float4 frag(VertexOutput i) : COLOR { half4 var_MainTex = tex2D(_MainTex, i.uv); half finalOpacity = var_MainTex.a * _Opacity; return half4(var_MainTex.rgb * finalOpacity,finalOpacity); } ENDCG } } FallBack "Diffuse" }
注意sin()的完整周期是2π,因此如果不乘2π会造成动画卡顿闪烁。
效果如下
顶点缩放
顶点的缩放和顶点的移动是相同的原理,代码也类似。
// shader的路径和名称 Shader "Shader Forge/VertexScale" { // 暴露属性到面板 Properties { _MainTex("RGB: Color A:Alpha", 2d) = "gray"{} _Opacity("Opacity", range(0.0, 1.0)) = 1.0 _ScaleRange("Scale Range", range(0.0, 2.0)) = 1.0 _ScaleSpeed("Scale Speed", range(0.0, 3.0)) = 1.0 } SubShader { Tags { "Queue"="Transparent" //调整渲染顺序 "RenderType"="Transparent" //改为对应的 "ForceNoShadowCasting"="True" //关闭阴影投射 "IgnoreProjector"="True" //不响应投射器 } Pass { Name "FORWARD" Tags { "LightMode"="ForwardBase" } Blend One OneMinusSrcAlpha //修改混合模式 Cull Off //双面显示 CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #pragma multi_compile_fwdbase_fullshadows #pragma target 3.0 // 声明变量 uniform sampler2D _MainTex; uniform float4 _MainTex_ST; //支持UV TillingOffset uniform half _Opacity; uniform half _ScaleRange; uniform half _ScaleSpeed; // 输入结构 struct VertexInput { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; // 输出结构 struct VertexOutput { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; // 声明常量 #define TwoPi 6.283185 // 顶点动画方法 void Scaling(inout float3 vertex){ //inout表示在函数内直接修改此传入变量 vertex *= 1.0 + _ScaleRange * sin(frac(_Time.z * _ScaleSpeed) * TwoPi); //sin()用于产生周期波动,sin()的完整周期是0到2π,frac()取余的值域是0到1,因此需要乘TwoPi } // 顶点shader VertexOutput vert (VertexInput v) { VertexOutput o = (VertexOutput)0; Scaling(v.vertex.xyz); o.pos = UnityObjectToClipPos( v.vertex ); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } // 像素shader float4 frag(VertexOutput i) : COLOR { half4 var_MainTex = tex2D(_MainTex, i.uv); half finalOpacity = var_MainTex.a * _Opacity; return half4(var_MainTex.rgb * finalOpacity,finalOpacity); } ENDCG } } FallBack "Diffuse" }
区别就是+=换成*=,修改的轴向由单个y轴改成xyz三轴整体,效果如下。
顶点旋转
顶点的旋转相对于移动和缩放要复杂一些,需要了解向量的旋转原理。
首先将问题简化一下,顶点绕Y轴旋转时,此时y坐标不变,可以视为[x, y]二维向量绕原点旋转,求旋转后的红色箭头处的XZ坐标,下面的图展示了这种方式的计算方法。
通过三角函数配合向量的加减运算即可得到旋转后的坐标,具体代码如下:
// shader的路径和名称 Shader "Shader Forge/VertexRotate" { // 暴露属性到面板 Properties { _MainTex("RGB: Color A:Alpha", 2d) = "gray"{} _Opacity("Opacity", range(0.0, 1.0)) = 1.0 _RotateRange("Rotate Range", range(0.0, 90.0)) = 30.0 _RotateSpeed("Rotate Speed", range(0.0, 3.0)) = 1.0 } SubShader { Tags { "Queue"="Transparent" //调整渲染顺序 "RenderType"="Transparent" //改为对应的 "ForceNoShadowCasting"="True" //关闭阴影投射 "IgnoreProjector"="True" //不响应投射器 } Pass { Name "FORWARD" Tags { "LightMode"="ForwardBase" } Blend One OneMinusSrcAlpha //修改混合模式 Cull Off //双面显示 CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #pragma multi_compile_fwdbase_fullshadows #pragma target 3.0 // 声明变量 uniform sampler2D _MainTex; uniform float4 _MainTex_ST; //支持UV TillingOffset uniform half _Opacity; uniform half _RotateRange; uniform half _RotateSpeed; // 输入结构 struct VertexInput { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; // 输出结构 struct VertexOutput { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; // 声明常量 #define TwoPi 6.283185 // 顶点动画方法 void Rotation(inout float3 vertex){ //inout表示在函数内直接修改此传入变量 float angelY = _RotateRange * sin(frac(_Time.z * _RotateSpeed) * TwoPi); //旋转范围 float radY = radians(angelY); //计算弧度 float sinY, cosY = 0; sincos(radY, sinY, cosY); //根据弧度计算sin和cos vertex.xz = float2(vertex.x * cosY - vertex.z * sinY, vertex.x * sinY + vertex.z * cosY); //计算偏移量 } // 顶点shader VertexOutput vert (VertexInput v) { VertexOutput o = (VertexOutput)0; Rotation(v.vertex.xyz); o.pos = UnityObjectToClipPos( v.vertex ); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } // 像素shader float4 frag(VertexOutput i) : COLOR { half4 var_MainTex = tex2D(_MainTex, i.uv); half finalOpacity = var_MainTex.a * _Opacity; return half4(var_MainTex.rgb * finalOpacity,finalOpacity); } ENDCG } } FallBack "Diffuse" }
效果如下
注意
注意下图中,当选择三个应用了不同定点动画的模型时,可以发现三个物体实际仍在原来的位置,也就是说顶点动画可以使用静态物体实现动态的效果,在大量物体进行随机运动的情况下,可以避免由CPU处理这些transform信息,减少DrawCall压力,也就是所谓的静态合批。
顶点动画由于实现简单、效果容易控制、节省CPU资源等优点,因此在草丛、建筑等大量随机散布物体,特别是移动平台上被大量使用。
目前动画虽然已经实现,但默认的阴影由于调用的是原始的顶点位置进行计算,会导致有顶点动画的物体投影不正确,为了修复这个问题,需要自定义一个ShadowCaster Pass,在这个Pass中,进行同样的顶点变换过程。这一部分之后会单独开篇介绍。
本文同样参考自B站庄懂的技术美术入门课,感谢。
梦想养活不起你的时候,
你得养着梦想啊。
——小林一茶
评论
It is truly a nice and helpful piece of info. I am satisfied that you shared this helpful info with us. Please stay us informed like this. Thanks for sharing.
https://youtu.be/sxTCvydDiCA
Nice post. I learn something more challenging on different blogs everyday. It will always be stimulating to read content from other writers and practice a little something from their store. I’d prefer to use some with the content on my blog whether you don’t mind. Natually I’ll give you a link on your web blog. Thanks for sharing.
https://youtu.be/FSlp-BTUAA0
Super-Duper blog! I am loving it!! Will be back later to read some more. I am taking your feeds also.
https://youtu.be/VoBGMol7oIU
Thanks on your marvelous posting! I quite enjoyed reading it, you’re a great author.I will be sure to bookmark your blog and definitely will come back in the foreseeable future. I want to encourage continue your great posts, have a nice day!
https://youtu.be/y5_dn-bwq7w
At this time it seems like Movable Type is the preferred blogging platform available right now. (from what I’ve read) Is that what you are using on your blog?
https://www.tdsky.com/
Thank you, I’ve just been looking for information approximately this subject for a long time and yours is the greatest I have came upon so far. However, what in regards to the conclusion? Are you certain concerning the supply?
https://youtu.be/fWb2MALMQhM
Hello! I just wanted to ask if you ever have any issues with hackers? My last blog (wordpress) was hacked and I ended up losing months of hard work due to no back up. Do you have any methods to prevent hackers?
https://www.actualteam.com/
Nice post. I learn something more challenging on different blogs everyday. It will always be stimulating to read content from other writers and practice a little something from their store. I’d prefer to use some with the content on my blog whether you don’t mind. Natually I’ll give you a link on your web blog. Thanks for sharing.
https://youtu.be/idcTUkW38XI
I really treasure your work, Great post.
https://youtu.be/NnfUcQM5pps
You have observed very interesting details! ps decent website.
https://www.bigzh.com/hire-a-hacker-for-social-media/
Outstanding post however , I was wondering if you could write a litte more on this topic? I’d be very thankful if you could elaborate a little bit more. Thanks!
https://youtu.be/9CNRKSCXeYY
May I use Wikipedia content in my blog without violating the copyright law?
https://hearthis.at/htnweb/d-drill/
I don’t ordinarily comment but I gotta tell thankyou for the post on this one : D.
https://youtu.be/F4LBoHVpsCA
I am from India. I did my Engineering in Computer Science. I had a made a poor career choice and regretting now.. . I am currently working as a Senior Software Engineer in one of the software firms.. . I wish to do MS in USA. But I dont want to do it in anything related to Computer Science.. . I am more interested in English Literature or Psychology or Medicine related courses…. . Can a computer Science student do such Master degree courses in USA?.
https://store.payloadz.com/details/2685316-ebooks-technical-htnweb.html