Opengl 广告牌矩阵 [英] Opengl Billboard matrix

查看:40
本文介绍了Opengl 广告牌矩阵的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am writing a viewer for a proprietary mesh & animation format in OpenGL.

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

During rendering a transformation matrix is created for each bone (node) and is applied to the vertices that bone is attached to.

一个骨骼可能被标记为Billboarded",众所周知,这意味着它应该始终面向相机.

It is possible for a bone to be marked as "Billboarded" which as most everyone knows, means it should always face the camera.

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

So the idea is to generate a matrix for that bone which when used to transform the vertices it's attached to, causes the vertices to be billboarded.

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

On my test model it should look like this:

不过目前看起来是这样的:

However currently it looks like this:

请注意,尽管它的方向不正确,但它还是有广告牌的.因为无论相机朝哪个方向看,这些顶点总是在那个方向面向那个方向.

Note, that despite its incorrect orientation, it is billboarded. As in no matter which direction the camera looks, those vertices are always facing that direction at that orientation.

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

My code for generating the matrix for bones marked as billboarded is:

    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 进行相关的数学计算.

I am using GLM to do the math involved.

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

Though this part of the code is based off of the tutorial here, other parts of the code are based off of an open source program similar to the one I'm building. However that program was written for DirectX and I haven't had much luck directly converting. The (working) directX code for billboarding looks like this:

    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 中.

Note the results are stored in baseMatrix in the directX version.

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

Here's the code I came up with when I tried to modify my code according to datenwolf's suggestions. I'm pretty sure I made some mistakes still. This attempt creates heavily distorted results with one end of the object directly in the camera.

    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;
}

推荐答案

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

Figured it out myself. It turns out the model format I'm using uses different axes for billboarding. Most billboarding implementations (including the one I used) use the X,Y coordinates to position the billboarded object. The format I was reading uses Y and Z.

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

The thing to look for is that there was a billboarding effect, but facing the wrong direction. To fix this I played with the different camera vectors until I arrived at the correct matrix calculation:

    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 的建议没有成功,此时他还没有提供任何额外的解释,所以我不确定为什么.还是谢谢!

My attempts to follow datenwolf's advice did not succeed and at this time he hasn't offered any additional explanation so I'm unsure why. Thanks anyways!

这篇关于Opengl 广告牌矩阵的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆