去年疫情+部分私人原因搞的我人都要自闭了
还是得好好学习,别想那有的没的,希望现在止损还来得及
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Custom/BillboardShader"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_VerticalBillboarding ("Vertical Restraints", Range(0, 1)) = 1
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" "IgnoreProjector"="True" "DisableBatching"="True"}
Pass
{
Tags { "LightMode" = "ForwardBase" }
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
CGPROGRAM
#pragma vertex VS
#pragma fragment PS
#include "Lighting.cginc"
struct Input
{
float4 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct Output
{
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _VerticalBillboarding;
Output VS(Input v)
{
Output o;
float3 center = float3(0, 0, 0); // 锚点
float3 viewer = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1)); // 摄像机模型空间位置
float3 normalDir = viewer - center; // 法线方向
normalDir.y = normalDir.y * _VerticalBillboarding;
normalDir = normalize(normalDir);
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 centerOffset = v.vertex.xyz - center;
float3 localPos = center + rightDir * centerOffset.x + upDir * centerOffset.y + normalDir.z * centerOffset.z; // 顶点在局部坐标系的坐标转换到新的坐标系中
o.pos = UnityObjectToClipPos(float4(localPos, 1));
o.uv = v.texcoord * _MainTex_ST.xy + _MainTex_ST.zw;
return o;
}
fixed4 PS(Output o) : SV_TARGET
{
fixed4 c = tex2D(_MainTex, o.uv);
c.rgb *= _Color.rgb;
return c;
}
ENDCG
}
}
FallBack "Transparent/VertexLit"
}
核心代码就是
float3 center = float3(0, 0, 0); // 锚点
float3 viewer = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1)); // 摄像机模型空间位置
float3 normalDir = viewer - center; // 法线方向
normalDir.y = normalDir.y * _VerticalBillboarding;
normalDir = normalize(normalDir);
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 centerOffset = v.vertex.xyz - center;
float3 localPos = center + rightDir * centerOffset.x + upDir * centerOffset.y + normalDir.z * centerOffset.z; // 顶点在局部坐标系的坐标转换到新的坐标系中
o.pos = UnityObjectToClipPos(float4(localPos, 1));
书上的解释写的比较简单,所以我想明白之后觉得还是记录下来比较好
公告牌的实现过程实际上就是一个坐标系转换的过程,将原本顶点在模型空间中的位置,转换到另一个法线朝向摄像机的平面。
float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3(0, 1, 0);
的意思就是,当摄像机在公告牌的正上方时,公告牌的up方向会与法线方向平行,因此给它改成z轴即可,满足垂直条件。 但注意,这里的up轴是不准确的,只是用来计算right轴的。