Shaderlab 公告牌Billboard

以3D空间里的Sprite为例
思路

  • 使物体旋转到合适的位置
  • 需要知道模型空间下的点(x,y,z)和旋转后的坐标系的方向向量在原来的模型空间下的值(i,j,k)
  • 新的点在模型空间下为xi + yj + zk

注:
上面的i,j,k为矢量,x,y,z为标量
都是在物体原来的模型空间下完成的

  1. Sprite面对摄像机的点
    详情看最下面的完整代码以及注释
    在这里插入图片描述
  2. Sprite平行于屏幕平面,近大远小(类似于血条,饥荒中的物体的面片实现)
    在这里插入图片描述

定点着色器核心代码

//化简版
float3 forwardDir = UNITY_MATRIX_MV[2].xyz;
float3 upDir      = UNITY_MATRIX_MV[1].xyz;
float3 rightDir   = UNITY_MATRIX_MV[0].xyz;

//完整版
//float3 forwardDir = mul(UNITY_MATRIX_T_MV, float4(0, 0, 1, 1)).xyz;
//float3 upDir      = mul(UNITY_MATRIX_T_MV, float4(0, 1, 0, 1)).xyz;
//float3 rightDir   = mul(UNITY_MATRIX_T_MV, float4(1, 0, 0, 1)).xyz;

UNITY_MATRIX_MV代表从模型空间向观察空间的转换矩阵,
UNITY_MATRIX_T_MV代表从观察空间向模型空间的转换矩阵,是UNITY_MATRIX_MV的转置矩阵,完整版就代表观察空间下的方向向量到模型空间的转换

下面是坐标系转换相关内容,来自于《Unity Shader入门精要》
在这里插入图片描述

在这里插入图片描述

第一部分代码来自于《Unity Shader 入门精要》第十一章

Shader "Test/Billboard" {
    
    
	Properties {
    
    
		_MainTex ("Main Tex", 2D) = "white" {
    
    }
		_Color ("Color Tint", Color) = (1, 1, 1, 1)
		_VerticalBillboarding ("Vertical Restraints", Range(0, 1)) = 1 

	}
	SubShader {
    
    
		// Need to disable batching because of the vertex animation
		Tags {
    
    "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "DisableBatching"="True"}
		
		Pass {
    
     
			Tags {
    
     "LightMode"="ForwardBase" }
			
			ZWrite Off
			Blend SrcAlpha OneMinusSrcAlpha
			Cull Off
		
			CGPROGRAM
			
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			

			struct a2v {
    
    
				float4 vertex : POSITION;
				float4 texcoord : TEXCOORD0;
			};
			
			struct v2f {
    
    
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			fixed4 _Color;
			fixed _VerticalBillboarding;
			
			
			v2f vert (a2v v) {
    
    
				v2f 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);
				// Get the approximate up dir
				// If normal dir is already towards up, then the up dir is towards front
				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 normalDir = UNITY_MATRIX_MV[2].xyz;
				//float3 upDir = UNITY_MATRIX_MV[1].xyz;
				//float3 rightDir = cross(upDir, normalDir);
				
				// Use the three vectors to rotate the quad
				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.pos = UnityObjectToClipPos(float4(localPos, 1));
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target {
    
    
				fixed4 c = tex2D (_MainTex, i.uv);
				c.rgb *= _Color.rgb;
				
				return c;
			}
			
			ENDCG
		}
	} 
	FallBack "Transparent/VertexLit"
}

Shader "Test/Test" {
    
    
	Properties {
    
    
		_MainTex ("Main Tex", 2D) = "white" {
    
    }

	}
	SubShader {
    
    	
		Pass {
    
     
			CGPROGRAM
			
			#pragma vertex vert
			#pragma fragment frag	
			#include "Lighting.cginc"

			struct a2v {
    
    
				float4 vertex : POSITION;
				float4 texcoord : TEXCOORD0;
			};
			
			struct v2f {
    
    
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			
			
			v2f vert (a2v v) {
    
    
				v2f o;
				

//化简版
				float3 forwardDir = UNITY_MATRIX_MV[2].xyz;
				float3 upDir      = UNITY_MATRIX_MV[1].xyz;
				float3 rightDir   = UNITY_MATRIX_MV[0].xyz;

				//完整版
				//float3 forwardDir = mul(UNITY_MATRIX_T_MV, float4(0, 0, 1, 1)).xyz;
				//float3 upDir      = mul(UNITY_MATRIX_T_MV, float4(0, 1, 0, 1)).xyz;
				//float3 rightDir   = mul(UNITY_MATRIX_T_MV, float4(1, 0, 0, 1)).xyz;

				float3 localPos = rightDir * v.vertex.x + upDir * v.vertex.y + forwardDir * v.vertex.z;
              
				o.pos = UnityObjectToClipPos(float4(localPos, 1));
				//o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target {
    
    
				fixed4 c = tex2D (_MainTex, i.uv);
				
				return c;
			}
			
			ENDCG
		}
	} 
	FallBack "Transparent/VertexLit"
}


猜你喜欢

转载自blog.csdn.net/qq_41225779/article/details/107295788
今日推荐