7

円柱を8面プリズムに分割し、その位置に基づいて頂点法線を計算すると(「スムーズシェーディング」)、かなり見栄えがします。

円錐を8面のピラミッドに分割し、その位置に基づいて法線を計算すると、円錐の先端(技術的には円錐の頂点ですが、メッシュの頂点との混同を避けるために先端と呼びましょう)に引っかかってしまいます。 。

8面シリンダーvsコーン

三角形の面ごとに、両方のエッジに沿って法線を一致させる必要があります。ただし、三角形の各頂点で指定できる法線は1つだけなので、一方のエッジまたはもう一方のエッジを一致させることはできますが、両方を一致させることはできません。2つのエッジの平均であるチップ法線を選択することで妥協することができますが、今ではどのエッジも見栄えがよくありません。各先端頂点の平均法線を選択する方法の詳細は次のとおりです。

チップ平均化による顔の詳細

完璧な世界では、GPUは三角形だけでなく真のクワッドをラスタライズできます。次に、縮退したクワッドを使用して各面を指定し、各三角形の隣接する2つのエッジに異なる法線を指定できるようにします。しかし、処理する必要があるのは三角形だけです...コーンを複数の「スタック」にカットできるため、エッジの不連続性は、全体に沿ってではなく、コーンの先端でのみ表示されますが、それでもヒント!

滑らかな色合いの低ポリコーンのトリックはありますか?

4

2 に答える 2

10

三角形で構成された最新のOpenGL(つまりシェーダー)のコーンに少し苦労していましたが、驚くほど簡単な解決策を見つけました!私はそれが現在受け入れられている答えで提案されているものよりもはるかに良くて単純だと思います。

円錐の表面を形成する三角形の配列(明らかにそれぞれに3つの頂点があります)があります。これは本当に簡単なので、底面(円形のベース)は気にしませんでした。すべての作業で、次の単純な頂点構造を使用します。

  • position: vec3(最後の要素として1.0fを追加することにより、シェーダーでvec4に自動的に変換されました)

  • normal_vector: vec3(光の方向の内積の計算に使用されたため、シェーダーではvec3として保持されていました)

  • color: vec3(透明度は使用しませんでした)

私の頂点シェーダーでは、頂点の位置を変換するだけで(投影とモデルビュー行列を乗算)、法線ベクトルも変換していました(モデルビュー行列の変換された逆行列を乗算します)。次に、変換された位置、法線ベクトル、および変換されていない色がフラグメントシェーダーに渡され、光の方向と法線ベクトルの内積が計算され、この数値に色が乗算されました。

私がしたことから始めましょう、そして不十分であるとわかりました:

試行#1:各円錐面(三角形)は一定の法線ベクトルを使用していました。つまり、1つの三角形のすべての頂点が同じ法線ベクトルを持っていました。これは単純ですが、スムーズな照明は実現しませんでした。三角形のすべてのフラグメントが同じ法線ベクトルを持っていたため、各面の色は一定でした。間違い。

試行#2:各頂点の法線ベクトルを個別に計算しました。これは、円錐の円形の底面の頂点では簡単でしたが、円錐の先端には何を使用する必要がありますか?三角形全体の法線ベクトルを使用しました(つまり、attempt#と同じ値)。円錐の基部に近い部分では滑らかな照明がありましたが、先端の近くでは滑らかではなかったので、これはより良い方法でした。間違い。

しかし、それから私は解決策を見つけました:

試行#3 :ゼロベクトルvec3(0.0f、0.0f、0.0f)に等しい円錐先端の頂点に法線ベクトルを割り当てたことを除いて、試行#2と同じようにすべてを実行しました。これがトリックの鍵です!次に、このゼロ法線ベクトルがフラグメントシェーダーに渡されます(つまり、頂点シェーダーとフラグメントシェーダーの間で、他の2つの頂点の法線ベクトルで自動的に補間されます)。もちろん、フラグメント(!)シェーダーのベクトルは一定のサイズ(ドット積に必要)ではないため、正規化する必要があります。だから私はそれを正規化します-もちろん、これは法線ベクトルのサイズがゼロである円錐の先端では不可能です。しかし、それは他のすべての点で機能します。以上です。

覚えておくべき重要なことが1つあります。それは、フラグメントシェーダーで法線ベクトルのみを正規化できることです。確かに、C ++でゼロサイズのベクトルを正規化しようとすると、エラーが発生します。したがって、何らかの理由でフラグメントシェーダーに入る前に正規化が必要な場合は、サイズがゼロの法線ベクトルを除外するようにしてください(つまり、円錐の先端を除外しないと、エラーが発生します)。

これにより、円錐の先端のポイントを除くすべてのポイントで円錐の滑らかなシェーディングが生成されます。しかし、その点は重要ではありません(1ピクセルを気にする人は...)、または特別な方法で処理できます。もう1つの利点は、非常に単純なシェーダーでも使用できることです。唯一の変更は、頂点シェーダーではなく、フラグメントシェーダーで、またはそれ以前でさえ、法線ベクトルを正規化することです。

ここに滑らかな円錐の例

于 2016-05-12T13:01:25.987 に答える
4

はい、それは確かに三角形の制限です。円柱から円錐に近づくときに問題を表示すると、問題が非常に明確になると思います。

ここに画像の説明を入力してください

これがあなたが試すことができるいくつかのことです...

  1. クワッドを使用します(@WhitAnglが言うように)。新しいOpenGLで地獄に落ちるに、結局のところ、クワッドの使用があります。

  2. もう少し均等にテッセレーションします。先端の法線を共通のアップベクトルに設定すると、照明のない側では少し奇妙に見えますが、粗いエッジが削除されます。残念ながら、これは質問のタイトルである低ポリゴンコーンに反します。

    ここに画像の説明を入力してください

  3. 円錐がオブジェクト空間の原点の中心にあることを確認し(または頂点シェーダーで手続き的に生成し)、フラグメント位置を使用して法線を生成します...

    in vec2 coneSlope; //normal x/z magnitude and y
    in vec3 objectSpaceFragPos;
    
    uniform mat3 normalMatrix;
    
    void main()
    {
        vec3 osNormal = vec3(normalize(objectSpaceFragPos.xz) * coneSlope.x, coneSlope.y);
        vec3 esNormal = normalMatrix * osNormal;
        ...
    }
    

    フラグメントシェーダーの操作を減らすために実行できるいくつかの凝ったトリックもあるかもしれません。次に、より高価なシェーダーとより高価なシェーダーのテッセレーションの全体的なバランスがあります。

コーンはかなり単純なオブジェクトであり、私は挑戦が好きですが、実際には、たくさんのコーンが必要でない限り、これが問題になることはわかりません。その場合、ジオメトリシェーダーまたはインスタンス化に入る可能性があります。さらに良いことに、フラグメントシェーダーでクワッドとレイキャストの暗黙的なコーンを使用してコーンを描画できます。円錐がすべて平面上にある場合は、法線マッピングまたは視差マッピングを試すことができます。

于 2013-12-17T17:02:12.510 に答える