shaderlab Billboard公告牌

去年疫情+部分私人原因搞的我人都要自闭了
还是得好好学习,别想那有的没的,希望现在止损还来得及

代码看的unity shader入门精要
shaderlab Billboard公告牌_第1张图片
代码

// 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));

书上的解释写的比较简单,所以我想明白之后觉得还是记录下来比较好

公告牌的实现过程实际上就是一个坐标系转换的过程,将原本顶点在模型空间中的位置,转换到另一个法线朝向摄像机的平面。

  1. 首先得到摄像机的模型空间坐标,也就是乘世界坐标的逆矩阵UNITY_WorldToObject,并计算模型坐标中心到摄像机的法线
  2. 使用额外因子控制法线的y分量,可以用来调整公告牌的倾斜程度
  3. float3 upDir = abs(normalDir.y) > 0.999 ? float3(0, 0, 1) : float3(0, 1, 0); 的意思就是,当摄像机在公告牌的正上方时,公告牌的up方向会与法线方向平行,因此给它改成z轴即可,满足垂直条件。 但注意,这里的up轴是不准确的,只是用来计算right轴的。
  4. 叉乘计算right轴,并重新计算up轴,得到三个轴的向量

shaderlab Billboard公告牌_第2张图片

  1. 坐标系变换,将三个轴乘以原坐标的三个分量,得到其在垂直于摄像机方向的平面的新坐标。

你可能感兴趣的:(Unity3D)