2

現在、opengl ワールドにシャドウ ボリュームを実装しようとしています。今は、ボリュームを正しく計算することに集中しています。

現在、レンダリングされたティーポットがあり、いくつかのシャドウ ボリュームを生成することができますが、それらは常にティーポットの左側を直接指しています。ライトをどこに移動しても (ティーポットがディフューズ ライティングで照らされているため、実際にライトを移動していることがわかります)、シャドウ ボリュームは常に左にまっすぐ進みます。

ボリュームを作成するために使用している方法は次のとおりです。

    1. オブジェクト内のすべての三角形を見て、シルエット エッジを見つけます。三角形が点灯していない場合 (内積でテスト)、スキップします。点灯している場合は、すべてのエッジを確認してください。エッジが現在シルエット エッジのリストにある場合は、それを削除します。それ以外の場合は追加します。
    2. すべてのシルエット エッジを取得したら、各エッジを通過して、エッジの各頂点に 1 つの頂点を持つクワッドを作成し、残りの 2 つはライトから離れて延長します。

すべてを実行する私のコードは次のとおりです。

void getSilhoueteEdges(Model model, vector<Edge> &edges, Vector3f lightPos) {

    //for every triangle
    // if triangle is not facing the light then skip
    // for every edge
    //  if edge is already in the list
    //   remove
    //  else
    //   add

    vector<Face> faces = model.faces;

    //for every triangle
    for ( unsigned int i = 0; i < faces.size(); i++ ) {
        Face currentFace = faces.at(i);

        //if triangle is not facing the light
        //for this i'll just use the normal of any vertex, it should be the same for all of them
        Vector3f v1 = model.vertices[currentFace.vertices[0] - 1];
        Vector3f n1 = model.normals[currentFace.normals[0] - 1];

        Vector3f dirToLight = lightPos - v1;
        dirToLight.normalize();

        float dot = n1.dot(dirToLight);
        if ( dot <= 0.0f ) 
            continue; //then skip

        //lets get the edges
        //v1,v2; v2,v3; v3,v1
        Vector3f v2 = model.vertices[currentFace.vertices[1] - 1];
        Vector3f v3 = model.vertices[currentFace.vertices[2] - 1];

        Edge e[3];
        e[0] = Edge(v1, v2);
        e[1] = Edge(v2, v3);
        e[2] = Edge(v3, v1);

        //for every edge
        //triangles only have 3 edges so loop 3 times
        for ( int j = 0; j < 3; j++ ) {
            if ( edges.size() == 0 ) {
                edges.push_back(e[j]);
                continue;
            }

            bool wasRemoved = false;
            //if edge is in the list
            for ( unsigned int k = 0; k < edges.size(); k++ ) {
                Edge tempEdge = edges.at(k);
                if ( tempEdge == e[j] ) {
                    edges.erase(edges.begin() + k);
                    wasRemoved = true;
                    break;
                }
            }

            if ( ! wasRemoved )
                edges.push_back(e[j]);
        }
    }
}

void extendEdges(vector<Edge> edges, Vector3f lightPos, GLBatch &batch) {
    float extrudeSize = 100.0f;
    batch.Begin(GL_QUADS, edges.size() * 4);
    for ( unsigned int i = 0; i < edges.size(); i++ ) {
        Edge edge = edges.at(i);

        batch.Vertex3f(edge.v1.x, edge.v1.y, edge.v1.z);
        batch.Vertex3f(edge.v2.x, edge.v2.y, edge.v2.z);

        Vector3f temp = edge.v2 + (( edge.v2 - lightPos ) * extrudeSize);
        batch.Vertex3f(temp.x, temp.y, temp.z);

        temp = edge.v1 + ((edge.v1 - lightPos) * extrudeSize);
        batch.Vertex3f(temp.x, temp.y, temp.z);
    }
    batch.End();
}

void createShadowVolumesLM(Vector3f lightPos, Model model) {
    getSilhoueteEdges(model, silhoueteEdges, lightPos);
    extendEdges(silhoueteEdges, lightPos, boxShadow);
}

私はライトを次のように定義しており、メインのシャドウ ボリューム生成メソッドは次のように呼び出されます。

Vector3f vLightPos = Vector3f(-5.0f,0.0f,2.0f);
createShadowVolumesLM(vLightPos, boxModel);

私のコードはすべて、コメントがない場所で自己文書化されているようですが、紛らわしい部分がある場合はお知らせください。

私が見過ごした単純な間違いだと感じています。シャドウ ボリュームがレンダリングされている場合とレンダリングされていない場合の外観次に示します。

4

1 に答える 1

1

シャドウ ボリュームを変換していないようです。残りのジオメトリと同じように変換されるように、モデル ビュー マトリックスを設定する必要があります。または、すべての頂点を (手動で) ビュー空間に変換してから、ビュー空間でシルエットと変換を行う必要があります。

明らかに、最初の方法はより少ない CPU 時間を使用するため、IMO の方が望ましいでしょう。

于 2010-11-24T15:29:47.253 に答える