OpengL ES 2.0 Billboard:这个数学有什么问题?

时间:2012-01-25 22:03:05

标签: view opengl-es-2.0 projection

下面粘贴的是我在线发现的两种方法的伪代码,用于为场景中的3d对象生成广告牌转换矩阵。编辑:请注意这是一个可能有超过4个顶点的对象 - 我正在尝试计算一个3d对象的完整广告牌转换矩阵,而不是“单个四面向相机”广告牌。< / p>

此转换旨在将对象(“广告牌”)定向为面向相机,同时保持直立。

这两种方法都没有奏效,大多数情况下我的场景中什么都没有显示,即坐标已经变换了视线。

任何人都可以确定着色器代码行中的计算或矩阵乘法的排序是否存在缺陷?我非常感谢你的建议。

// Vectors:
//
// bbPos    Billboard position.
// bbUp     Billboard up vector.
// bbRight  Billboard right vector.
//
// camPos   Camera position.
// camUp    Camera up vector.
// camRight Camera right vector.

// Approach 1:
vec3 bbLook = bbPos - camPos;
bbLook.normalize();

vec3 bbRight = cross(camUp, bbLook);
bbRight.normalize();

vec3 bbUp = cross(bbLook, bbRight);
bbUp.normalize();

mx4 a_billboard = (     bbRight.x,  bbRight.y,  bbRight.z,  0.0f,
                bbUp.x,     bbUp.y,     bbUp.z,     0.0f,
                bbLook.x,   bbLook.y,   bbLook.z,   0.0f,
                bbPos.x,    bbPos.y,    bbPos.z,    1.0f);

// Approach 2:
vec3 bbLook = camPos - bbPos;
bbLook.normalize();

vec3 bbRight = cross(camUp, bbLook);
bbRight.normalize();

vec3 bbUp = cross(bbLook, bbRight);
bbUp.normalize();

mx4 a_billboard = ( bbRight.x,  bbUp.x,     bbLook.x,   bbPos.x,
            bbRight.y,  bbUp.y,     bbLook.y,   bbPos.y,
            bbRight.z,  bbUp.z,     bbLook.z,   bbPos.z,
            0.0f,       0.0f,       0.0f,       1.0f);

在顶点着色器中,以下代码组合了p(rojection),wv(view * world),m(odel)和billboard矩阵:

    gl_Position = p * a_billboard * wv * m * vec4(a_position.xyz, 1.0);

1 个答案:

答案 0 :(得分:0)

干杯,第一个缺陷就是你修改了你的bbUp向量。这需要保持固定(如果你改变它,你怎么期望它保持直立?)。您可以使用:

vec3 bbUp = vec3(0, 1, 0); // up

vec3 bbLook = bbPos - camPos;
bbLook.normalize();

vec3 bbRight = cross(bbUp, bbLook);
bbRight.normalize();
// calculate right vector from look vector

或:

vec3 bbRight = camRight - bbUp * dot(bbUp, camRight); // use the Gram-Schmidt process
bbRight.normalize();
// just take camRight and make it orthogonal to bbUp

bbLook向量需要在两种情况下重新计算为bbUp和bbRight的交叉积。这样你的数学就出了什么问题。

另一个错误的是,使用矩阵渲染广告牌是无效的,因为每个广告牌需要一个这样的矩阵。最好将广告牌中心位置存储在顶点属性数组中,并使用纹理坐标计算广告牌顶点(这意味着广告牌中心位置使用不同的texcoords重复4次)。一个例子:

float[] billboard = {x, y, z, 0, 0, x, y, z, 1, 0, x, y, z, 1, 1, x, y, z, 0, 1};

这使您可以使用如下的顶点着色器一次绘制多个广告牌:

attribute vec3 vCenter;
attribute vec2 texCoord;

uniform matrix4 mvp;

uniform vec3 bbUp, bbRight;

varying vec2 texCoordOut;

void main()
{
    vec3 corner = vCenter + (texCoord.x - .5) * 2.0 * bbRight +
                            (texCoord.y - .5) * 2.0 * bbUp;
    // this calculates corner position (texcoords need to be rescaled from [0 1] to [-1 1])

    gl_Position = mvp * corner;
    texCoordOut = texCoord;
    // write position, texcoords
}

这使得可以渲染具有相同向上和向右向量的许多广告牌。但是,您可以将向上矢量作为另一个顶点属性提供,以便您的每个广告牌都拥有它自己的轴。你可以在这里查看一个小小的演示:http://www.fit.vutbr.cz/~ipolok/tam/10_Billboarding.zip