URP - 公告牌的效果实现
效果:
【太妃糖耶】我的最新作品,快来一睹为快!
原理:使面片的正面永远跟随摄像机的旋转
首先我们可以了解一下顶点旋转的原理
B点是由原坐标系中的基向量和A点坐标值相乘得到的
当旋转此基向量后,B点的坐标值会发生改变
所以旋转后顶点的坐标值是由旋转后的基向量在原坐标系下的值乘以原顶点坐标
根据上面顶点旋转的原理我们来看一下如何让面片的顶点跟随摄像机进行旋转,求得旋转后的面片顶点的坐标值
原模型的顶点坐标是在模型本地坐标系的坐标值
此时就需要知道旋转后坐标系的基向量在原本地坐标系下的值
而模型跟随摄像机旋转后的坐标系的基向量在原本地坐标系下的值如何得到呢?
可以假设Z方向向量为从模型指向摄像机,将摄像机的世界坐标系下的坐标值转换到模型空间再归一化就得到了旋转后的坐标系的基向量在原本地坐标系下的Z方向的基向量
float3 viewDir = mul(GetWorldToObjectMatrix(),float4(_WorldSpaceCameraPos,1));
viewDir = normalize(viewDir);
_WorldSpaceCameraPos为三维数
假设Y方向的基向量为(0,1,0) : float3 upDir = float3(0,1,0);
X方向的基向量可以有Y方向和Z方向的基向量叉乘得到
// 模型的本地空间为左手坐标系 默认X轴向右,Y轴向上,Z轴
float3 rightDir = normalize(cross(viewDir,upDir));
通过左手定则,大拇指指向要求的x轴,叉乘时食指代表的数值在前,中指代表的数值在后
upDir = normalize(cross(rightDir,viewDir));
最后根据所求得的基向量乘以原模型的顶点坐标得到:旋转后的模型顶点后相对于原本地坐标系下的坐标值
然后将此坐标值转换到齐次裁剪空间下即可
float3 newVertex = rightDir*v.positionOS.x+upDir*v.positionOS.y+viewDir*v.positionOS.z;
设置面片在垂直方向的显示与否在代码中体现
Shader"unity/UVSeequence"
{Properties{[NoScaleOffset]_MainTex("MainTex",2D)="white"{}_Row("Row",float)=1_Column("Column",float)=1_Speed("Speed",float)=3//枚举,用于设置viewDir向量的y轴分量值是否为0[Enum(Billaboard,1,VerticalBillaboard,0)]_BillaboardType("BillaboardType",int)=1}SubShader{Tags{"RenderPipeline"="UniversalPipeline""Queue"="Transparent"}//常用于透贴// Blend SrcAlpha OneMinusSrcAlpha//用于黑底图片Blend One OnePass{HLSLPROGRAM#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"#pragma vertex vert#pragma fragment fragTEXTURE2D(_MainTex);float4 _MainTex_ST;#define sampler_MainTex samplerState_Linear_RepeatSAMPLER(sampler_MainTex);CBUFFER_START(UnityPerMaterial)float _Row,_Column,_Speed;int _BillaboardType;CBUFFER_ENDstruct Attributes{float4 positionOS : POSITION;float2 uv : TEXCOORD;};struct Varyings{float4 positionCS : SV_POSITION;float2 uv : TEXCOORD;};Varyings vert(Attributes v){Varyings o = (Varyings)0;//将摄像机的位置转换到模型本地坐标系下float3 viewDir = mul(GetWorldToObjectMatrix(),float4(_WorldSpaceCameraPos,1));//设置垂直方向的显示与否,若不希望面片在垂直方向显示,那么就直接将viewDir向量的y分量设置为0viewDir.y *= _BillaboardType;viewDir = normalize(viewDir);float3 upDir = float3(0,1,0);//模型的本地空间为左手坐标系 默认X轴向右,Y轴向上,Z轴float3 rightDir = normalize(cross(viewDir,upDir));upDir = normalize(cross(rightDir,viewDir));float3 newVertex = rightDir*v.positionOS.x+upDir*v.positionOS.y+viewDir*v.positionOS.z;o.positionCS = TransformObjectToHClip(newVertex);o.uv = TRANSFORM_TEX(v.uv,_MainTex);//序列图动画的起始位置o.uv = float2(v.uv.x/_Column,v.uv.y/_Row+1/_Row*(_Row-1));//frac取小数的作用是优化纹理采样,使得采样纹理的UV在0-1的范围内//U方向上的走格 floor(_Time.y*_Column)/_Column代表一秒钟走完一行中的所以列的格子o.uv.x+=frac(floor(_Time.y*_Column*_Speed)/_Column);//V方向上的走格 floor(_Time.y)/_Row 代表每一秒走一行o.uv.y-=frac(floor(_Time.y*_Speed)/_Row);return o;}float4 frag(Varyings i):SV_Target{float4 c;float4 mainTex = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,i.uv);c=mainTex;//用于透贴图片消除Alpah为0的区域 Alpha=1为不透明,Alpha=0为透明c.rgb*=c.a;return c;}ENDHLSL}}}