【问题标题】:Missing vertices in sphere model球体模型中缺少顶点
【发布时间】:2016-03-25 11:13:06
【问题描述】:

我正在学习 OpenGL,并且正在创建自己的球体模型。我能够画出一个完整的球体,尽管结果有些令人费解。我想知道是否有人可以解释(并且可能更正)我的代码。

基本原理:使用根据极坐标计算的笛卡尔坐标构建三角形。细分的数量告诉我生成球体点的 phi 或 theta 弧度的步骤。从特定点 P(phi, theta),我为 [phi, delta_phi], [theta, delta_tetha] 构建扇区的其他边缘,其中 phi 从 [0, pi] (180 度) 和 tetha 从 [0 , 2*pi] (360 度)。

这是我想出的代码(我使用的是 QT 对象,但它应该非常简单):

QVector3D polarToCarthesian(float rho, float phi, float theta)
{
    float r = qSin(phi) * rho;
    float y = qCos(phi) * rho;

    float x = r * qSin(theta);
    float z = r * qCos(theta);

    return QVector3D{x, y, z};
}

void make_sector(QVector<QVector3D>& mesh, float phi, float theta, float rho, float deltaPhi, float deltaTheta)
{
    QVector3D p1 = polarToCarthesian(rho, phi, theta);
    QVector3D p2 = polarToCarthesian(rho, phi, theta + deltaTheta);
    QVector3D p3 = polarToCarthesian(rho, phi + deltaPhi, theta);
    QVector3D p4 = polarToCarthesian(rho, phi + deltaPhi, theta + deltaTheta);

    // First Triangle
    mesh.push_back(p1);
    mesh.push_back(p1); // Normal
    mesh.push_back(p3);
    mesh.push_back(p3); // Normal
    mesh.push_back(p2);
    mesh.push_back(p2); // Normal

    // Second Triangle
    mesh.push_back(p2);
    mesh.push_back(p2); // Normal
    mesh.push_back(p3);
    mesh.push_back(p3); // Normal
    mesh.push_back(p4);
    mesh.push_back(p4); // Normal
}

void build_sphere(QVector<QVector3D>& mesh, int ndiv)
{
    const float PHI_MAX = static_cast<float>(M_PI);
    const float THETA_MAX = static_cast<float>(M_PI) * 2;

    const float delta_phi = PHI_MAX / ndiv;
    const float delta_theta = THETA_MAX / ndiv;

    for (int i = 0; i < ndiv; ++i) {
        float phi = i * delta_phi;
        for (int j = 0; j < ndiv; ++j) {
            float theta = j * delta_theta;
            make_sector(mesh, phi, theta, 1.0f, delta_phi, delta_theta);
        }
    }
}

// Then I can generate the sphere with
build_sphere(sphere_mesh, 10);

但是,除非我将 phi 的迭代从 ndiv 迭代更改为 3 * ndiv 迭代,否则我无法获得完整的球体。我不明白为什么! Phi 应该从 0 到 PI 变化以覆盖整个 Y 轴,而从 0 到 2 * pi 的 Theta 应该覆盖 XZ 平面。

有人可以解释发生了什么以及为什么3 * ndiv 有效吗?

【问题讨论】:

  • 你是怎么画整个东西的?我强烈怀疑您只绘制了您生成的所有顶点的 1/3。然后,如果你生成 3 倍的必要顶点,那么这些顶点的 1/3 就足以覆盖整个球体。少了任何东西,零件就丢失了。
  • 我将数据加载到顶点缓冲区对象,并使用 glDrawArrays(GL_TRIANGLES, 0, mesh.size() / 2) 绘制它(这是一半,因为正常值最终占据了向量的一半)。我将顶点值与 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0) 和正常值与 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 3 * sizeof (GLfloat));
  • @RetoKoradi 在另一台电脑上重写软件截屏后,我发现了这个bug。问题是我只在顶点缓冲区中加载了三分之一的模型,因为我使用了大小为 model.size() * sizeof(GLfloat) 而不是 model.size() * sizeof(QVector3D) 的 glBufferData。现在它按预期工作,我得到了一个完整的球体。 :)
  • 虽然您的代码可能会以某种方式工作,但我认为您会发现实现此博客文章中描述的“icosphere”方法会更满意:blog.andreaskahler.com/2009/06/…。这让我省去了很多麻烦。

标签: c++ opengl math graphics 3d


【解决方案1】:

phi 应该从 -π/2 到 +π/2,而不是从 0 到 π:

float phi = i * delta_phi - (M_PI / 2);

此外,您的 ry 计算似乎是错误的。您希望r 在赤道处最大(当phi == 0 时)。

认为如果您一直停留在2 * ndiv,您的代码可能会起作用(尽管生成的多边形数量是应有的两倍)。事实上,从 0 到 π 只会在北半球放置多边形,因此您必须不断超越,才能在南半球拥有任何多边形。

附言笛卡尔中没有“h”;)

【讨论】:

  • 在 [-pi/2, pi/2] 之间的 phi 迭代到 2 * ndiv,我只得到北半球。即使我迭代到 4 * ndiv 我也没有得到它,我必须至少 4.5 * ndiv 才能得到一个完整的球体。
  • @HomeroC.deAlmeida 好吧,我认为您在 ry 的计算中也弄错了 sincos(工作的基础是赤道是x / z 平面)
  • 还是什么都没有。制作r = cos(phi) * rhoy = sin(phi) * rho 给了我一个倒置的南半球四分之一。如果我也更改 x = r * cos(theta)z=r * sin(theta) 也是一样。
猜你喜欢
  • 2013-06-21
  • 1970-01-01
  • 2011-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-13
相关资源
最近更新 更多