Triplanar Mapping
下記チュートリアルで紹介されているTriplanar Mappingをやってみます。 www.ronja-tutorials.com
Triplanar Mappingとは
Triplanar Mappingとはどういうものかと言うと、上方向、横方向からテクスチャを貼り付けるようなイメージです。 モデルのUVを参照せず、world座標を参照するため、他のモデルとの境界線を目立たなくさせる事ができます。 地形などを作るのに向いていそうです。
頂点shader
まず、頂点shaderの処理。UVではなくworld空間の座標を参照するようにします。
また、3方向から投影するテクスチャをどれだけ混ぜるか? の指標とするため、 world空間でのモデルの法線を求めます。
struct appdata{ float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f{ float4 position : SV_POSITION; float3 worldPos : TEXCOORD0; float3 normal : NORMAL; // world空間での法線 }; v2f vert(appdata v){ v2f o; o.position = UnityObjectToClipPos(v.vertex); // 頂点のworld座標を求める float4 worldPos = mul(unity_ObjectToWorld, v.vertex); o.worldPos = worldPos.xyz; // world空間での法線を求める o.normal = UnityObjectToWorldNormal(v.normal); return o; }
world空間でのモデルの法線の算出について、なぜその計算になるのか? についてはこちらが詳しかったです。 raytracing.hatenablog.com
fragment shader
次にfragment shaderの処理。
fixed4 frag(v2f i) : SV_TARGET{
// TRANSFORM_TEXを使ってテクスチャのrepeatなどを考慮
float2 uv_front = TRANSFORM_TEX(i.worldPos.xy, _MainTex);
float2 uv_side = TRANSFORM_TEX(i.worldPos.zy, _MainTex);
float2 uv_top = TRANSFORM_TEX(i.worldPos.xz, _MainTex);
TRANSFORM_TEXをする事でtexutreのoffset, tilingが反映されます。 UnityのTRANSFORM_TEXマクロ | 生存日記
// 先程作ったworld座標ベースのuvでtextureを読みます。 fixed4 col_front = tex2D(_MainTex, uv_front); // xy平面から貼り付けるtexture fixed4 col_side = tex2D(_MainTex, uv_side); // zy平面から貼り付けるtexutre fixed4 col_top = tex2D(_MainTex, uv_top); // 上 (xz平面) から貼り付けるtxture
3方向から投影するテクスチャをどれだけ混ぜるか? の指標となる重みを定義します。 法線はマイナスの値も取るので、ここは絶対値を使います。 マイナスの値を採用すると、下方向を向いた面が黒くなってしまいます。
// world座標の法線をもとにした重みを定義 float3 weights = i.normal; // 法線が単純に縦方向を向いているのか? 横方向を向いているのか? の判断だけに使うので、絶対値を使う。 weights = abs(weights); // 全部足して1になるよう調整する。暗くなるのを避けるため。 weights = weights / (weights.x + weights.y + weights.z); // それぞれの重みを影響させる col_front *= weights.z; col_side *= weights.x; col_top *= weights.y; // 3方向を合成 fixed4 col = col_front + col_side + col_top; // 外部propertyでの色調整を反映 col *= _Color; return col;
ここで、上方向からのテクスチャを草に入れ替えてみます。 上方向からのテクスチャをpropertyとして持たせ、反映させるようコードを修正します。
_MainTexTop ("Texture", 2D) = "white" {} //... sampler2D _MainTexTop; float4 _MainTexTop_ST; //... float2 uv_top = TRANSFORM_TEX(i.worldPos.xz, _MainTexTop);
上方向を向いている部分に草が生えました。
しかし、なんだか草部分がボンヤリしていますね。
期待している状態はこんな感じです。
このための修正をしていきます。
より方向の影響を強くする
係数とpowを使って重みを際立たせます。
powを使うとどう値が変化するのかは下記にて。 ssr-maguro.hatenablog.com
//... _Sharpness("Blend Sharpness", Range(1, 64)) = 1 //... float _Sharpness; //... weights = abs(weights); // powを使って重みをくっきりさせる weights = pow(weights, _Sharpness); weights = weights / (weights.x + weights.y + weights.z); //...
完成、ブラッシュアップ
これで期待した絵になりました。
しかしまだ色々問題があり、下から見ても草が生えていたりします。
次はこういった問題を解消し、草が生える範囲を調整できたりするようにしてみます。 続く。