第十八课:公告板与粒子1

来源:互联网 发布:Linux 中xargs 编辑:程序博客网 时间:2024/05/22 14:45

翻译自:http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/billboards/


Billboards

公告板

Billboards are 2D elements incrusted in a 3D world. Not a 2D menu on top of everything else; not a 3D plane around which you can turn; but something in-between, like health bars in many games.

公告板是一个3D世界的2D元素,而不是一个在所有物件之上的2D菜单,也不是一个你可以随便转动的3D平面,而是一个介于两者之间的东西,比如许多游戏中的血条。

What’s different with billboards is that they are positionned at a specific location, but their orientation is automatically computed so that it always faces the camera.

公告板之间的区别在于位置的不同,但是他们的朝向是自动计算的,它永远面向摄像机。

Solution #1 : The 2D way

方法#1:2D方法

This one is supra-easy.

这个方法很简单。

Just compute where your point is on screen, and display a 2D text (see Tutorial 11) at this position.

只计算你的点在屏幕上的位置,然后在这个未知显示一个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 6 if (BillboardPos_screenspace.z < 0.0f){7     // Object is behind the camera, don't display it.8 }

Ta-dah !

On the plus side, this method is really easy, and the billboard will have the same size regardless of its distance to the camera. But 2D text is always displayed on top of everything else, and this can/will mess up the rendering and show above other objects.

从好的方面想,这个方法相当简单,billboard的大小也不会因为离开摄像机的距离发生变化。但2D文本会永远显示在其他东西之上,这在渲染其他物件的时候会发生混淆。

Solution #2 : The 3D way

方法#2:3D方法

This one is usually better and not much more complicated.

The goal is to keep the mesh aligned with the camera, even when the camera moves :

这个方法相对更好而且也没那么的复杂。

这个方法的目的是与摄像机的方法对齐,即便摄像机发生移动。

You can view this problem as generating an appropriate Model matrix, even though it’s is much simpler than that.

你可以把这个问题看成是生成一个合适的Model Matrix,甚至比这更简单。

The idea is that each corner of the billboard is at the center position, displaced by the camera’s up and right vectors :

这个做法是公告板的每个角都在中心位置,以摄像机up向量right向量确定的方向摆放。


Of course, we only know the billboard’s center position in world space, so we also need the camera’s up/right vectors in world space.

当然,我们只知道公告板在世界坐标系的中心位置,所以我们也需要摄像机在世界坐标系中的up/right向量。

In camera space, the camera’s up vector is (0,1,0). To get it in world space, just multiply this by the matrix that goes from Camera Space to World Space, which is, of course, the inverse of the View matrix.

在相机坐标系中,摄像机的up向量是(0,1,0)。转换到世界坐标系中,只需要乘上相机坐标系到世界坐标系的矩阵。也就是View Matrix的逆矩阵。

An easier way to express the same math is :

一个简单的解释的数学解释方法是:

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

Once we have this, it’s very easy to compute the final vertex’ position :

一旦我们有了这个矩阵,很容易计算最终的顶点位置:

1 vec3 vertexPosition_worldspace =2     particleCenter_wordspace3     + CameraRight_worldspace * squareVertices.x * BillboardSize.x4     + CameraUp_worldspace * squareVertices.y * BillboardSize.y;
  • particleCenter_worldspace is, as its name suggests, the billboard’s center position. It is specified with an uniform vec3.
  • squareVertices is the original mesh. squareVertices.x is -0.5 for the left vertices, which are thus moved towards the left of the camera (because of the *CameraRight_worldspace)
  • BillboardSize is the size, in world units, of the billboard, sent as another uniform.
  • particleCenter_worldspace如图它的名字,是公告板的中心位置。它由一个uniform变量vec3来指定
  • squareVertices是原始的网格。squareVertices.x为-0.5对于坐标的顶点而言,就是移向摄像机的左边
  • BillboardSize表示公告板的大小,以一个uniform变量的形式传入
And presto, here's the result. Wasn't this easy ?
以下为显示结果,简单么?

For the record, here’s how squareVertices is made :

以下是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  };

Solution #3 : The fixed-size 3D way

方法3#:固定大小的3D方法

As you can see above, the size of the billboard changes with respect to the camera’s distance. This is the expected result in some cases, but in others, such as health bars, you probably want a fixed-size instead.

如上所示,公告板的大小随着摄像机的距离而变化。这在某些情况下是符合预期的,但在其他情况,比如血条,你可能希望有一个固定的大小。

Since the displacement between the center and a corner must be fixed in screen-space, that’s exactly what we’re going to do : compute the center’s position in screen space, and offset it.

既然公告板中心到边缘的距离在屏幕空间中必须被固定,我们需要做以下事情:计算公告板在屏幕空间的中心位置,然后对它做偏移。

1 vertexPosition_worldspace = particleCenter_wordspace;2 // Get the screen-space position of the particle's center3 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 7 // Move the vertex in directly screen space. No need for CameraUp/Right_worlspace here.8 gl_Position.xy += squareVertices.xy * vec2(0.2, 0.05);

Remember that at this stage of the rendering pipeline, you’re in Normalized Device Coordinates, so between -1 and 1 on both axes : it’s not in pixels.

If you want a size in pixels, easy : just use (ScreenSizeInPixels / BillboardSizeInPixels) instead of BillboardSizeInScreenPercentage.

记住在渲染管线的这个阶段,你在一个标准化的设备坐标系中,它在两个轴上都是在-1到1之间,而不是以像素计数。如果你想要得到像素位置,使用 (ScreenSizeInPixels / BillboardSizeInPixels)取代BillboardSizeInScreenPercentage。

Solution #4 : Vertical rotation only

方法#4只进行垂直旋转

Some systems model faraway trees and lamps as billboards. But you really, really don’t want your tree to be bent : it MUST be vertical. So you need an hybrid system that rotates only around one axis.

在某些系统中将远处的树和等作为公告板。你需要的是你的树看上去不是弯曲的,它必须是垂直的。所以你需要一个混合系统,它只绕某一个轴进行旋转。

Well, this one is left as an exercise to the reader !

这个就留给练习者自己去渲染!

0 0
原创粉丝点击