找回密码
 立即注册
查看: 252|回复: 0

unity urp 13 广告牌算法

[复制链接]
发表于 2022-6-24 12:05 | 显示全部楼层 |阅读模式
一、思路

广告牌的效果就是让物体的正面总是面对摄像机,能随着视角的变化而变化。
广告牌算法的本质就是构建一个旋转矩阵对物体进行顶点坐标变换。已知每个物体都有Object Space对应的基向量:表面法线(z)、向上(y)和向右方向(x),假设经过广告牌算法的变换矩阵的变换后,每个物体所在空间对应的基向量为z',y',x',之后又要分为两种情况:

  • 例如再模拟草丛时,y'的方向永远是(0,1,0),z'会随着视角变换。
  • 例如在模拟粒子效果时,y'的方向会发生变化,z'的方向则永远指向相机。
实现方法主要有三种:
1.z'指向相机,y'与相机y轴方向相同
2.z'指向相机,x'与原本的y方向垂直
如下图所示,z'只要知道相机位置即可求出(相机位置减原点),x'同时垂直于y和z',有cross(y,z')即可求得。
最后再由cross(x',z')可以求得y'。


但要注意的是,因为第一步需要叉乘z'和y,如果此时z'和y几乎重合,那么求得x'可以是一个平面上的任意一个向量,即失去了一个自由度。所以这时候需要分情况讨论。


此时可以当作y'为(0,0,1),然后将z'和y'叉乘即可求得x'
float3 newX = abs(newZ.y)<0.99?cross(float3(0,1,0),newZ):cross(newZ,float3(0,0,1));3.z'指向相机,但是z'.y锁定为0,y'方向为(0,1,0)
和第二种的过程一样,只是这里直接令z'的y分量即z'.y为0就可以了。

最后就是矩阵变换了,代码中的矩阵变化如下所示,最后能得到某一坐标在三个基变量上的投影,然后相加,即可得到最终的坐标。


二、代码

Shader "Unlit/15_BillBoard"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        
        HLSLINCLUDE
        #include"Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        #include"Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
        struct Attributes
        {
            float3 positionOS: POSITION;
            half3 normalOS: NORMAL;
            half4 tangentOS: TANGENT;
            float2 texcoord: TEXCOORD0;
        };

        struct Varyings
        {
            float2 uv: TEXCOORD0;
            float3 positionWS: TEXCOORD1;
            half3 normalWS: TEXCOORD2;
            half3 tangentWS: TEXCOORD3;
            half3 bitangentWS: TEXCOORD4;
            float4 positionCS: SV_POSITION;
        };
        
        CBUFFER_START(UnityPerMaterial)
        float4 _MainTex_ST;
        CBUFFER_END
        sampler2D _MainTex;
        
        ENDHLSL
        
        Pass
        {   
            Tags
            {
                "LightMode"="UniversalForward"
            }
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            Varyings vert (Attributes input)
            {
                Varyings output;
                VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS);
                VertexNormalInputs vertexNormalInputs = GetVertexNormalInputs(input.normalOS, input.tangentOS);  
                output.positionCS = vertexInput.positionCS;
                output.positionWS = vertexInput.positionWS;
                output.normalWS = vertexNormalInputs.normalWS;
                output.tangentWS = vertexNormalInputs.tangentWS;
                output.bitangentWS = vertexNormalInputs.bitangentWS;
                output.uv = TRANSFORM_TEX(input.texcoord, _MainTex);
               
                //获取模型空间下的相机坐标
                float3 newZ = TransformWorldToObject(GetCameraPositionWS());
                //normalize作为模型空间下的z轴方向
                newZ = -normalize(newZ);
                //newZ.y = 0;
                float3 newX = abs(newZ.y)<0.99?cross(float3(0,1,0),newZ):cross(newZ,float3(0,0,1));
                newX = normalize(newX);
                float3 newY = cross(newZ, newX);
                newY = normalize(newY);
               
                float3x3 toBillBoard = {newX, newY, newZ};
                toBillBoard = transpose(toBillBoard);
                float3 newPos = mul(toBillBoard, input.positionOS);
                output.positionCS = TransformObjectToHClip(float4(newPos,1));
               
                return output;
            }

            half4 frag (Varyings input) : SV_Target
            {
                Light mainLight = GetMainLight();
               
                half4 col = tex2D(_MainTex, input.uv);
               
                return col;
            }
            ENDHLSL
        }
    }
}三、结果



四、参考

HansenChen:UnityShaderBillBoard(公告牌)原理和实现
urp管线的自学hlsl之路 第十四篇  广告牌算法

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-15 21:09 , Processed in 0.090251 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表