广告牌效果既是不论物体与摄像机的角度,被渲染物体总是正对着摄像机。
此技术广泛利用于粒子效果中,例如Unity内置的Particle System。下文将要介绍如何在Shader中实现广告牌效果。
在视空间对顶点进行重定位
(图1:摄像机绑定在立方体上,立方体进行原地旋转,雪花使用里广告牌渲染,总是正对着摄像机)
此项技术的核心是在视空间(view space)将顶点进行重新定位。
网上有一个简单的例子,https://en.wikibooks.org/wiki/Cg_Programming/Unity/Billboards
...
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));
...
看以上这行代码理解广告牌的两处核心逻辑:
1,先看mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
float4(0.0, 0.0, 0.0, 1.0)代表顶点所属物体在Model空间中的位置,mul MV矩阵后,Model空间转到了视空间。在此阶段x,y轴方向既是屏幕的xy轴。在这次mul运算之后,所有的顶点位置都集中到了被渲染物体的中心点,并等待对它们进行重新定位。由于视空间换行是一个必须过程,相比于在其他空间重定位还需要再寻找摄像机角度,这里操作可以省去一次矩阵乘法运算。
2,再看+ float4(input.vertex.x, input.vertex.y, 0.0, 0.0):
由于vertex.xy是当前顶点相对与模型中心点的,已知中心点位置在2D平面中用vertex.xy就可以对顶点进行定位了,将顶点的位置分别在视空间中向x方向偏移vertex.x,向y方向偏移vertex.y,就相当于以float4(0.0, 0.0, 0.0, 1.0)为中心,在视空间重新归位了顶点位置。而由于视空间的z轴与摄像机是一致的,所以所有重新归位xy坐标的顶点连接起来的图元一定是面向摄像机的。
以上的代码试用于当2D图元的顶点是以自身坐标轴中的xy分布的,例如Unity内置的立方体quad,如果是其他情况,例如plane的顶点是在xz平面分布,那么代码就要改为+ float4(input.vertex.x, input.vertex.z, 0.0, 0.0):
(图2:plane的顶点以xz分布。绿色箭头指向y,兰z,红x)
(图3:quad的顶点分布在xy平面上)
应用到复杂网格
以上Shader代码只适用于渲染单个quad,或plane的mesh。在用同一个Shader渲染复杂网格的情况下,需要用每个基础图元单位的中心点取代上文中的物体中心点‘float(0,0,0,1)’。
(图4:在以两个三角形组成的quad为基本单位的线型网格中实现粒子广告牌,所有的亮点都在quad中心点并正对摄像机)
(图5:在以两个三角形组成的quad为基本单位零散分布在3D空间中,它们都属于同一个mesh)
以图4图5为例,可以在进入渲染管线之前的顶点属性定义阶段(C#脚本)计算好quad的中心点位置,然后赋值给Mesh的任意属性,Shader在顶点着色器通过相应的语义获取。也可以在Shader的几何着色器中进行计算,因为两个三角形是对称的,只要用三个顶点的位置计算斜边中点就可得出quad中心点。不论哪种实现,计算公式为:
v c e n t e r = ( v 0 − v 3 ) / 2 + v 3 v_{center}=(v_0-v_3)/2+v_3 vcenter=(v0−v3)/2+v3
v 0 v_0 v0与 v 3 v_3 v3为quad对角顶点位置, v c e n t e r v_{center} vcenter为quad中心点位置,具体实现代码就不再赘述。
2020-8-15:review