2

私は現在、GLSL に 3D ノイズ関数を実装しています。これは、球体の頂点を変位させて地形を与えるために使用されます。現在、ジオメトリ シェーダーを使用して面ごとの法線を単純に計算しています (テッセレーションも使用しているため、頂点シェーダーの代わりにここでこれを行っているのです)。ここで、頂点ごとの法線を計算したいと思います。

今、フラット グリッドを移動するときにノイズから法線を計算することに関するいくつかの投稿を見てきましたが、自分で機能させることはできないようです。以下は、新しい頂点の位置を計算するテッセレーション評価シェーダーのスニペットです。(これは正常に動作します)。

// Get the position of the newly created vert and push onto sphere's surface.
tePosition = normalize(point0 + point1 + point2) * Radius;

// Get the noise val at given location. (Using fractional brownian motion)
float noiseVal = fBM(tePosition, Octaves); 

// Push out vertex by noise amount, adjust for amplitude desired.
tePosition = tePosition + normalize(tePosition) * noiseVal * Amplitude; 

tePosition次にジオメトリ シェーダーに入り、そのうちの 3 つを使用して三角形の表面法線を計算します。これを使用して、上記の頂点の法線を計算するにはどうすればよいですか?

からの 2 つの小さなオフセットでノイズをリサンプリングすることにより、「ネイバー」メソッドを実行しようとしましたtePosition(ノイズ値で置き換える前に、これらを球に押し戻します)。次に、これら 2 つの新しい位置を使用して、tePosition からそれぞれの位置へのベクトルを取得し、外積を使用して法線を取得します。ただし、これにより多くの領域が黒くなり (法線が後ろ向きであることを示唆)、法線が外側を向いている部分は球の周りで非常に均一に見えます (光の反対側の照明)。上記を実行するコードは次のとおりです。

// theta used for small offset
float theta = 0.000001; 
// Calculate two new position on the sphere.
vec3 tangent = tePosition + vec3(theta, 0.0, 0.0);
tangent = normalize(tangent) * Radius;
vec3 bitangent = tePosition + vec3(0.0, theta, 0.0);
bitangent = normalize(bitangent) * Radius; 

// Displace new positions by noise, then calculate vector from tePosition
float tanNoise = fBM(tangent, Octaves) * Amplitude;
tangent += normalize(tangent) * tanNoise;
tangent = tangent - tePosition;

float bitanNoise = fBM(bitangent, Octaves) * Amplitude;
bitangent += normalize(bitangent) * bitanNoise;
bitangent = bitangent - tePosition;

vec3 norm = normalize(cross(normalize(tangent), normalize(bitangent)));

値を変更して、これをオフセットに使用する方法を変更しようとしthetaましたが、その結果、さまざまな程度の「誤り」が生じました。

法線を正しく計算する方法について誰か考えがありますか?

4

1 に答える 1

2

(theta, 0.0, 0.0)接線を作成するために追加するベクトルは(0.0, theta, 0.0)、球に接していません。タンジェントとバイタンジェントを取得するには、外積を使用する必要があります。

// pos x (1,0,0) could be 0, so add pos x (0,1,0).
vec3 vecTangent = normalize(cross(tePosition, vec3(1.0, 0.0, 0.0))
  + cross(tePosition, vec3(0.0, 1.0, 0.0)));
// vecTangent is orthonormal to tePosition, compute bitangent
// (rotate tangent 90° around tePosition)
vec3 vecBitangent = normalize(cross(vecTangent, tePosition));

vec3 ptTangentSample = noisy(tePosition + theta * normalize(vecTangent));
vec3 ptBitangentSample = noisy(tePosition + theta * normalize(vecBitangent));

vec3 vecNorm = normalize(
  cross(ptTangentSample - tePosition, ptBitangentSample - tePosition));

補足として、ベクトル (方向 + 長さ、数学的に (x,y,z,0)) とポイント (座標系の位置、数学的に (x,y,z,1)) に同じ変数を使用しないことをお勧めします。 )。

于 2013-05-26T10:26:57.353 に答える