首页 > 技术文章 > shader中的广告板技术

skylinee 2016-08-26 19:25 原文

Shader "CM/Billboard1"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			
			float4 Billboard(float4 vertex)
			{
				float4 ori=mul(UNITY_MATRIX_MV, float4(0,0,0,1));
				float4 vt = vertex;
				float2 r1=float2(_Object2World[0][0],_Object2World[0][2]);
				float2 r2=float2(_Object2World[2][0],_Object2World[2][2]);
				vt.xy = vt.x*r1 + vt.z*r2;
				vt.z = 0;
				vt.xyz += ori.xyz;
				return mul(UNITY_MATRIX_P, vt);
			}
			
			v2f vert (appdata_base v) 
			{
				v2f o;
				o.pos = Billboard(v.vertex);
				return o;
			}

			fixed4 frag(v2f i) : COLOR 
			{
				return tex2D(_MainTex, i.uv);
			}
			ENDCG
		}
	}
}

跟着相机转的plane:

 

广告板技术之二:   来自wiki ----------- https://en.wikibooks.org/wiki/Cg_Programming/Unity/Billboards            不过这种技术不能缩放广告板

Shader "Cg  shader for billboards" {
   Properties {
      _MainTex ("Texture Image", 2D) = "white" {}
   }
   SubShader {
      Pass {   
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 

         // User-specified uniforms            
         uniform sampler2D _MainTex;        
 
         struct vertexInput {
            float4 vertex : POSITION;
            float4 tex : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;

            output.pos = mul(UNITY_MATRIX_P, 
              mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
              - float4(input.vertex.x, input.vertex.y, 0.0, 0.0));
 
            output.tex = input.tex;

            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            return tex2D(_MainTex, float2(input.tex.xy));   
         }
 
         ENDCG
      }
   }
}

  广告板技术之三:   来自wiki -----------https://en.wikibooks.org/wiki/Cg_Programming/Unity/Billboards            这种技术可缩放广告板

Shader "Cg  shader for billboards" {
   Properties {
      _MainTex ("Texture Image", 2D) = "white" {}
      _ScaleX ("Scale X", Float) = 1.0
      _ScaleY ("Scale Y", Float) = 1.0
   }
   SubShader {
      Pass {   
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 

         // User-specified uniforms            
         uniform sampler2D _MainTex;        
         uniform float _ScaleX;
         uniform float _ScaleY;

         struct vertexInput {
            float4 vertex : POSITION;
            float4 tex : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;

            output.pos = mul(UNITY_MATRIX_P, 
              mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
              - float4(input.vertex.x, input.vertex.y, 0.0, 0.0)
              * float4(_ScaleX, _ScaleY, 1.0, 1.0));
 
            output.tex = input.tex;

            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            return tex2D(_MainTex, float2(input.tex.xy));   
         }
 
         ENDCG
      }
   }
}

广告板技术4:Y轴锁定的广告板 ------------------------------------------------------------------- 只能一个片使用该shader,两个片以上就会出问题(因为Unity会动态合并或静态合并)

Shader "CM/Billboard"
{
	Properties 
	{
		_MainTex ("Base texture", 2D) = "white" {}
		_VerticalBillboarding("Vertical Restraints", Range(0,1)) = 1
	}

	SubShader 
	{
		Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
		Blend one one
		cull off
		zwrite off
		
		
		Pass 
		{
			CGPROGRAM	
			#pragma vertex vert
			#pragma fragment frag
			#pragma fragmentoption ARB_precision_hint_fastest		
			#include "UnityCG.cginc"

			sampler2D _MainTex;
			float4 _MainTex_ST;
			float _VerticalBillboarding;

			
			struct v2f 
			{
				float4	pos	: SV_POSITION;
				float2	uv	: TEXCOORD0;
			};

			void CalcOrthonormalBasis(float3 dir,out float3 right,out float3 up)
			{
				up    = abs(dir.y) > 0.999f ? float3(0,0,1) : float3(0,1,0);		
				right = normalize(cross(up,dir));		
				up    = cross(dir,right);	
			}
			
			
			v2f vert (appdata_full v)
			{
				v2f o;
				o.uv    = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
				
				float3	centerLocal = 0;
				float3	centerOffs  = v.vertex;

				float3	viewerLocal = mul(_World2Object,float4(_WorldSpaceCameraPos,1));			
				float3	localDir    = viewerLocal - centerLocal;
						
				localDir.y =localDir.y * _VerticalBillboarding;
				
				float3	rightLocal;
				float3	upLocal;
				
				CalcOrthonormalBasis(normalize(localDir) ,rightLocal,upLocal);

				float3	BBNormal   = rightLocal * v.normal.x + upLocal * v.normal.y;
				float3	BBLocalPos = centerLocal - (rightLocal * centerOffs.x + upLocal * centerOffs.y);	
										
				o.pos = mul(UNITY_MATRIX_MVP, float4(BBLocalPos, 1));
				
				return o;
			}
			
			fixed4 frag (v2f i) : COLOR
			{
				fixed4 col = tex2D(_MainTex, i.uv);
				return col;
			}
			ENDCG
		}
	}
}

广告板技术5:与4表现一样,计算方式不一样

Shader "CM/Billboard"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		Tags { "Queue" = "Transparent" "RenderType"="Transparent" }
		Blend srcalpha one
		cull off
		zwrite off
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"


			struct appdata
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float4 vertex : SV_POSITION;
				float2 uv : TEXCOORD0;
				float randAlpha: TEXCOORD1;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			
			inline float4 Billboard(float4 localVertex)
			{
				float2 billboardDirection_local_xy = normalize (
					_WorldSpaceCameraPos.xz
					 -float2(_World2Object[1].w, _World2Object[2].w)
				);
			   
				float2x2 billboardRotation = float2x2(
					billboardDirection_local_xy.y,
					billboardDirection_local_xy.x,
					-billboardDirection_local_xy.x,
					billboardDirection_local_xy.y
				); 
			   
				float4 billboardLocalVertex;
				billboardLocalVertex.xz = mul(billboardRotation, localVertex.xz);
				billboardLocalVertex.yw = localVertex.yw;
				return billboardLocalVertex;
			}
			
			float4x4 inverse(float4x4 input)
			{
				#define minor(a,b,c) determinant(float3x3(input.a, input.b, input.c))
				//determinant(float3x3(input._22_23_23, input._32_33_34, input._42_43_44))

				float4x4 cofactors = float4x4(
					minor(_22_23_24, _32_33_34, _42_43_44), 
					-minor(_21_23_24, _31_33_34, _41_43_44),
					minor(_21_22_24, _31_32_34, _41_42_44),
					-minor(_21_22_23, _31_32_33, _41_42_43),

					-minor(_12_13_14, _32_33_34, _42_43_44),
					minor(_11_13_14, _31_33_34, _41_43_44),
					-minor(_11_12_14, _31_32_34, _41_42_44),
					minor(_11_12_13, _31_32_33, _41_42_43),

					minor(_12_13_14, _22_23_24, _42_43_44),
					-minor(_11_13_14, _21_23_24, _41_43_44),
					minor(_11_12_14, _21_22_24, _41_42_44),
					-minor(_11_12_13, _21_22_23, _41_42_43),

					-minor(_12_13_14, _22_23_24, _32_33_34),
					minor(_11_13_14, _21_23_24, _31_33_34),
					-minor(_11_12_14, _21_22_24, _31_32_34),
					minor(_11_12_13, _21_22_23, _31_32_33)
				);
				#undef minor
				return transpose(cofactors) / determinant(input);
			}
 
			v2f vert (appdata v)
			{
				v2f o;

				float4 bbLocalVertx = Billboard(v.vertex);
				o.vertex = mul(UNITY_MATRIX_MVP,  bbLocalVertx);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);

				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				fixed4 col = tex2D(_MainTex, i.uv);
				return col;
			}
			ENDCG
		}
	}
}

  

广告板技术6: 草         ---------------------- 类似4、5,不过要提防unity的动静态合并,可以先选择在3dsmax中做一个草坪的4边形集合,这样就可以确定各四边形的localCenter.

 

推荐阅读