テーパーする生成されたメッシュのジグザグのUVマッピングアーティファクトを修正するにはどうすればよいですか?


10

以下のように、カーブに基づいて手続き型メッシュを作成しています。メッシュ全体のサイズがカーブ全体で小さくなっています。

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

そして問題は、サイズが変わるとUVがジグザグになることです(カーブ全体でメッシュのサイズが同じである場合、UVは完全に機能します)。

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

 Vertices.Add(R);
 Vertices.Add(L);
 UVs.Add(new Vector2(0f, (float)id / count));
 UVs.Add(new Vector2(1f, (float)id / count));
 start = Vertices.Count - 4;
          Triangles.Add(start + 0);
                 Triangles.Add(start + 2);
                 Triangles.Add(start + 1);
                 Triangles.Add(start + 1);
                 Triangles.Add(start + 2);
                 Triangles.Add(start + 3);

 mesh.vertices = Vertices.ToArray();
         //mesh.normals = normales;
         mesh.uv = UVs.ToArray();
         mesh.triangles = Triangles.ToArray();

どうすれば修正できますか?


何であるidcount?何をしUVs.ToArray()ますか?頂点とテクスチャ座標をカードにどのようにアップロードしますか?
user1118321 2017

コンテキストからの@ user1118321 idは、ストリップに沿ったすべてのクロスバーからの現在のセグメントのインデックスですcountList<T>.ToArray()リスト内のすべてのエントリの型付き配列を返します(つまり、ここではa Vector2[])。これらのデータバッファーは、最後の数行でMeshインスタンスmeshに割り当てることにより、レンダリングシステムで使用できるようになります。ただし、これはコードの特に興味深い部分ではありません。頂点ポイントの選択方法です。これらの詳細は、見るとさらに便利です。;)
DMGregory

それが私の仮定でしたが、仮定が間違っていることもあるので、説明を求めました。私は過去に自分のコードでそのようなものを見たことがありますが、これはcount実際にはポリゴンではなく頂点を意味していること、またはその逆を理解しているだけです。私たちが行っていると思うすべてが本当に起こっていることを確認するだけです。
user1118321 2017

回答:


13

典型的なUVマッピングは、いわゆるアフィン変換です。つまり、3D空間とテクスチャ空間の間の各三角形のマッピングには、回転、平行移動、スケーリング/スカッシュ、およびスキュー(つまり、同種行列の乗算で実行できるすべてのこと)を含めることができます。

アフィン変換についてのことは、それらがドメイン全体で均一であることです。頂点Aの近くのテクスチャに適用する回転、移動、スケール、およびスキューは、1つの三角形内の頂点Bの近くに適用するものと同じです。一方のスペースで平行な線は、もう一方のスペースで平行な線にマップされ、収束/発散することはありません。

ただし、適用しようとしている段階的なテーパは均一ではありません。テクスチャの平行線をメッシュの収束線にマッピングしています。つまり、バンド全体で測定されたテクスチャのスケールは、ストリップを下に移動するにつれて連続的に変化します。これは、2D UVマッピングのアフィン変換が正確に表現できる以上のものです。隣接する頂点間で2D UV座標を補間すると、エッジ全体に沿って1つの一貫したスケールが得られます。この不一致が、この揺れ動くジグザグを作成するものです。

この問題は、長方形を台形にマップしたいときにいつでも発生します-平行な辺から収束する辺へ:これを行うアフィン変換はないので、それを区分的に近似し、目に見える継ぎ目にする必要があります。

ほとんどの目的で、ジオメトリを追加することで効果を最小限に抑えることができます。ストリップの長さに沿ってサブディビジョンの数を増やし、ストリップをその幅に沿って2つ以上のセグメントに分割し、三角形の対角線をヘリンボーンパターンに配置すると、効果が目立たなくなります。ただし、アフィン変換を使用している限り、常にある程度存在します。

しかし、それを回避する方法があります。3Dレンダリングで使用するのと同じトリックを使用して、長方形の壁と床が与えられた場合に、遠近法で台形を描画できます。射影座標を使用します!

アフィンテクスチャリング: ジグザグアーティファクトを使用した通常のアフィンテクスチャリングの例

射影テクスチャリング: アーティファクトを修正する射影テキストリングの例

これを行うには、3番目のUV座標(uvw)を追加し、シェーダーを変更する必要があります。

各ポイントのスケールファクター(たとえば、そのスポットでのストリップの幅に等しい)を指定すると、次のようにして、通常の2D UV座標から3D射影UVW座標を構築できます。

Vector3 uv3 = ((Vector3)uv2) * scale;
uv3.z = scale;

これらの3D uvw座標をメッシュに適用するには、Vector3オーバーロードMesh.SetUVs(int channel、List uvs)を使用する必要があります。

また、シェーダーの入力構造体を変更して、3Dテクスチャ座標を期待するようにしてください(ここでは、デフォルトの照らされていないシェーダーを使用しています)。

struct appdata
{
    float4 vertex : POSITION;
    float3 uv : TEXCOORD0; // Change float2 to float 3.
};
// Also do this for the uv sent from the vertex shader to the fragment shader.

また、2D uvを想定しているため、頂点シェーダーでTRANSFORM_TEXマクロを切り取る必要があります。

// o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.uv = v.uv;
// If you define a float4 with the special name _MainTex_ST, 
// you can get the same effect the macro had by doing this:
o.uv.xy = o.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw;

最後に、テクスチャサンプリングのために2Dテクスチャ座標に戻るには、フラグメントシェーダーの 3番目の座標で除算するだけです。

float2 uv = i.uv.xy / i.uv.z;

同じ数値を乗算することで、目的の2D座標からこの3D uvw座標を作成したため、2つの演算がキャンセルされ、元の目的の2D座標に戻りますが、頂点間の非線形補間が行われます。:D

頂点シェーダーではなく、フラグメントごとにこの分割を行うことが重要です。頂点ごとに行われる場合は、結果の座標を各エッジに沿って直線的に補間することに戻り、射影座標で導入しようとしていた非線形性が失われます。


こんにちは、私はかなり長い間同じ問題に取り組んでいますが、これはまさに私に何が起こっているようです。唯一の違いは、私はthreejsで作業していて、統一ではないということです。三角形の数を増やすことで問題を解決することができましたが、射影テクスチャリングを試してみたいと思います。これをthreejsに実装し始める方法さえありますか?ありがとうございました!
DživoJelić

1
ほぼ同じです。除数を格納するために3番目のテクスチャ座標が必要な場合は、フラグメントシェーダーで除算を実行します。これをケースに適用するのに問題がある場合は、新しい質問をすることでコードサンプルを含めることができ、これまでにメッシュをどのように描画しているかを示し、その答えに基づいて構築できます。
DMGregory

除数を3番目の座標として保存する必要がありますか(そのため、構造体を変更してTRANSFORM_TEXマクロを切り取ります。これはthreejsで行う方法がわかりません)、または除数を属性として頂点シェーダーに渡すだけで済みますか?そして、そこから、分割に使用できるフラグメントシェーダーへの可変として、
DživoJelić

TRANSFORM_TEXはUnityマクロです。three.jsにはそれがないので、切り取る必要はありません。補間されたUV座標と除数がフラグメントシェーダーに到達する限り、それらをどのように取得したかは重要ではありません。これまでに属性/変更として提供するときに問題が発生しましたか?
DMGregory

可能なことを確認するまで時間を無駄にしたくなかったので、私はまだ試しませんでした。最後の1つだけ質問です。除数は、フラグメントシェーダーに到達すると補間されますよね?2つの頂点間のピクセルでは、補間された値であり、元の値ではないという意味ですか?なぜUVを乗算してから分割するのが効果的なのか頭を悩ませるのに苦労しますが、私はあなたの言葉を受け入れて試してみます。:slightly_smiling_face:どうもありがとうございました!
DživoJelić
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.