実際にポジションをどのように生成したのか正確には言いませんでした。そこで、高さマップで高さ値を生成するためにPerlinノイズを使用していると仮定します。したがって、hieghtmapの任意の位置X、Yに対して、2Dノイズ関数を使用してZ値を生成します。
それでは、次のように自分の位置が計算されていると仮定しましょう:
vec3 CalcPosition(in vec2 loc) {
float height = MyNoiseFunc2D(loc);
return vec3(loc, height);
}
これは、3次元位置を生成します。しかし、何でスペースのこの位置ですか?それが問題です。
ほとんどのノイズ関数は、ある種の浮動小数点範囲ではloc
が2つの値になると予測しています。あなたのノイズ関数がどれほど優れているかによって、値を渡すことができる範囲が決まります。モデル空間の2D位置がノイズ関数の範囲内にあることが保証されていない場合は、その範囲に変換し、計算を行い、それからをにモデル空間に変換してください。
これで、3Dの位置になりました。 XとYの値の変換は単純です(ノイズ関数の空間への変換の逆ですが)。ここでは、高さにある程度のスケールを適用する必要があります。ノイズ関数は[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;
}
二つの行列は、ノイズ関数の空間に変換した後、バック変換:したがって、私たちの改訂版のcalc位置は次のようになります。実際のコードでは、ユースケースに応じて複雑な構造を使用することはできませんが、完全なアフィン変換は簡単に記述できます。
これで、あなたが覚えておく必要があるのは、次のとおりです。スペースがどれだけあるか分からない限り意味がありません。あなたの普通の位置、何も問題ありません。に。
この関数は、モデル空間内の位置を返します。法線はモデルスペースで計算する必要があります。これを行うには、頂点の現在の位置と、現在の位置からわずかにオフセットした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;
}
:
したがって、我々は、以下の機能を持っている必要があります。
delta
の値は、ノイズテクスチャの入力スペースの小さなオフセットです。このオフセットのサイズはノイズ関数に依存します。実際の現在の位置から返された高さと大幅に異なる高さを返すのに十分な大きさである必要があります。しかし、それは小で十分である必要があります。ノイズ分布のランダムな部分から引っ張らないようにしてください。
あなたのノイズ機能を知る必要があります。今、あなたは3ポジションを持っていることを
(現在の位置は、xがオフセット、とyオフセット)モデル空間で、あなたがモデル空間で通常の頂点を計算することができます:ここから
vec3 modelXGrad = modelXOffset - modelPosition;
vec3 modelYGrad = modelYOffset - modelPosition;
vec3 modelNormal = normalize(cross(modelXGrad, modelYGrad));
、普通のことをする。しかし、決してあなたのさまざまなベクトルのスペースを追跡することを忘れないでください。
ああ、もう1つ:頂点シェーダで行う必要があります。ジオメトリシェーダでこれを行う理由はありません。計算のどれも他の頂点に影響しないからです。あなたにGPUの並列処理をさせてください。
私はこのようなアプローチを考え、試して失敗しました。あなたの答えを読んだ後、私はおそらく正しい場所にすべてがあるわけではなく、エラーを引き起こしています。頂点、ジオメトリ、およびフラグメントシェーダーを使って作業しているので、私が何か空間を保持しているかどうかをさらに細心の注意を払わなければなりません。明示的にこのメソッドを使用し、何が起こるかを見てみましょう。 – Nitrex88
私はこのアプローチで作業しました。しかし、それを動作させるには、4つのオフセットベクトルを作成し、オフセットの勾配(modelPositionのオフセットの勾配ではありません)を使用する必要がありました。そして、適切な方向に照明を得るためには、modelXGradとmodelYGradのクロス製品を取る順番を入れ替えなければなりませんでした。座標空間をとてもうまく説明してくれてありがとう。それが助けになった。また、ジオメトリシェーダでジオメトリシェーダの地形をテッセレーションするので、ジオメトリシェーダでこれを実行していたことを言いたいと思います – Nitrex88