如何制作广告牌球形

时间:2013-04-10 11:45:53

标签: opengl 3d directx glsl opentk

关注此here

我设法创建了一个圆柱形广告牌(它使用了一个几何着色器,它可以获取点并生成四边形)。问题是,当我移动相机使其高于广告牌(使用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子矩阵的方法。我可能已经解释了行为错误,但这个gif应该做得更好: This is what I mean by "incorrect moving"

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

3 个答案:

答案 0 :(得分: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中,我们为垂直方向做。

为场景中的每个billbaord执行此操作。

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

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

答案 1 :(得分:0)

只需将模型视图矩阵的左上角3×3子部分重置为同一性,保留第4列和第7行,即:

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

更新广告牌之后的世界空间轴

有效实施对齐广告牌的关键见解是实现 他们如何在视野中工作。根据定义,广告牌的法线向量 视图空间是Z =(0,0,1)。这只留下一个自由参数,即 广告牌围绕此轴旋转。在视图中对齐广告牌 广告牌右和上轴仅被强制为视图X和Y.这就是 设置模型视图矩阵的左上角3×3。

现在我们希望广告牌与场景中的某个轴对齐 但仍面向观众,我们可以改变的唯一参数是广告牌 回转。为此,我们执行以下操作:

在世界空间中,我们选择一个应该是广告牌上轴的轴。 请注意,如果观察轴与广告牌上行轴平行,则如下所示 步骤变得单一,即广告牌的旋转是不确定的。你有 以某种方式处理这个,我在这里留下未定义。

我们将这个选定的轴带入视图空间。现在轴是同一种 像普通的东西,即方向,所以我们改变它的方式和我们一样 与法线。我们通过模型视图矩阵的逆转置对其进行变换 和你一样正常;请注意,由于我们在世界空间中定义了轴,我们 需要实际使用世界的逆转置来查看转换 矩阵然后。

广告牌的转换主轴现在位于视图空间中。下一步是 将其与观察方向正交化。为此你使用Gram-Schmidt 方法。现在我们得到了广告牌变换的Z和Y列。遗迹 X列,我们通过采用Z与Y列的叉积得到。

答案 2 :(得分: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)