LuminoEngine/Lumino

法線マップをサポートする

Opened this issue · 0 comments

lriki commented

Proposal

法線マップテクスチャは Material に設定して使う。

material->setNormalMap(Texture2D::load(u"normal.png"));

接線ベクトルは標準頂点データとして追加する。

 struct Vertex
 {
     Vector3 position;
     Vector3 normal;
     Vector2 uv;
     Color color;
+    Vector4 tangent;
 };

VertexTangents は削除。

シェーダについては、法線マップ処理の有無をスイッチできるようにする。

 @module
 techniques:
     Forward_Geometry_UnLighting:
         passes:
         -   Pass0:
+                defines: USE_NORMALMAP
                 vertexShader: VS_ClusteredForward_Geometry
                 pixelShader: PS_Main
 @end

※define よりは TechniqueClass に新しいグループを作ったほうがいいかも。

Implementation

Unity や three.js と同じにしてみる。

従法線ベクトルは頂点シェーダで計算する。現状頂点セマンティクスとして Binormal はサポートしているが、Tangent だけにしてみる。

three.js の実装メモは後述。

Note

懸念 - struct Vertex のデータサイズ増大

そろそろ無視できなくなってきそう。

これまでの想定としては従法線も CPU 側で計算する予定だったから VertexTangents を作って、標準頂点とは別ストリームの頂点バッファとして作る予定だった。

VertexTangents はこんな感じ。

struct VertexTangents
{
    Vector3 tangent;
    Vector3 binormal;
};

結果的に Vector4 だけで済んだので別頂点バッファにするのは大げさかな…ということで標準頂点の方に統合してみる。

実際に Lumino を使ったシーンでどれだけ法線マップが使われるかは何とも言えないけど…。

これ以上別なデータが増えそうならまた分離を考えよう。

ちなみに統合しない場合、MeshGenerator で作っている球とかの標準形状で複数の頂点バッファが必要となり、かなり大掛かりな変更が必要になる。

シェーダ

法線テクスチャを使わないときは、青で塗りつぶしたデフォルトのテクスチャを使用すればスイッチの必要はないが、
シェーダだけでなく CPU 側でも ModelView の逆行列を計算したりと、それなりの負荷の処理を行うため切り替えられるようにしておく。

three.js

defaultnormal_vertex.glsl.js で、やっぱりView空間へ変換しているようだ。

vec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;

次に normal_vert.glsl.js で

vTangent = normalize( transformedTangent );
vBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );

tangent は vec4。.w は求めた 従法線 を反転するかどうかを示す、おそらく 1 or -1 の値が入っている。

その他

  • normal_fragment_begin.glsl.js
  • normal_fragment_maps.glsl.js

Unity

three.js と同じ実装のようだ。