そこで私は、表面と惑星レベルの両方から見ることができる現実的な惑星を作成することを目標に、Directx11/hlsl レンダリング エンジンに取り組んできました。惑星は正規化された立方体であり、ノイズを使用してプロシージャルに生成されます。惑星の表面に近づくと、バイナリ ベースの三角ツリーが目的の詳細レベルに達するまで分割されます。頂点の法線計算が正しく機能するようになりました。最近、地形テクスチャの法線マッピングの実装を試み始めました。ほとんどの部分で機能しているように見えるものが得られました。ただし、太陽が地面に対してほぼ垂直 (90 度) を指している場合は、より明るくなります。
ただし、反対の角度 (270 度) から見ると、 のように見え
ますが、同じようにずれている可能性があります。
レンダリングされているデバッグ ラインは、法線、接線、複接線です (これらはすべて正しく、地形のトポロジに適合しているように見えます)。
ここに私のシェーダーコードがあります:
頂点シェーダー:
PSIn mainvs(VSIn input)
{
PSIn output;
output.WorldPos = mul(float4(input.Position, 1.f), Instances[input.InstanceID].WorldMatrix); // pass pixel world position as opposed to screen space position for lighitng calculations
output.Position = mul(output.WorldPos, CameraViewProjectionMatrix);
output.TexCoord = input.TexCoord;
output.CameraPos = CameraPosition;
output.Normal = normalize(mul(input.Normal, (float3x3)Instances[input.InstanceID].WorldMatrix));
float3 Tangent = normalize(mul(input.Tangent, (float3x3)Instances[input.InstanceID].WorldMatrix));
float3 Bitangent = normalize(cross(output.Normal, Tangent));
output.TBN = transpose(float3x3(Tangent, Bitangent, output.Normal));
return output;
}
ピクセル シェーダー (Texcoord スカラーは、惑星の表面に近い小さなテクスチャ用です):
float3 FetchNormalVector(float2 TexCoord)
{
float3 Color = NormalTex.Sample(Samp, TexCoord * TexcoordScalar);
Color *= 2.f;
return normalize(float3(Color.x - 1.f, Color.y - 1.f, Color.z - 1.f));
}
float3 LightVector = -SunDirection;
float3 TexNormal = FetchNormalVector(input.TexCoord);
float3 WorldNormal = normalize(mul(input.TBN, TexNormal));
float nDotL = max(0.0, dot(WorldNormal, LightVector));
float4 SampleColor = float4(1.f, 1.f, 1.f, 1.f);
SampleColor *= nDotL;
return float4(SampleColor.xyz, 1.f);
事前に感謝します。ここで何が問題なのかについて何か洞察があればお知らせください。
編集 1: 通常のテクスチャからサンプリングする代わりに、固定の青の値で試してみました。これにより、マッピングを適用しなかった場合と同じ結果が得られます (期待どおり)。この問題の原因についてはまだ手がかりがありません。
編集 2: 最も奇妙なことに気付きました。0、0、+Z には、法線マッピングが有効
になっている場合にのみ表示されるこれらのハードシームがあります 少し見にくいですが、同じ頂点に複数の接線が関連付けられているように見えます (まだインデックスを使用していないため) ) デバッグ ラインが継ぎ目で分割されているように見えるためです。タンジェントを生成するために使用しているコードは次のとおりです (バイタンジェントは cross(Normal, Tangent) を使用して頂点シェーダーで計算されます)
v3& p0 = Chunk.Vertices[0].Position;
v3& p1 = Chunk.Vertices[1].Position;
v3& p2 = Chunk.Vertices[2].Position;
v2& uv0 = Chunk.Vertices[0].UV;
v2& uv1 = Chunk.Vertices[1].UV;
v2& uv2 = Chunk.Vertices[2].UV;
v3 deltaPos1 = p1 - p0;
v3 deltaPos2 = p2 - p0;
v2 deltaUV1 = uv1 - uv0;
v2 deltaUV2 = uv2 - uv0;
f32 r = 1.f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
v3 Tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r;
Chunk.Vertices[0].Tangent = Normalize(Tangent - (Chunk.Vertices[0].Normal * DotProduct(Chunk.Vertices[0].Normal, Tangent)));
Chunk.Vertices[1].Tangent = Normalize(Tangent - (Chunk.Vertices[1].Normal * DotProduct(Chunk.Vertices[1].Normal, Tangent)));
Chunk.Vertices[2].Tangent = Normalize(Tangent - (Chunk.Vertices[2].Normal * DotProduct(Chunk.Vertices[2].Normal, Tangent)));
また、参考までに、これは私がこれらすべてを実装する際に見た主な記事です:リンク