关注此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应该做得更好:
在上图中,使用标识子矩阵方法使用广告牌(红色)旋转相机。 然而,广告牌不应该穿过表面(白色),它应该正确地保持它的位置并且始终位于表面的一侧,这不会发生。
答案 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)