Unity Shader 学习笔记(18)纹理动画、顶点动画、广告牌技术
来源:互联网 发布:linux 查看数据包 编辑:程序博客网 时间:2024/05/18 02:57
Unity Shader 学习笔记(18)纹理动画、顶点动画、广告牌技术
参考书籍:《Unity Shader 入门精要》
【《Real-Time Rendering 3rd》 提炼总结】(九) 第十章 · 游戏开发中基于图像的渲染技术总结
Unity Shader的内置变量
纹理动画
可用于代替粒子系统模拟动画效果。
帧序列动画
8x8帧序列纹理动画
Properties { _Color ("Color Tint", Color) = (1, 1, 1, 1) _MainTex ("Image Sequence", 2D) = "white" {} // 包含所有关键帧图像的纹理 _HorizontalAmount ("Horizontal Amount", Float) = 4 // 水平方向包含关键帧图像个数 _VerticalAmount ("Vertical Amount", Float) = 4 // 同上(竖直方向) _Speed ("Speed", Range(1, 100)) = 30 // 播放速度}
因为序列帧图像通常是透明纹理,所以就按半透明的方式设置。
// 序列帧图像通常包含透明通道Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}Pass { Tags { "LightMode"="ForwardBase" } // 关闭深度写入,开启混合模式 ZWrite Off Blend SrcAlpha OneMinusSrcAlpha ... fixed4 frag (v2f i) : SV_Target { float time = floor(_Time.y * _Speed); // floor()取整。CG的函数 float row = floor(time / _HorizontalAmount); // 行索引 float column = time % _HorizontalAmount; // 列索引 // 纹理坐标从上到下,所以是-row。下面两种计算方法 //half2 uv = float2(i.uv.x /_HorizontalAmount, i.uv.y / _VerticalAmount); //uv.x += column / _HorizontalAmount; //uv.y -= row / _VerticalAmount; half2 uv = i.uv + half2(column, -row); uv.x /= _HorizontalAmount; uv.y /= _VerticalAmount; fixed4 c = tex2D(_MainTex, uv); c.rgb *= _Color; return c; }}
滚动动画
可以模拟2D跑酷游戏背景的视察效果。
Properties { _MainTex ("Base Layer (RGB)", 2D) = "white" {} // 第一层背景(较远背景) _DetailTex ("2nd Layer (RGB)", 2D) = "white" {} // 较近背景 _ScrollX ("Base layer Scroll Speed", Float) = 1.0 // 第一层背景滚动速度 _Scroll2X ("2nd layer Scroll Speed", Float) = 1.0 // 第二层速度 _Multiplier ("Layer Multiplier", Float) = 1 // 纹理亮度}
v2f vert (a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); // TRANSFORM_TEX 得到初始纹理坐标,加上偏移坐标。frac为获取小数部分的值。 o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex) + frac(float2(_ScrollX, 0.0) * _Time.y); o.uv.zw = TRANSFORM_TEX(v.texcoord, _DetailTex) + frac(float2(_Scroll2X, 0.0) * _Time.y); return o;}fixed4 frag (v2f i) : SV_Target { fixed4 firstLayer = tex2D(_MainTex, i.uv.xy); fixed4 secondLayer = tex2D(_DetailTex, i.uv.zw); fixed4 c = lerp(firstLayer, secondLayer, secondLayer.a); c.rgb *= _Multiplier; return c;}
顶点动画
即修改顶点信息的动画。
一张长方形纹理,通过修改顶点信息,实现扭曲效果。
Properties { _MainTex ("Main Tex", 2D) = "white" {} _Color ("Color Tint", Color) = (1, 1, 1, 1) _Magnitude ("Distortion Magnitude", Float) = 1 // 幅度 _Frequency ("Distortion Frequency", Float) = 1 // 频率 _InvWaveLength ("Distortion Inverse Wave Length", Float) = 10 // 波长的倒数 _Speed ("Speed", Float) = 0.5}
// DisableBatching:取消批处理。需要对模型空间下的顶点位置进行偏移,所以就不合并模型。Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}Pass { Tags { "LightMode"="ForwardBase" } ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Cull Off // 关闭剔除模式(正反面都显示) ... v2f vert(a2v v) { v2f o; float4 offset; offset.yzw = float3(0.0, 0.0, 0.0); // 只改变X变量 offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude; o.pos = UnityObjectToClipPos(v.vertex + offset); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.uv += float2(0.0, _Time.y * _Speed); return o; }}
注意到前面使用内置阴影的Pass是没有处理顶点动画的,所以最后投影的阴影是错误的,需要自定义ShadowCasterPass,在这个Pass做相同顶点变换即可。
下面用到阴影的宏都在UnityCG.cginc中定义。
Pass { Tags { "LightMode" = "ShadowCaster" } ... #pragma multi_compile_shadowcaster ... struct v2f { // 内置宏,阴影投射需要的变量 V2F_SHADOW_CASTER; }; v2f vert(appdata_base v) { v2f o; float4 offset; offset.yzw = float3(0.0, 0.0, 0.0); offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnitude; v.vertex = v.vertex + offset; // 计算阴影 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o) return o; } fixed4 frag(v2f i) : SV_Target { // 阴影投射 SHADOW_CASTER_FRAGMENT(i) } ENDCG}
广告牌技术(Billboarding)
即让纹理始终面对着镜头。本质就是构建旋转矩阵,三个基向量:表面法线、向上的方向、向右的方向。还需要指定一个锚点,即旋转中心。
计算方法(如下图):
1. 先计算向右方向 right = up × normal。起始up是竖直向上的。
2. 叉乘即可得到向上方向 up’ = normal × right。
Vertical Restraints值为1,所有星星不管原来什么角度都会转向到镜头。
Vertical Restraints值为0,所有星星固定向上方向,并最大限度面向镜头。
Properties { _MainTex ("Main Tex", 2D) = "white" {} _Color ("Color Tint", Color) = (1, 1, 1, 1) _VerticalBillboarding ("Vertical Restraints", Range(0, 1)) = 1 // 垂直程度,0:固定向上,1:固定法线}
// 需要模型空间下的位置来作为锚点计算,所以要关掉批处理。Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}Pass { Tags { "LightMode"="ForwardBase" } ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Cull Off CGPROGRAM ... v2f vert (a2v v) { v2f o; float3 center = float3(0, 0, 0); // 模型空间的原点作为广告牌锚点 float3 viewer = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos, 1)); // 获取模型空间下视角 float3 normalDir = viewer - center; // _VerticalBillboarding 为1为法线固定(始终向上),为0为向上方向固定。 normalDir.y =normalDir.y * _VerticalBillboarding; normalDir = normalize(normalDir); // 通过normalDir.y 先判断法线和向上是否平行(叉积会错),来改变向上方向 float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3(0, 1, 0); float3 rightDir = normalize(cross(upDir, normalDir)); upDir = normalize(cross(normalDir, rightDir)); // 通过三个正交基矢量,计算得到新的顶点位置 float3 centerOffs = v.vertex.xyz - center; float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z; o.pos = UnityObjectToClipPos(float4(localPos, 1)); // 模型转裁剪空间 o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); return o; }
关于 DisableBatching
如果要进行一些顶点动画,就要关闭批处理。性能会下降,所以尽量避免使用模型空间下的绝对位置和方向进行计算。如广告拍技术中,可以用顶点颜色来存储顶点到锚点的距离。
阅读全文
0 0
- Unity Shader 学习笔记(18)纹理动画、顶点动画、广告牌技术
- Unity Shader学习笔记:纹理动画
- Unity Shader 学习笔记(十三)表面着色器的顶点动画
- Unity Shader 学习笔记(九) UV动画Shader实例
- Unity Shader 学习笔记(24) 深度纹理、法线纹理
- 【Unity Shader】摇摆的小草——顶点动画
- Unity MegaFiers 顶点动画
- Unity Shader 学习笔记(8) 纹理映射、凹凸映射
- unity之shader学习笔记(五)--纹理
- Unity Shader学习笔记:基础纹理
- Unity Shader学习笔记:渐变纹理
- Unity Shader学习笔记:遮罩纹理
- Unity Shader学习笔记:渲染纹理
- unity shader学习笔记(四)——Unity中的基础纹理之单张纹理
- unity shader学习笔记(六)——Unity中的基础纹理之渐变纹理
- unity shader学习笔记(七)——Unity中的基础纹理之遮罩纹理
- BoYing Unity 之 Shader 笔记(一)帧动画
- Unity Shader 学习笔记(十一) 混合纹理Shader实例
- 测试服务器上直接修改properties文件导致OOM的问题
- Hibernate理解2:hibernate的运用理解
- 编写一个JFrame窗口
- 用easyui时遇到一对一 外键关联时 数据绑定
- Intent的详解
- Unity Shader 学习笔记(18)纹理动画、顶点动画、广告牌技术
- sleep与wait的区别
- Stenffensen加速迭代法
- 事件对象
- 欢迎使用CSDN-markdown编辑器
- switch
- mysql连接池
- Virtualbox 主机与虚拟机互相访问
- Python 实现股票数据的实时抓取