あなたは実際にどのようにポジションを生み出していたかを正確に言っていませんでした。したがって、パーリンノイズを使用して高さマップに高さの値を生成していると仮定します。したがって、hieghtmapの任意の位置X、Yに対して、2Dノイズ関数を使用してZ値を生成します。
それで、あなたの位置が次のように計算されると仮定しましょう:
vec3 CalcPosition(in vec2 loc) {
float height = MyNoiseFunc2D(loc);
return vec3(loc, height);
}
これにより、3D位置が生成されます。しかし、この位置はどのスペースにありますか?それが問題です。
loc
ほとんどのノイズ関数は、特定の浮動小数点範囲で2つの値になると想定しています。ノイズ関数がどれだけ優れているかによって、値を渡すことができる範囲が決まります。モデル空間の2D位置がノイズ関数の範囲内にあることが保証されていない場合は、それらをその範囲に変換して計算を行い、次に、それをモデル空間に変換し直します。
そうすることで、3D位置になります。X値とY値の変換は単純です(ノイズ関数の空間への変換の逆)が、Zはどうでしょうか。ここでは、高さに何らかのスケールを適用する必要があります。ノイズ関数は[0、1)の範囲の数値を返すため、この範囲をX値とY値と同じモデル空間にスケーリングする必要があります。これは通常、最大の高さを選択し、位置を適切にスケーリングすることによって行われます。したがって、修正された計算位置は次のようになります。
vec3 CalcPosition(in vec2 modelLoc, const in mat3 modelToNoise, const in mat4 noiseToModel)
{
vec2 loc = modelToNoise * vec3(modelLoc, 1.0);
float height = MyNoiseFunc2D(loc);
vec4 modelPos = noiseToModel * vec4(loc, height, 1.0);
return modelPos.xyz;
}
2つの行列は、ノイズ関数の空間に変換されてから、元に戻ります。実際のコードでは、ユースケースによってはそれほど複雑でない構造を使用できますが、完全なアフィン変換は簡単に説明できます。
さて、私たちがそれを確立したので、あなたが覚えておく必要があるのはこれです:それがどのスペースにあるかを知らない限り何も意味がありません。あなたがそれがどのスペースにあるかを確立するまで、あなたの通常、あなたの位置、何も重要ではありません。
この関数は、モデル空間内の位置を返します。モデル空間で法線を計算する必要があります。そのためには、頂点の現在の位置と、現在の位置からわずかにオフセットされた2つの位置の3つの位置が必要です。取得する位置はモデル空間内にある必要があります。そうでない場合、通常はそうではありません。
したがって、次の関数が必要です。
void CalcDeltas(in vec2 modelLoc, const in mat3 modelToNoise, const in mat4 noiseToModel, out vec3 modelXOffset, out vec3 modelYOffset)
{
vec2 loc = modelToNoise * vec3(modelLoc, 1.0);
vec2 xOffsetLoc = loc + vec2(delta, 0.0);
vec2 yOffsetLoc = loc + vec2(0.0, delta);
float xOffsetHeight = MyNoiseFunc2D(xOffsetLoc);
float yOffsetHeight = MyNoiseFunc2D(yOffsetLoc);
modelXOffset = (noiseToModel * vec4(xOffsetLoc, xOffsetHeight, 1.0)).xyz;
modelYOffset = (noiseToModel * vec4(yOffsetLoc, yOffsetHeight, 1.0)).xyz;
}
もちろん、これら2つの関数を1つにマージできます。
delta
値は、ノイズテクスチャの入力のスペースの小さなオフセットです。このオフセットのサイズは、ノイズ関数によって異なります。実際の現在の位置によって返される高さとは大幅に異なる高さを返すのに十分な大きさである必要があります。ただし、ノイズ分布のランダムな部分から引っ張らないように、十分に小さくする必要があります。
あなたはあなたのノイズ関数を知るようになるべきです。
モデル空間に3つの位置(現在の位置、xオフセット、yオフセット)があるので、モデル空間の頂点法線を計算できます。
vec3 modelXGrad = modelXOffset - modelPosition;
vec3 modelYGrad = modelYOffset - modelPosition;
vec3 modelNormal = normalize(cross(modelXGrad, modelYGrad));
ここから、いつものことをします。ただし、さまざまなベクトルのスペースを追跡することを忘れないでください。
ああ、もう1つ、これは頂点シェーダーで実行する必要があります。どの計算も他の頂点に影響を与えないため、ジオメトリシェーダーでこれを行う理由はありません。GPUの並列処理を機能させましょう。