UnityShader实例10:广告牌(Billboard)材质

 原文链接: http://blog.csdn.net/u011047171/article/details/47255233




广告牌(Billboard)材质


Billboard概述


Billboard技术在游戏引擎中占有很重要的地位,一般用在粒子效果或者光晕效果上,让粒子面片z轴朝向摄影机。Unity里面也不例外 ,在Unity的粒子系统中的render面板的render mode中就四中billboard模式可选,这些模式都是面对摄影机的,只是轴向的约束不同;另外Unity的Terrain系统里也有Billboard技术的使用;但是如果我们使用自己做的模型或者预设,要使它朝向摄影机的话,则得自己写脚本或者写相应的shader实现,在这里将拿shadowgun里面的一个写得不错的shader(MADFINGER/Transparent/Blinking GodRays Billboarded)做例子实现billboard功能(如下图:),原来的例子中有一些与billboard无关的效果(如闪烁,根据距离渐隐等)我将它去掉了,只讲述billboard的实现。




模型在3d软件中的准备


在这个shader里面,为了获得面片的中心,将一些数据存在顶点颜色和UV2里面,在顶点颜色R通道和G通道里面存储一个单位面片(长宽为1的面片)的坐标,即四个顶点的顶点色(0,0,0),(255,0,0),(255,255,0),(0,255,0),而在UV2里面存下这个面片的长宽值(6,8),需要注意的是要保证单位为米,方便匹配unity的单位;如下图本例使用的面片:四个顶点的顶点色如下图所示,长宽为6和8,四个顶点的UV2如下图所示,记录长宽的单位6和8。






shader实现


这个shader是一个可以约束Y轴的billboard效果,因此在属性里我们需要定义一个参数,来控制轴向约束的开关:


[csharp]  view plain  copy
 print ?
  1. _VerticalBillboarding("Vertical Restraints", Range(0,1)) = 1  


接下来主要工作是在vert函数里修改面片模型的顶点,进行顶点位置的计算,首先我们先获得面片中心到摄影机位置的向量;这个时候我们存在模型顶点颜色和uv2的数据就可以起作用了,下面的计算都是在object space下计算的。

[csharp]  view plain  copy
 print ?
  1. float3  centerOffs  = float3(float(0.5).xx - v.color.rg,0) * v.texcoord1.xyy;//利用事先存在模型顶点色和UV2的数据获得每个顶点相对与中心的偏移量  
  2. // float3   centerOffs  = float3(float(0.5).xx - v.color.rg,0) * v.color.bbb*255;  
  3. float3  centerLocal = v.vertex.xyz + centerOffs.xyz;//将顶点坐标偏移到中心位置  
  4. float3  viewerLocal = mul(_World2Object,float4(_WorldSpaceCameraPos,1));//获得观察点在object space下的坐标              
  5. float3  localDir    = viewerLocal - centerLocal;//获得面片中心到观察点的方向向量  
  6. localDir.y =localDir.y * _VerticalBillboarding;//如果_VerticalBillboarding为0,则面片则绕y轴旋转  


然后将得到的方向向量正则化,并将该方向向量作为Z轴,重构出面片中心面对视角的右手方向向量rightLocal和向上方向向量upLocal


[csharp]  view plain  copy
 print ?
  1. float3  rightLocal;  
  2. float3  upLocal;  
  3.   
  4. CalcOrthonormalBasis(normalize(localDir) ,rightLocal,upLocal);//localDir的正则化很重要!  


这里使用了CalcOrthonormalBasis(float3 dir,out float3 right,out float3 up),该函数作用就是根据dir重构出右手方向和向上方向up;这个函数是需要自己定义的 ,原型如下:



[csharp]  view plain  copy
 print ?
  1. void CalcOrthonormalBasis(float3 dir,out float3 right,out float3 up)  
  2. {  
  3.     up    = abs(dir.y) > 0.999f ? float3(0,0,1) : float3(0,1,0);       
  4.     right = normalize(cross(up,dir));         
  5.     up    = cross(dir,right);     
  6. }  


从上述原型可以看出dir,right,up是相互垂直的向量,从而构建出一个在坐标系统;在这里我们的输入时归一化后的localDir向量,因此得到一个在object space下的以localDir作为Z轴,rightLocal做X轴,upLocal做Y轴的新的坐标系,而localDir视线方向,所以rightLocal和upLocal 所构成的平面与视线垂直;最后我们根据这两个单位向量将之前偏移到面片中心的顶点坐标centerLocal重新按偏移量centerOffs偏移回去,构成一个垂直于视线的新的平面;


[csharp]  view plain  copy
 print ?
  1. float3  BBLocalPos = centerLocal - (rightLocal * centerOffs.x + upLocal * centerOffs.y);      


当然这个新的平面是在object space下的,还需要转换到屏幕投影空间;


[csharp]  view plain  copy
 print ?
  1. o.pos   = mul(UNITY_MATRIX_MVP, float4(BBLocalPos,1));//w分量设为1表明float4(BBLocalPos,1)是一个顶点  


VF版本代码01



[csharp]  view plain  copy
 print ?
  1. Shader "PengLu/Billboard/UnlitAddVF" {  
  2.   
  3. Properties {  
  4.     _MainTex ("Base texture", 2D) = "white" {}  
  5.     _VerticalBillboarding("Vertical Restraints", Range(0,1)) = 1  
  6. }  
  7.   
  8.       
  9. SubShader {  
  10.       
  11.       
  12.     Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }  
  13.       
  14.     Blend One One  
  15.     Cull Off Lighting Off ZWrite Off Fog { Color (0,0,0,0) }  
  16.       
  17.     LOD 100  
  18.       
  19.     CGINCLUDE     
  20.     #include "UnityCG.cginc"  
  21.   
  22.     sampler2D _MainTex;  
  23.     float _VerticalBillboarding;  
  24.   
  25.       
  26.     struct v2f {  
  27.         float4  pos : SV_POSITION;  
  28.         float2  uv  : TEXCOORD0;  
  29.     };  
  30.   
  31.     void CalcOrthonormalBasis(float3 dir,out float3 right,out float3 up)  
  32.     {  
  33.         up    = abs(dir.y) > 0.999f ? float3(0,0,1) : float3(0,1,0);       
  34.         right = normalize(cross(up,dir));         
  35.         up    = cross(dir,right);     
  36.     }  
  37.       
  38.       
  39.     v2f vert (appdata_full v)  
  40.     {  
  41.         v2f o;  
  42.               
  43.         float3  centerOffs  = float3(float(0.5).xx - v.color.rg,0) * v.texcoord1.xyy;  
  44.         //float3    centerOffs  = float3(float(0.5).xx - v.color.rg,0) * v.color.bbb*256;  
  45.         float3  centerLocal = v.vertex.xyz + centerOffs.xyz;  
  46.         float3  viewerLocal = mul(_World2Object,float4(_WorldSpaceCameraPos,1));              
  47.         float3  localDir    = viewerLocal - centerLocal;  
  48.                   
  49.         localDir.y =localDir.y * _VerticalBillboarding;  
  50.           
  51.         float3  rightLocal;  
  52.         float3  upLocal;  
  53.           
  54.         CalcOrthonormalBasis(normalize(localDir) ,rightLocal,upLocal);  
  55.   
  56.         float3  BBNormal   = rightLocal * v.normal.x + upLocal * v.normal.y;  
  57.         float3  BBLocalPos = centerLocal - (rightLocal * centerOffs.x + upLocal * centerOffs.y);      
  58.         o.uv    = v.texcoord.xy;  
  59.         o.pos   = mul(UNITY_MATRIX_MVP, float4(BBLocalPos,1));  
  60.                           
  61.         return o;  
  62.     }  
  63.     ENDCG  
  64.   
  65.   
  66.     Pass {  
  67.         CGPROGRAM  
  68.         #pragma vertex vert  
  69.         #pragma fragment frag  
  70.         #pragma fragmentoption ARB_precision_hint_fastest         
  71.         fixed4 frag (v2f i) : COLOR  
  72.         {         
  73.             return tex2D (_MainTex, i.uv.xy);  
  74.         }  
  75.         ENDCG   
  76.     }     
  77. }  
  78.   
  79.   
  80. }  

VF版本代码01效果:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值