[关闭]
@cybercser 2015-11-20T18:21:52.000000Z 字数 2286 阅读 98

第十八课(一):公告板

OpenGL 教程

公告板是3D世界中的2D元素。它既不是最顶层的2D菜单,也不是可以随意转动的3D平面,而是介于两者之间的一种元素,比如游戏中的血条。

公告板可处于某个特定位置,并自动调整朝向使自己始终面向摄像机。

方案1:2D法

2D法十分简单。只需计算出点在屏幕空间的坐标,然后在该处显示2D文本(参见第十一课)即可。

  1. // Everything here is explained in Tutorial 3 ! There's nothing new.
  2. glm::vec4 BillboardPos_worldspace(x,y,z, 1.0f);
  3. glm::vec4 BillboardPos_screenspace = ProjectionMatrix * ViewMatrix * BillboardPos_worldspace;
  4. BillboardPos_screenspace /= BillboardPos_screenspace.w;
  5. if (BillboardPos_screenspace.z < 0.0f){
  6. // Object is behind the camera, don't display it.
  7. }

就这么搞定了!

2D法优点是简单易行,无论点与相机距离远近,公告板始终保持大小不变。缺点在于文本总是显示在最顶层,有可能会遮挡其他物体,影响渲染。

方案2:3D法

与2D法相比,3D法常常效果更好,也没复杂多少。
我们的目的就是无论相机如何移动,都要让公告板mesh正对着摄像机:

2a

可将此视为模型矩阵的构造问题之简化版。基本思路是将公告板始终正对于摄像机的中心The idea is that each corner of the billboard is at the center position, displaced by the camera’s up and right vectors :

principle

当然,我们仅仅知道世界空间中的公告板中心位置,因此还需要摄像机在世界空间中的up/right向量。

在相机空间,相机的up向量为(0,1,0)。要把up向量变换到世界空间,只需乘以观察矩阵的逆矩阵(由相机空间变换至世界空间的矩阵)。

用数学公式表示即:

CameraRight_worldspace = {ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]}
CameraUp_worldspace = {ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]}

接下来,顶点坐标的计算就很简单了:

  1. vec3 vertexPosition_worldspace =
  2. particleCenter_wordspace
  3. + CameraRight_worldspace * squareVertices.x * BillboardSize.x
  4. + CameraUp_worldspace * squareVertices.y * BillboardSize.y;

效果如下。怎么样,是不是很简单?

2

为了保证内容完整性,这里给出squareVertices的数据:

  1. // The VBO containing the 4 vertices of the particles.
  2. static const GLfloat g_vertex_buffer_data[] = {
  3. -0.5f, -0.5f, 0.0f,
  4. 0.5f, -0.5f, 0.0f,
  5. -0.5f, 0.5f, 0.0f,
  6. 0.5f, 0.5f, 0.0f,
  7. };

方案3:固定大小3D法

正如上面所看到的,公告板大小随着相机与之的距离变化。有些情况下的确需要这样的效果,但血条这类公告板则需要保持大小不变。

  1. vertexPosition_worldspace = particleCenter_wordspace;
  2. // Get the screen-space position of the particle's center
  3. gl_Position = VP * vec4(vertexPosition_worldspace, 1.0f);
  4. // Here we have to do the perspective division ourselves.
  5. gl_Position /= gl_Position.w;
  6. // Move the vertex in directly screen space. No need for CameraUp/Right_worlspace here.
  7. gl_Position.xy += squareVertices.xy * vec2(0.2, 0.05);

3

方案4:限制垂直旋转法

一些引擎以公告板表示远处的树和灯。不过,这些树可不能任意转向,必须是竖直的。So you need an hybrid system that rotates only around one axis.(存疑待查)

这个方案作为练习留给读者。

© http://www.opengl-tutorial.org/

Written with Cmd Markdown.

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注