其实做一个Billboard系统本身并不难。但是要集成一个使用容易,效率高的Billboard系统还有些技巧的。
主要得问题在于,美术在3Ds Max里可以随意放置很多Billboard,程序导出以后,这些物体通常为单独的Quad。这样就会严重导致渲染的效率低下。
我们希望,美术还是依照自由的方式在场景放置Billboard。设置这些Billboard是可以任意形状,不限于矩形。在导出之前,美术可以将这些物体Attach成一个Mesh。当然也可以导出后由Evolution3D的模型优化工具来塌陷。
与一般物体的区别就在于,美术需要告诉导出插件,这些是一个Billboard物体。
Evol3D系统中的Billboard系统就是为了目的设计。
方案:
1. Billboard面向摄像机的特性在 Vertex Shader中来计算。
2. 模型数据中保存一个平面中心的位置,在Evol3D中,这个数据目前保存在Binormal中。因为一般的Billboard是不会参与法线贴图光照计算的。如果计算那就乱了。
因为在View Matrix,我们可以知道摄像机的UP/Left/等信息。所有只要将当前顶点的位置减去平面中心的位置,然后跟Tangent和Binormal做个点积。 就可知道应该可以计算出这个点在屏幕上的位置了。
这样的Billboard对引擎的上层来说,是极为透明的,只要指定不同的材质就可以了。
VS如下。
PS_INPUT main( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
float4 inPos = input.Pos;
float4x4 _matWorld = matWorld;
if(input.Binormal.w <= 0.01f)
{
float3 polyCen = input.Binormal.xyz;
float3 _pos = vecMul( float4(polyCen.xyz , 1.0f) , _matWorld).xyz;
float3 _delta = input.Pos.xyz - polyCen;
#ifdef _D3D9_
float3 vX = float3(matView[0][0] , matView[1][0] , matView[2][0]);
float3 vY = float3(matView[0][1] , matView[1][1] , matView[2][1]);
#else
float3 vX = float3(matView[0][0] , matView[0][1] , matView[0][2]);
float3 vY = float3(matView[1][0] , matView[1][1] , matView[1][2]);
#endif
float3 _tan = normalize(input.Tan.xyz);
float3 _bin = normalize( cross(input.Nor , input.Tan ).xyz);
float _vLen = dot(_delta.xyz , _bin);
float _uLen = dot(_delta.xyz , _tan);
inPos.xyz = _pos.xyz + _uLen * vX + _vLen * vY;
}
output.Tex = float4(input.Tex , 1.0f , 1.0f);
output.Tex1 = float4(input.Tex1, 1.0f , 1.0f);
float4 vertexColor = input.Color.xyzw * MaterialDiffuse;
float4 _Position = inPos;
float4 _Normal = input.Nor;
float4 _Tangent = input.Tan;
float4x4 matModelView = matMul(_matWorld , matView);
output.wPosition = vecMul ( _Position , matView );
output.wNormal = transNormal( _Normal , matModelView);
output.wTangent = transNormal( _Tangent , matModelView);
output.tPos = vecMul( output.wPosition , matProject );
output.Pos = output.tPos;
output.Color = vertexColor;
output.wPosition.w = output.Pos.w;
return output;
}