私は何日もこれと格闘してきました。最終的に頂点ごとの接線の問題に絞り込んだと思いますが、それを修正する最善の方法はわかりません。
コンテキストは iPhone アプリで、独自のエンジンを使用した opengl es2 です。私のシェーダーは、提供された頂点ごとの接線を使用して TBN マトリックスを作成するバンプ マップ (法線マップ) です。頂点シェーダーは、ライト ベクトルと目のベクトルを接線空間に変換し、それらをフラグメント シェーダーに渡し、ライトを計算します。しかし、最初の 2 つのテスト モデルの一部のジオメトリは、照明に奇妙なアーティファクトを示しています。鏡面反射光コンポーネントで見るのが最も簡単です。
これをデバッグしようとして、法線マップをフラットな法線 png に置き換えました。すべてのピクセルは 128,128,255 です。色もハードコーディングしました。
私の最初のモデルはボタンの形です。これは、アーティファクトを、外側のリングでのスカラップ スペキュラー ヒットとして示しています。注意すべき重要な点は、ここでの UV マッピング方法は「フラット」であり、マッピングに垂直な側面が基本的にそこを横切ってテクスチャをストリークすることです。これにより、2 つのポイントがまったく同じテクスチャ座標を持つため、そのジオメトリの接線の計算が難しくなると思います。
gl_FragColor をさまざまな変数に設定してレンダリングをデバッグしようとしました。頂点ごとの法線に設定すると、スカロッピングがなくなり、法線が正しいことがわかります。しかし、頂点ごとの接線に設定すると、スカラップが表示されます。
次の形状は単純な球体です。これにより、モデルの最上部と最下部にアーティファクトが表示されます。ワイヤーフレームでは、複数の三角形が 1 つの頂点で交わっている場所であることがわかります。各三角形には完全に異なる UV マッピングがあるため、接線にとってそれが何を意味するのかについて頭を悩ませることはできません。
シェーダーコードを表示しないと、多くのフラックが発生すると思います...
頂点シェーダー:
v_fragmentTexCoord0 = a_vertexTexCoord0;
gl_Position = u_modelViewProjectionMatrix * vec4(a_vertexPosition,1.0);
vec3 normal = normalize(u_normalMatrix * a_vertexNormal);
vec3 tangent = normalize(u_normalMatrix * a_vertexTangent);
vec3 bitangent = cross(normal, tangent);
mat3 TBNMatrix = mat3(tangent, bitangent, normal);
v_eyeVec = -a_vertexPosition.xyz;
v_eyeVec *= TBNMatrix;
v_lightVec = u_lightPosition - a_vertexPosition.xyz;
v_lightVec *= TBNMatrix;
v_normal = a_vertexTangent;
フラグメント シェーダー:
vec3 norm = texture2D(u_normalSampler, v_fragmentTexCoord0).rgb * 2.0 - 1.0;
vec4 baseColor = vec4(0.6015625,0.0,0.0,1.0); // is normally texture2D(u_textureSampler,v_fragmentTexCoord0);
float dist = length(v_lightVec);
vec3 lightVector = normalize(v_lightVec);
float nxDir = max(0.0, dot(norm, lightVector));
vec4 diffuse = u_lightColorDiffuse * nxDir;
float specularPower = 0.0;
if(nxDir != 0.0)
{
vec3 cameraVector = v_eyeVec;
vec3 halfVector = normalize(v_lightVec + cameraVector);
float nxHalf = max(0.0,dot(norm, halfVector));
specularPower = pow(nxHalf, u_shininess);
}
vec4 specular = u_lightColorSpecular * specularPower;
gl_FragColor = (diffuse * vec4(baseColor.rgb,1.0)) + specular;
シェーダーを理解しようとして、オンラインで見つけたすべてのサンプルとチュートリアルを調べて... バンプ マップ シェーダーが 3D モデルによって提供される法線マップを乱すだけではない理由に戸惑いました。モデルの法線を変更する方法をどのように知っているのですか?どの向きで?それがTBNマトリックスの目的だと思います。しかし、上記の私のテストでは、法線マップの法線ベクトルは 0,0,1 - まっすぐです。したがって、それをまったく変更するべきではないようです。1 を何回掛けても 1 のままです。しかし、数学または TBN マトリックスに何か問題があり、3D モデルと同じ法線が得られないことがあります。それから、そのアイデアは私に何かをひらめきました..私の頂点シェーダーで私は また、最初に頂点法線を normalMatrix で乗算して、モデル空間に取得します。しかし、これらのデバッグ レンダーは、変換前の頂点法線のものです。
TBN 行列を使用せずにモデルの法線を乱す別の方法はありますか? 法線マップなしでフォン シェーダーを使用してレンダリングすると、アーティファクトが表示されません。
更新:問題は、インポートするアプリによって作成された事前計算された接線であるとほぼ確信しています。さまざまな UV マップでさまざまなモデルを試したところ、似たような問題が見つかりました。ハイライトではなく暗くなっている場合があります。したがって、TBM マトリックスを使用せずに法線マップを適用したり、接線空間に変換したりできない限り、別のインポーターを見つける必要があります。
更新 #2: 本当の問題の手がかりになりそうなこの別の質問を見つけました。 3D グラフィックス、単位ベクトル、直交行列
これらの奇妙なライトは頂点ではなく、それらの間でのみ発生することに注意することが重要です。球体でも、一番上の頂点とそのすぐ下の頂点の間にリングが見えます。これは補間の問題だと思い始めています。そこにある三角形の 1 つだけを取り上げます。
私がそれを再計算している 2 番目の原因については、悪いバイタンジェントを無視してください。しかし、接線は反対の極性を持っています。したがって、これらの 2 つの状態の間で補間されている間に、あらゆる場所を指すベクトルが得られます。
新しい質問は、どうすれば解決できますか? 接線を修正しますか? それに対処するためにシェーダーを修正しますか?