【问题标题】:Opengl Billboard matrixOpengl 广告牌矩阵
【发布时间】:2013-08-05 00:06:02
【问题描述】:

我正在为 OpenGL 中的专有网格和动画格式编写查看器。

在渲染过程中,会为每个骨骼(节点)创建一个变换矩阵,并将其应用于骨骼所连接的顶点。

骨头可能会被标记为“广告牌”,众所周知,这意味着它应该始终面向相机。

因此我们的想法是为该骨骼生成一个矩阵,该矩阵在用于转换它所连接的顶点时,会导致顶点被显示在广告牌上。

在我的测试模型上应该是这样的:

但目前看起来是这样的:

请注意,尽管它的方向不正确,但它是广告牌。就像无论相机看哪个方向一样,这些顶点始终在那个方向上朝向那个方向。

我为标记为广告牌的骨骼生成矩阵的代码是:

    mat4        view;
    glGetFloatv(GL_MODELVIEW_MATRIX, (float*)&view);

    vec4 camPos = vec4(-view[3].x, -view[3].y, -view[3].z,1);
    vec3 camUp  = vec3(view[0].y, view[1].y, view[2].y);

    // zero the translation in the matrix, so we can use the matrix to transform
    // camera postion to world coordinates using the view matrix
    view[3].x = view[3].y = view[3].z = 0;

    // the view matrix is how to get to the gluLookAt pos from what we gave as
    // input for the camera position, so to go the other way we need to reverse
    // the rotation.  Transposing the matrix will do this.
    {
        float * matrix = (float*)&view;
        float   temp[16];
        // copy this into temp
        memcpy(temp, matrix, sizeof(float) * 16);
        matrix[1] = temp[4];    matrix[4] = temp[1];
        matrix[2] = temp[8];    matrix[8] = temp[2];
        matrix[6] = temp[9];    matrix[9] = temp[6];
    }

    // get the correct position of the camera in world space
    camPos  = view * camPos;

    //vec3 pos = pivot;

    vec3 look = glm::normalize(vec3(camPos.x-pos.x,camPos.y-pos.y,camPos.z-pos.z));
    vec3 right = glm::cross(camUp,look);
    vec3 up = glm::cross(look,right);


    mat4 bmatrix;
    bmatrix[0].x = right.x;
    bmatrix[0].y = right.y;
    bmatrix[0].z = right.z;
    bmatrix[0].w = 0;

    bmatrix[1].x = up.x;
    bmatrix[1].y = up.y;
    bmatrix[1].z = up.z;
    bmatrix[1].w = 0;

    bmatrix[2].x = look.x;
    bmatrix[2].y = look.y;
    bmatrix[2].z = look.z;
    bmatrix[2].w = 0;

    bmatrix[3].x = pos.x;
    bmatrix[3].y = pos.y;
    bmatrix[3].z = pos.z;
    bmatrix[3].w = 1;

我正在使用 GLM 进行相关数学运算。

虽然这部分代码基于教程here,但其他部分代码基于类似于我正在构建的开源程序。但是,该程序是为 DirectX 编写的,我没有太多运气直接转换。用于广告牌的(工作)directX 代码如下所示:

    D3DXMatrixRotationY(&CameraRotationMatrixY, -Camera.GetPitch());
    D3DXMatrixRotationZ(&CameraRotationMatrixZ, Camera.GetYaw());
    D3DXMatrixMultiply(&CameraRotationMatrix, &CameraRotationMatrixY, &CameraRotationMatrixZ);
    D3DXQuaternionRotationMatrix(&CameraRotation, &CameraRotationMatrix);
    D3DXMatrixTransformation(&CameraRotationMatrix, NULL, NULL, NULL, &ModelBaseData->PivotPoint, &CameraRotation, NULL);

    D3DXMatrixDecompose(&Scaling, &Rotation, &Translation, &BaseMatrix);
    D3DXMatrixTransformation(&RotationMatrix, NULL, NULL, NULL, &ModelBaseData->PivotPoint, &Rotation, NULL);

    D3DXMatrixMultiply(&TempMatrix, &CameraRotationMatrix, &RotationMatrix);
    D3DXMatrixMultiply(&BaseMatrix, &TempMatrix, &BaseMatrix);

注意结果存储在directX版本的baseMatrix中。

EDIT2:这是我根据 datenwolf 的建议尝试修改代码时提出的代码。我很确定我仍然犯了一些错误。这种尝试会产生严重扭曲的结果,对象的一端直接位于相机中。

    mat4        view;
    glGetFloatv(GL_MODELVIEW_MATRIX, (float*)&view);

    vec3 pos = vec3(calculatedMatrix[3].x,calculatedMatrix[3].y,calculatedMatrix[3].z);

    mat4 inverted = glm::inverse(view);

    vec4 plook = inverted * vec4(0,0,0,1);
    vec3 look = vec3(plook.x,plook.y,plook.z);
    vec3 right = orthogonalize(vec3(view[0].x,view[1].x,view[2].x),look);
    vec3 up = orthogonalize(vec3(view[0].y,view[1].y,view[2].y),look);

    mat4 bmatrix;
    bmatrix[0].x = right.x;
    bmatrix[0].y = right.y;
    bmatrix[0].z = right.z;
    bmatrix[0].w = 0;

    bmatrix[1].x = up.x;
    bmatrix[1].y = up.y;
    bmatrix[1].z = up.z;
    bmatrix[1].w = 0;

    bmatrix[2].x = look.x;
    bmatrix[2].y = look.y;
    bmatrix[2].z = look.z;
    bmatrix[2].w = 0;

    bmatrix[3].x = pos.x;
    bmatrix[3].y = pos.y;
    bmatrix[3].z = pos.z;
    bmatrix[3].w = 1;

    calculatedMatrix = bmatrix;

vec3 orthogonalize(vec3 toOrtho, vec3 orthoAgainst) {
    float bottom = (orthoAgainst.x*orthoAgainst.x)+(orthoAgainst.y*orthoAgainst.y)+(orthoAgainst.z*orthoAgainst.z);
    float top = (toOrtho.x*orthoAgainst.x)+(toOrtho.y*orthoAgainst.y)+(toOrtho.z*orthoAgainst.z);
    return toOrtho - top/bottom*orthoAgainst;
}

【问题讨论】:

    标签: opengl graphics 3d glm-math


    【解决方案1】:

    创建一个与视图平行的广告牌矩阵就像将总模型视图矩阵的左上角 3×3 子矩阵设置为恒等一样简单。只有在某些情况下,您实际上需要实际的外观矢量。

    不管怎样,你的想法太复杂了。您对矩阵的所有修补都完全没有抓住重点。即模型视图转换假定相机始终位于 (0,0,0) 并且相反地移动世界和模型。您尝试做的是在模型空间中找到指向相机的向量。这只是转换后指向 (0,0,0) 的向量。

    所以我们要做的就是反转模型视图矩阵并用它变换 (0,0,0,1)。那是你的外观矢量。为了计算右向量和上向量,将模型视图矩阵的第一 (X) 和第二 (Y) 列与该外观向量正交。

    【讨论】:

    • 我尝试将其编辑为您的规范,但恐怕我的尝试没有成功。知道我做错了什么吗?我认为“正交化”是指叉积?
    • @wd40bomber7:没有正交化并不意味着叉积。这意味着:en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process
    • 我的错。我修改了我的代码(以及我上面的帖子)以反映该建议,但它仍然不起作用。我对照几个在线示例检查了正交化的实现,它似乎工作正常。我不确定还有什么问题
    【解决方案2】:

    我自己想出来的。事实证明,我使用的模型格式使用不同的轴进行广告牌。大多数广告牌实现(包括我使用的那个)使用 X,Y 坐标来定位广告牌对象。我正在阅读的格式使用 Y 和 Z。

    要寻找的是有广告牌效果,但方向错误。为了解决这个问题,我使用了不同的相机向量,直到得到正确的矩阵计算:

        bmatrix[1].x = right.x;
        bmatrix[1].y = right.y;
        bmatrix[1].z = right.z;
        bmatrix[1].w = 0;
    
        bmatrix[2].x = up.x;
        bmatrix[2].y = up.y;
        bmatrix[2].z = up.z;
        bmatrix[2].w = 0;
    
        bmatrix[0].x = look.x;
        bmatrix[0].y = look.y;
        bmatrix[0].z = look.z;
        bmatrix[0].w = 0;
    
        bmatrix[3].x = pos.x;
        bmatrix[3].y = pos.y;
        bmatrix[3].z = pos.z;
        bmatrix[3].w = 1;
    

    我尝试遵循 datenwolf 的建议没有成功,此时他没有提供任何额外的解释,所以我不确定为什么。还是谢谢!

    【讨论】:

    • 抱歉,没有回复您。但是 ATM 我大部分时间都被我的日常工作所消耗。
    • datenwolf 的答案是正确的,但显然同样的问题是轴错误会使他的答案无效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多