定向边界框在 OpenGL 中畸形且尺寸错误

Bir*_*der 1 c++ opengl bounding-box

我正在 OpenGL 中编写一个程序来加载一个网格并在所述网格周围绘制一个定向边界框。网格正确加载,但是当我绘制边界框时,框的形状错误且太小。

兔网

我用来计算这个框的过程是使用主成分分析来找到协方差矩阵。然后我得到了该矩阵的特征向量并将它们用作局部坐标系来找到立方体的 8 个顶点。然后我计算了一个变换,将立方体从局部坐标系移动到全局坐标系。

计算协方差的代码在这里:

std::array<std::array<double, 3>, 3> covarianceCalc2()
{
 std::array<std::array<double, 3>, 3> sum = {{{0, 0, 0}, {0, 0, 0}, {0, 0, 0,}}};
 std::array<double, 3> tempVec;
 double mean = 0;
 for(int i = 0; i < meshVertices.size(); i++)
 {
     mean += meshVertices[i].x;
     mean += meshVertices[i].y;
     mean += meshVertices[i].z;
 }
 mean = mean/(meshVertices.size() * 3);

 for(int i = 0; i < meshVertices.size(); i++)
 {
     //mean = (meshVertices[i].x + meshVertices[i].y + meshVertices[i].z)/3;
     tempVec[0] = meshVertices[i].x - mean;
     tempVec[1] = meshVertices[i].y - mean;
     tempVec[2] = meshVertices[i].z - mean;
     sum = matrixAdd(sum, vectorTranposeMult(tempVec));
 }
 sum = matrixMultNum(sum,(double) 1/(meshVertices.size()));
 return sum;
 }
Run Code Online (Sandbox Code Playgroud)

计算特征向量的代码在这里:

void Compute_EigenV(std::array<std::array<double, 3>, 3> covariance, double eigenValues[3], double eigenVectors_1[3], double eigenVectors_2[3], double eigenVectors_3[3])
{

    printf("Matrix Stuff\n");
    MatrixXd m(3, 3);
    m << covariance[0][0], covariance[0][1], covariance[0][2],
         covariance[1][0], covariance[1][1], covariance[1][2],
         covariance[2][0], covariance[2][1], covariance[2][2];

    // volving SVD
    printf("EigenSolver\n");
    EigenSolver<MatrixXd> solver(m);
    MatrixXd all_eigenVectors = solver.eigenvectors().real();
    MatrixXd all_eigenValues = solver.eigenvalues().real();

    // find the max index
    printf("Find Max Index\n");
    int INDEX[3];
    double max;
    max=all_eigenValues(0,0);
    int index=0;
    for (int i=1;i<3;i++){
        if (max<all_eigenValues(i,0)){
            max=all_eigenValues(i,0);
            index=i;
        }
    }
    INDEX[0]=index;

    // find the min index
    printf("Find Min Index\n");
    double min;
    min=all_eigenValues(0,0);

    index=0;
    for (int i=1;i<3;i++){
        if (min>all_eigenValues(i,0)){
            min=all_eigenValues(i,0);
            index=i;
        }
    }
    INDEX[1]=3-index-INDEX[0];
    INDEX[2]=index;

    // giave eigenvalues and eien vectors to matrix
    printf("Give values and vector to matrix\n");
    eigenValues[0]=all_eigenValues(INDEX[0],0);
    printf("1");
    eigenValues[1]=all_eigenValues(INDEX[1],0);
    printf("1\n");
    eigenValues[2]=all_eigenValues(INDEX[2],0);

    printf("Vector 1\n");
    VectorXd featureVector_1 = all_eigenVectors.col(INDEX[0]);
    eigenVectors_1[0]=featureVector_1(0);
    eigenVectors_1[1]=featureVector_1(1);
    eigenVectors_1[2]=featureVector_1(2);

    printf("Vector 2\n");
    VectorXd featureVector_2 = all_eigenVectors.col(INDEX[1]);
    eigenVectors_2[0]=featureVector_2(0);
    eigenVectors_2[1]=featureVector_2(1);
    eigenVectors_2[2]=featureVector_2(2);

    printf("Vector 3\n");
    VectorXd featureVector_3 = all_eigenVectors.col(INDEX[2]);
    eigenVectors_3[0]=featureVector_3(0);
    eigenVectors_3[1]=featureVector_3(1);
    eigenVectors_3[2]=featureVector_3(2);

}
Run Code Online (Sandbox Code Playgroud)

找到全局坐标的代码是这样的:

std::array<double, 3> localToGlobal(std::array<double, 3> vec, double eigenVector1[3], double eigenVector2[3], double eigenVector3[3], double mean)
{
std::array<double, 3> tempVec;
std::array<std::array<double, 3>, 3> eigenArray;
eigenArray[0][0] = eigenVector1[0]; eigenArray[0][1] = eigenVector2[0]; eigenArray[0][2] = eigenVector3[0];
eigenArray[1][0] = eigenVector1[1]; eigenArray[1][1] = eigenVector2[1]; eigenArray[1][2] = eigenVector3[1];
eigenArray[2][0] = eigenVector1[2]; eigenArray[2][1] = eigenVector2[2]; eigenArray[2][2] = eigenVector3[2];

tempVec = matrixVectorMult(eigenArray, vec);
tempVec[0] += mean;
tempVec[1] += mean;
tempVec[2] += mean;

return tempVec;
}
Run Code Online (Sandbox Code Playgroud)

调用所有这些并绘制框的代码是:

void obbBoundingBox()
{

double eigenValues[3] = {0, 0, 0};
double eigenVectors_1[3] = {0, 0, 0}, eigenVectors_2[3] = {0, 0, 0}, eigenVectors_3[3] = {0, 0, 0};

Compute_EigenV(covarianceCalc2(), eigenValues, eigenVectors_1, eigenVectors_2, eigenVectors_3);


std::array<double, 3> point1 = {findVectorMax(eigenVectors_1), findVectorMax(eigenVectors_2), findVectorMax(eigenVectors_3)};
std::array<double, 3> point2 = {findVectorMax(eigenVectors_1), findVectorMax(eigenVectors_2), findVectorMin(eigenVectors_3)};
std::array<double, 3> point3 = {findVectorMax(eigenVectors_1), findVectorMin(eigenVectors_2), findVectorMin(eigenVectors_3)};
std::array<double, 3> point4 = {findVectorMax(eigenVectors_1), findVectorMin(eigenVectors_2), findVectorMin(eigenVectors_3)};
std::array<double, 3> point5 = {findVectorMin(eigenVectors_1), findVectorMax(eigenVectors_2), findVectorMax(eigenVectors_3)};
std::array<double, 3> point6 = {findVectorMin(eigenVectors_1), findVectorMax(eigenVectors_2), findVectorMin(eigenVectors_3)};
std::array<double, 3> point7 = {findVectorMin(eigenVectors_1), findVectorMin(eigenVectors_2), findVectorMax(eigenVectors_3)};
std::array<double, 3> point8 = {findVectorMin(eigenVectors_1), findVectorMin(eigenVectors_2), findVectorMin(eigenVectors_3)};


 double mean = 0;
 for(int i = 0; i < meshVertices.size(); i++)
 {
     mean += meshVertices[i].x;
     mean += meshVertices[i].y;
     mean += meshVertices[i].z;
 }
 mean = mean/(meshVertices.size() * 3);

point1 = localToGlobal(point1, eigenVectors_1, eigenVectors_2, eigenVectors_3, mean);
point2 = localToGlobal(point2, eigenVectors_1, eigenVectors_2, eigenVectors_3, mean);
point3 = localToGlobal(point3, eigenVectors_1, eigenVectors_2, eigenVectors_3, mean);
point4 = localToGlobal(point4, eigenVectors_1, eigenVectors_2, eigenVectors_3, mean);
point5 = localToGlobal(point5, eigenVectors_1, eigenVectors_2, eigenVectors_3, mean);
point6 = localToGlobal(point6, eigenVectors_1, eigenVectors_2, eigenVectors_3, mean);
point7 = localToGlobal(point7, eigenVectors_1, eigenVectors_2, eigenVectors_3, mean);
point8 = localToGlobal(point8, eigenVectors_1, eigenVectors_2, eigenVectors_3, mean);


glEnable(GL_BLEND);
 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 glColor4f(1.0f, 1.0f, 1.0f, 0.5f);

glBegin(GL_QUADS);
//Front Face
    glVertex3f(point1[0], point1[1], point1[2]);
    glVertex3f(point3[0], point3[1], point3[2]);
    glVertex3f(point7[0], point7[1], point7[2]);
    glVertex3f(point5[0], point5[1], point5[2]);
glEnd();

glBegin(GL_QUADS);
//Left Face
    glVertex3f(point5[0], point5[1], point5[2]);
    glVertex3f(point7[0], point7[1], point7[2]);
    glVertex3f(point8[0], point8[1], point8[2]);
    glVertex3f(point6[0], point6[1], point6[2]);
glEnd();

glBegin(GL_QUADS);
//Back Face
    glVertex3f(point6[0], point6[1], point6[2]);
    glVertex3f(point8[0], point8[1], point8[2]);
    glVertex3f(point4[0], point4[1], point4[2]);
    glVertex3f(point2[0], point2[1], point2[2]);
glEnd();

glBegin(GL_QUADS);
//Right Face
    glVertex3f(point2[0], point2[1], point2[2]);
    glVertex3f(point4[0], point4[1], point4[2]);
    glVertex3f(point3[0], point3[1], point3[2]);
    glVertex3f(point1[0], point1[1], point1[2]);
glEnd();

glBegin(GL_QUADS);
//Top Face
    glVertex3f(point2[0], point2[1], point2[2]);
    glVertex3f(point1[0], point1[1], point1[2]);
    glVertex3f(point5[0], point5[1], point5[2]);
    glVertex3f(point6[0], point6[1], point6[2]);
glEnd();

glBegin(GL_QUADS);
//Bottom Face
    glVertex3f(point4[0], point4[1], point4[2]);
    glVertex3f(point3[0], point3[1], point3[2]);
    glVertex3f(point7[0], point7[1], point7[2]);
    glVertex3f(point8[0], point8[1], point8[2]);
glEnd();




 }
Run Code Online (Sandbox Code Playgroud)

And*_*uri 5

代码看起来是正确的(我没有检查过所有的函数,比如 matrixmult 之类的,但我假设你已经测试并检查过它们)。

问题:您对自己在那里做什么有一点误解。

所以,为了帮助你,但不要自己编写你的课程,因为这会让我们俩都陷入困境,我决定在 Matlab 中制作一个小教程(我知道你可以访问)你想要做什么和为什么。缺少某些功能,但您应该能够理解发生了什么:

clear;clc;
%% your "bunny"
vtx=    [ 1 0
         1 1
         2 2
         3 3 
         1 3];

% Lets draw it  

hold on
plot(vtx(:,1),vtx(:,2),'.')

% lets draw XY axis also
plot([0 4],[0 0],'k')
plot([0 0],[0 4],'k')
axis([-1 5 -1 5])
axis square

%% Draw abb
maxX=max(vtx(:,1));
maxY=max(vtx(:,2));
minX=min(vtx(:,1));
minY=min(vtx(:,2));

% Mising: Create a square and draw it 
cub=createcube(maxX,maxY,minX,minY)
drawabb(cub);
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

%% Create obb

C=cov(vtx);
vtxmean=mean(vtx);

[eVect,~]=eig(C);

% Draw new local coord system
plot([vtxmean(1) vtxmean(1)+eVect(1,1)],[vtxmean(2) vtxmean(2)+eVect(1,2)],'k')
plot([vtxmean(1) vtxmean(1)+eVect(2,1)],[vtxmean(2) vtxmean(2)+eVect(2,2)],'k')
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

现在你可以看到,如果我们得到特征向量的最大值和最小值,那就没有太大意义了。那不是奥布。那么我们应该怎么做呢?好吧,我们可以创建一个 abb,但对齐到 NEW 轴,而不是 XY 轴!

我们需要什么?好吧,我们需要知道我们点在新坐标轴上的值,不是吗?

Localvtx=fromGlobalToLocal(vtx,eVect,vtxmean);

% get the max and min of the points IN THE NEW COORD SYSTEM!
maxX=max(Localvtx(:,1));
maxY=max(Localvtx(:,2));
minX=min(Localvtx(:,1));
minY=min(Localvtx(:,2));
Run Code Online (Sandbox Code Playgroud)

极好的!!!现在,我们可以在这个坐标系中创建一个正方形,并使用 fromLocalToGlobal,在 XY 中绘制它!!

obbcub=createcube(maxX,maxY,minX,minY);
obbcubXY=fromLocalToGlobal(obbcub,eVect,vtxmean);
drawcube(obbcubXY);
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

逻辑问题:我们为什么要做这一切!?!?

那么它确实是一个有趣的问题。你玩电子游戏吗?你有没有“膝盖中了一箭”?如果这个人一直在跳跃、蹲伏和躺着,计算机怎么知道你用狙击步枪射中了他的头部还是腿部!!

定向边界框怎么样!如果您知道腿部或头部的边界框,与模型的几何位置无关,您可以计算镜头是否进入该框内!(不要把一切都从字面上看,这是一个巨大的世界,有无数种方法可以做这样的事情)。

见示例:

在此处输入图片说明

旁注:请勿在您的报告中使用我的文字或图片或代码,因为这将被视为作弊!(以防万一)