1

私は無料のオープンソースOpenGL3ベースの3Dゲームエンジンを構築中です(これは学校の課題ではなく、個人的なスキル開発とオープンソースコミュニティへの還元のためのものです)。関連する数学をたくさん学ぶ必要がある段階に達したので、「3Dゲームプログラミングとコンピュータグラフィックスのための数学、第3版」という素晴らしい教科書を読んでいます。

ただし、C ++で「グラムシュミット直交化アルゴリズム」を実装しようとすると間違った答えが出力されるため、この本の演習を行うことを試みた初期の段階で問題が発生しました。私は数学の専門家ではありません(私はより良くしようとしていますが)、そして数学アルゴリズムを見てそれをコードに変換する経験は非常に限られています(Udacity.comから学んだものに限られています)。とにかく、誰かが私の間違ったコードを見て、ヒントや解決策を教えてくれると本当に助かります。

ここにあります:

/*
The Gram-Schmidt Orthogonalization algorithm is as follows:

    Given a set of n linearly independent vectors Beta = {e_1, e_2, ..., e_n},
    the algorithm produces a set Beta' = {e_1', e_2', ..., e_n'} such that
    dot(e_i', e_j') = 0 whenever i != j.

    A. Set e_1' = e_1
    B. Begin with the index i = 2 and k = 1
    C. Subtract the projection of e, onto the vectors e_1', e_2', ..., e_(i-1)'
       from e_i, and store the result in e_i', That is,

                             dot(e_i, e_k')
       e_i' = e_i - sum_over(-------------- e_k')
                                e_k'^2

    D. If i < n, increment i and loop back to step C.
*/

#include <iostream>
#include <glm/glm.hpp>

glm::vec3 sum_over_e(glm::vec3* e, glm::vec3* e_prime, int& i)
{
    int k = 0;
    glm::vec3 result;

    while (k < i-2)
    {
        glm::vec3 e_prime_k_squared(pow(e_prime[k].x, 2), pow(e_prime[k].y, 2), pow(e_prime[k].z, 2));
        result += (glm::dot(e[i], e_prime[k]) / e_prime_k_squared) * e_prime[k];
        k++;
    }

    return result;
}

int main(int argc, char** argv)
{
    int n = 2;  // number of vectors we're working with
    glm::vec3 e[] = {
        glm::vec3(sqrt(2)/2, sqrt(2)/2, 0),
        glm::vec3(-1, 1, -1),
        glm::vec3(0, -2, -2)
    };

    glm::vec3 e_prime[n];
    e_prime[0] = e[0];  // step A

    int i = 0;  // step B

    do  // step C
    {
        e_prime[i] = e[i] - sum_over_e(e, e_prime, i);

        i++;    // step D
    } while (i-1 < n);

    for (int loop_count = 0; loop_count <= n; loop_count++)
    {
        std::cout << "Vector e_prime_" << loop_count+1 << ": < " 
                  << e_prime[loop_count].x << ", " 
                  << e_prime[loop_count].y << ", " 
                  << e_prime[loop_count].z << " >" << std::endl;
    }

    return 0;
}

このコードは以下を出力します:

Vector e_prime_1: < 0.707107, 0.707107, 0 >
Vector e_prime_2: < -1, 1, -1 >
Vector e_prime_3: < 0, -2, -2 >

しかし、正解は次のようになっています。

Vector e_prime_1: < 0.707107, 0.707107, 0 >
Vector e_prime_2: < -1, 1, -1 >
Vector e_prime_3: < 1, -1, -2 >

編集:正しい答えを生成するコードは次のとおりです。

#include <iostream>
#include <glm/glm.hpp>

glm::vec3 sum_over_e(glm::vec3* e, glm::vec3* e_prime, int& i)
{
    int k = 0;
    glm::vec3 result;

    while (k < i-1)
    {
        float e_prime_k_squared = glm::dot(e_prime[k], e_prime[k]);
        result += ((glm::dot(e[i], e_prime[k]) / e_prime_k_squared) * e_prime[k]);
        k++;
    }

    return result;
}

int main(int argc, char** argv)
{
    int n = 3;  // number of vectors we're working with
    glm::vec3 e[] = {
        glm::vec3(sqrt(2)/2, sqrt(2)/2, 0),
        glm::vec3(-1, 1, -1),
        glm::vec3(0, -2, -2)
    };

    glm::vec3 e_prime[n];
    e_prime[0] = e[0];  // step A

    int i = 0;  // step B

    do  // step C
    {
        e_prime[i] = e[i] - sum_over_e(e, e_prime, i);

        i++;    // step D
    } while (i < n);

    for (int loop_count = 0; loop_count < n; loop_count++)
    {
        std::cout << "Vector e_prime_" << loop_count+1 << ": < " 
                  << e_prime[loop_count].x << ", " 
                  << e_prime[loop_count].y << ", " 
                  << e_prime[loop_count].z << " >" << std::endl;
    }

    return 0;
}
4

1 に答える 1

3

問題はおそらくあなたが定義する方法にありますe_k'^2。ベクトル計算に関する限り、ベクトルの2乗は通常、そのノルムの2乗と見なされます。したがって、

double e_prime_k_squared = glm::dot(e_prime_k, e_prime_k);

さらに、ベクトルによる除算は未定義であるため(GLMで許可されるのはなぜですか?)、e_k'^2がベクトルの場合、全体が未定義になります。

于 2012-09-03T22:46:43.257 に答える