0

跟随这个教程在这里

我设法创建了一个圆柱形广告牌(它利用几何着色器获取点并生成四边形)。问题是,当我移动相机使其高于广告牌(使用 gluLookat)时,广告牌不会旋转以真正面对相机(好像它是一个圆柱形广告牌)。

怎么弄成球形?

如果有人感兴趣,这里是稍微修改的几何着色器代码:

#version 330
//based on a great tutorial at http://ogldev.atspace.co.uk/www/tutorial27/tutorial27.html

layout (points) in;
layout (triangle_strip) out;
layout (max_vertices = 4) out;

uniform mat4 mvp;
uniform vec3 cameraPos;

out vec2 texCoord;

void main(){
    vec3 pos = gl_in[0].gl_Position.xyz;
    pos /= gl_in[0].gl_Position.w; //normalized device coordinates
    vec3 toCamera = normalize(cameraPos - pos);
    vec3 up = vec3(0,1,0);
    vec3 right = normalize(cross(up, toCamera)); //right-handed coordinate system
    //vec3 right = cross(toCamera, up); //left-handed coordinate system

    pos -= (right*0.5);
    gl_Position = mvp*vec4(pos,1.0);
    texCoord = vec2(0,0);
    EmitVertex();

    pos.y += 1.0;   
    gl_Position = mvp*vec4(pos,1.0);
    texCoord = vec2(0,1);
    EmitVertex();

    pos.y -= 1.0;   
    pos += right;
    gl_Position = mvp*vec4(pos,1.0);
    texCoord = vec2(1,0);
    EmitVertex();

    pos.y += 1.0;       
    gl_Position = mvp*vec4(pos,1.0);
    texCoord = vec2(1,1);
    EmitVertex();
}

编辑:正如我之前所说,我尝试过将 3,3-submatrix 设置为身份的方法。我可能已经解释了错误的行为,但是这个 gif 应该做得更好: 这就是我的意思

在上图中,相机使用标识子矩阵方法与广告牌(红色)一起旋转。但是,广告牌不应穿过表面(白色),它应该保持正确的位置并始终位于表面的一侧,这不会发生。

4

3 回答 3

1

创建广告牌的另一种方法是将几何着色器扔掉并像这样手动进行:

Vector3 DiffCamera = Billboard.position - Camera.position;
Vector3 UpVector   = new Vector3(0.0f, 1.0f, 0.0f);

Vector3 CrossA     = DiffCamera.cross(UpVector).normalize(); // (Step A)
Vector3 CrossB     = DiffCamera.cross(CrossA).normalize();   // (Step B)

// now you can use CrossA and CrossB and the billboard position to calculate the positions of the edges of the billboard-rectangle

// like this
Vector3 Pos1 = Billboard.position + CrossA + CrossB;
Vector3 Pos2 = Billboard.position - CrossA + CrossB;
Vector3 Pos3 = Billboard.position + CrossA - CrossB;
Vector3 Pos4 = Billboard.position - CrossA - CrossB;

我们在步骤 A 中计算叉积,因为我们想要广告牌的水平对齐方向。

在步骤 B 中,我们针对垂直方向执行此操作。

为场景中的每个广告牌执行此操作。

或更好的几何着色器(只是尝试)

vec3 pos = gl_in[0].gl_Position.xyz;
pos /= gl_in[0].gl_Position.w; //normalized device coordinates
vec3 toCamera = normalize(cameraPos - pos);
vec3 up = vec3(0,1,0);
vec3 CrossA = normalize(cross(up, toCamera));
vec3 CrossB = normalize(cross(CrossA, toCamera));

// set coordinates of the 4 points
于 2013-04-10T12:14:17.093 回答
1

Just reset the top left 3×3 subpart of the modelview matrix to identity, leaving the 4th column and row as it is, i.e.:

1 0 0 …
0 1 0 …
0 0 1 …
… … … …

UPDATE World space axis following billboards

The key insight into efficiently implementing aligned billboards is to realize how they work in view space. By definition the normal vector of a billboard in view space is Z = (0, 0, 1). This leaves only one free parameter, namely the rotation of the billboard around this axis. In a view aligned billboard the billboard right and up axes are merely forced to be view X and Y. This is what setting the upper left 3×3 of the modelview matrix does.

Now when we want the billboard be aligned to a certain axis within the scene yet still face the viewer, the only parameter we can vary is the billboards rotation. For this we do the following:

In world space we choose an axis that should be the up axis of the billboard. Note that if the viewing axis is parallel to the billboard up axis the following steps become singular, i.e. the rotation of the billboard is undefined. You have to deal with this in some way, that I leave undefined here.

This chosen axis we bring into view space. Now an axis is the same kind of thing like a normal, i.e. a direction, so we transform it the same way as we do with normals. We transform it by the inverse transpose of the modelview matrix as you to with normals; note that since we defined the axis in world space, we need to actually use the inverse transpose of the world to view transformation matrix then.

The transformed major axis of the billboard is now in view space. Next step is to orthogonalize it to the viewing direction. For this you use the Gram-Schmidt method. Now we got the Z and the Y column of the billboard transform. Remains the X column, which we get by taking the cross product of the Z with the Y column.

于 2013-04-10T11:47:54.093 回答
0

如果有人想知道我是如何解决这个问题的。
我的解决方案基于 Quonux 的回答,唯一的问题是当相机正上方时广告牌会旋转得非常快(当up矢量几乎平行于相机外观矢量时)。这种奇怪的行为是使用叉积来查找right向量的结果:当相机悬停在广告牌的顶部时,叉积会改变它的符号,right向量的方向也会改变。这就解释了发生的旋转。
所以我所需要的就是right使用其他方式找到一个向量。因为我知道相机的旋转角度(水平和垂直),我决定用它来找到一个right向量:

rotatedRight = Vector4.Transform(unRotatedRight, Matrix4.CreateRotationY((-alpha)));

和几何着色器:

...
uniform vec3 rotRight;
uniform vec3 cameraPos;

out vec2 texCoord;

void main(){

vec3 pos = gl_in[0].gl_Position.xyz;
pos /= gl_in[0].gl_Position.w; //normalized device coordinates
vec3 toCamera = normalize(cameraPos - pos);

vec3 CrossA = rotRight;
... (Continues as Quonux's code)
于 2013-04-11T09:22:16.443 回答