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

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

问题描述

我正在撰写一个专有网格浏览器,动画格式。



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

可以将骨骼标记为Billboarded,正如大家都知道的那样,意味着它应该始终面对相机。

<因此,我们的想法是为该骨骼生成一个矩阵,当它用于转换它所连接的顶点时,会导致顶点被标记。



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





不过,目前看起来像这样:


请注意,尽管它的方向不正确,但它仍然是标示。无论照相机在哪个方向上看,这些顶点总是朝向那个方向。



我生成标记为billboarded的骨骼矩阵的代码是: / p>

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

//将矩阵中的平移归零,因此我们可以使用矩阵将
//相机位置转换为使用视图矩阵
view [3] .x的世界坐标= view [3] .y = view [3] .z = 0;

//视图矩阵是如何从我们给出的
//输入到摄像头位置的gluLookAt pos中获取的,所以要采用另一种方式来逆转
//旋转。转置矩阵将做到这一点。
{
float * matrix =(float *)& view;
float temp [16];
//将其复制到temp
memcpy(temp,matrix,sizeof(float)* 16);
matrix [1] = temp [4];矩阵[4] =温度[1];
matrix [2] = temp [8];矩阵[8] =温度[2];
matrix [6] = temp [9];矩阵[9] =温度[6];
}

//获取相机在世界空间中的正确位置
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来进行数学计算。



尽管这部分代码是基于教程此处 ,代码的其他部分是基于一个类似于我正在构建的开源程序。但是,该程序是为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 =倒数* 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);
返回toOffho - 顶部/底部* orthoAgainst;
}


解决方案

事实证明,我使用的模型格式使用不同的坐标轴来显示广告牌。大多数广告牌实现(包括我使用的实现)使用X,Y坐标定位billboarded对象。我正在阅读的格式使用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的建议并没有成功,目前他没有提供任何额外的解释所以我不确定为什么。无论如何,谢谢!


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.

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;

I am using GLM to do the math involved.

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

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

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

解决方案

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;

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天全站免登陆