BillboardAsset 描述如何渲染公告牌。
公告牌是一种以更简单的方式绘制远处的复杂 3D 对象的细节级别 (LOD) 方法。由于对象很远,因此通常不需要绘制对象的全部细节,因为它在屏幕上的大小很小,并且它在摄像机视图中作为焦点的可能性很低。可将对象预渲染为纹理,该纹理可在面向摄像机的非常简单的平面几何形状(通常只是四边形)网格上使用,这种网格称为公告牌。在很远的距离,对象不会显著改变其相对于摄像机的方向,因此在无需从模型重新绘制的情况下,公告牌与其所代表的对象在每一帧看上去都差别很小。通过 BillboardAsset 类可创建从多个方向渲染的公告牌,从而使 BillboardAsset 能够从任何近乎水平的视点有效表示低细节级别的对象。
BillboardAsset 通常是通过导入 SpeedTree 资源创建的。知道如何描述公告牌后,您还可以创建自己的公告牌。
SpeedTree 公告牌几何图形通常比普通四边形更复杂。使用更多顶点来剪切公告牌图像的空部分可能提高渲染性能,因为图形系统不必绘制这些多余的透明像素。您可以通过 BillboardAsset.vertices 和 BillboardAsset.indices 访问几何图形数据。
在 UV 空间中会考虑所有顶点(参见以下图 1),因为几何图形即将通过公告牌图像进行纹理化。通过了解公告牌的宽度、高度、底部以及公告牌当前的朝向,UV 顶点被轻松扩展到 3D 空间顶点。假设我们有一个朝向负 Z 轴的位于 (0,0,0) 的公告牌,此 3D 空间坐标计算如下:
X = (u - 0.5) * width
Y = v * height + bottom
Z = 0
图 1:如何将 UV 顶点扩展到 3D 顶点
为了以类似于真实 3D 网格的方式显示公告牌样式的内容,SpeedTree 公告牌根据当前视图方向从几个预渲染的图像中选择合适的图像。以下图 2 中的图像是通过以不同视角捕获 3D 树的渲染图像创建的,这些图像均匀分布在 Y 轴周围。第一个图像始终从正 X 轴方向开始(或者如果您从上方看想象成一个单位圆,则为 0°)。
图 2:如何烘焙八个广告牌图像
应将所有图像一同镶嵌在一个纹理中。在该图集中,每个图像均被表示为 {left u, top v, width in u, height in v} 的 Vector4。您可以通过 BillboardAsset.imageTexCoords 访问所有这些图像。SpeedTree Modeler 始终将法线纹理与漫射纹理一同导出,以便更加近似于光照,并且它与漫射纹理共享相同的图集布局。
构建了 BillboardAsset 后,使用 BillboardRenderer 来渲染它。
bottom | 低于地面的公告牌高度。 |
height | 公告牌的高度。 |
imageCount | 从不同角度观看公告牌时可切换的预渲染图像数。 |
indexCount | 公告牌网格中的索引数。 |
material | 用于渲染的材质。 |
vertexCount | 公告牌网格中的顶点数。 |
width | 公告牌的宽度。 |
BillboardAsset | 构建一个新的 BillboardAsset。 |
GetImageTexCoords | 获取公告牌图像纹理坐标数据的数组。 |
GetIndices | 获取公告牌网格的索引。 |
GetVertices | 获取公告牌网格的顶点。 |
SetImageTexCoords | 设置公告牌图像纹理坐标数据的数组。 |
SetIndices | 设置公告牌网格的索引。 |
SetVertices | 设置公告牌网格的顶点。 |
hideFlags | Should the object be hidden, saved with the Scene or modifiable by the user? |
name | 对象的名称。 |
GetInstanceID | 返回对象的实例 ID。 |
ToString | 返回 GameObject 的名称。 |
Destroy | 删除 GameObject、组件或资源。 |
DestroyImmediate | 立即销毁对象 /obj/。强烈建议您改用 Destroy。 |
DontDestroyOnLoad | Do not destroy the target Object when loading a new Scene. |
FindObjectOfType | 返回第一个类型为 type 的已加载的激活对象。 |
FindObjectsOfType | 返回所有类型为 type 的已加载的激活对象的列表。 |
Instantiate | 克隆 original 对象并返回克隆对象。 |
bool | 该对象是否存在? |
operator != | 比较两个对象是否引用不同的对象。 |
operator == | 比较两个对象引用,判断它们是否引用同一个对象。 |