インデックス形状の簡単法線計算


やあ子供たち。今日はインデックス形式で表記されたポリゴン形状情報に対し、各頂点参照ごとのフラットな法線を一気に計算してくれるスペシャルな関数を紹介するぞ。ソースは以下のようになったよ。
(各頂点参照ごとに定義された法線をここでは"index aligned" な法線としているよ。index_alignedな法線配列は、頂点参照インデックス列と要素数が同じなのは勿論、各要素が一対一に対応する配列で、つまりそのままglBufferDataの引数になれる、描画順に「展開」された法線配列のことさ。)(2013年2月13日、以下glm対応版に書き換えました。)

void CalcNormalsFlat( const vector< int >& indices, const vector< glm::vec3 >& poslist,
                     vector< glm::vec3 >* normals_index_aligned )
{
    normals_index_aligned->reserve( indices.size() );
    for( auto it = indices.begin(); it!=indices.end(); )
    {
        auto& o = poslist[ *it ];++it;
        auto& p = poslist[ *it ];++it;
        auto& q = poslist[ *it ];++it;
        auto nor = glm::normalize( glm::cross( p-o, q-o ) );
        for( int i=0; i<3; ++i )
            normals_index_aligned->push_back( nor );
    }// it
    return;
}

出力引数normalsの各要素は、indicesとの各要素、つまり頂点参照と一対一に対応するぞ。これより得た法線で描画した結果は冒頭の左側画像のようになるよ。
でもこれだけじゃつまらないから例えば上記関数をインタフェースが同じな、「モデル中心から放射状に突き出す法線」を計算する関数もアップしておこうか。

void CalcNormalsSmoothRadial( const vector< int >& indices, const vector< Vec3 >& poslist, 
                         vector< Vec3 >* normals_index_aligned )
{
    normals_index_aligned->reserve( indices.size() );
    auto ctr = std::accumulate( poslist.begin(), poslist.end(), Vec3() );
    ctr /= poslist.size();
    for( auto it = indices.begin(); it!=indices.end(); ++it )
    {
        auto& o = poslist[ *it ];
        normals_index_aligned->push_back( (o-ctr).Normalize() );
    }        
    return;
}

この法線を使って描画した結果は、冒頭の右側の画像のようになるぞ。
じゃ今日はこの辺で。