【UnityShader】レイマーチング入門【2】 #33
前回の成果
レイマーチング入門を行った。
今回やること
前回はただ白くしただけだったので、そこにライティングを加えていきます。
事前準備
前回と同様に、Scene上にQuadをおいてください。
ソースコード
Shader "Unlit/lightingRaymarching" { Properties { _MainTex ("Texture", 2D) = "white" {} _Radius("Radius", Range(0.0, 1.0)) = 0.3 } SubShader { Tags { "Queue"="Transparent" "LightMode"="ForwardBase"} LOD 100 Pass { ZWrite On Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 pos : POSITION1; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float _Radius; float sphere(float3 pos) { return length(pos) - _Radius; } float3 getNormal(float3 pos) { float d = 0.001; return normalize(float3( sphere(pos + float3(d, 0, 0)) - sphere(pos + float3(-d, 0, 0)), sphere(pos + float3(0, d, 0)) - sphere(pos + float3(0, -d, 0)), sphere(pos + float3(0, 0, d)) - sphere(pos + float3(0, 0, -d)))); } v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.pos = mul(unity_ObjectToWorld, v.vertex); o.uv = v.uv; return o; } fixed4 frag (v2f i) : SV_Target { float3 pos = i.pos.xyz; float3 rayDir = normalize(pos.xyz - _WorldSpaceCameraPos); int stepNum = 30; for (int i = 0; i < stepNum; i++) { float marcingDist = sphere(pos); if (marcingDist < 0.001) { float3 lightDir = _WorldSpaceLightPos0.xyz; float3 normal = getNormal(pos); float3 lightColor = _LightColor0; fixed4 col = fixed4(lightColor * max(dot(normal, lightDir), 0), 1.0); col.rgb += fixed3(0.2f, 0.2f, 0.2f); return col; } pos.xyz += marcingDist * rayDir.xyz; } return 0; } ENDCG } } }
前回のソースにライティングの処理を加えました。
getNormal
float3 getNormal(float3 pos) { float d = 0.001; return normalize(float3( sphere(pos + float3(d, 0, 0)) - sphere(pos + float3(-d, 0, 0)), sphere(pos + float3(0, d, 0)) - sphere(pos + float3(0, -d, 0)), sphere(pos + float3(0, 0, d)) - sphere(pos + float3(0, 0, -d)))); }
今回の記事はここがキモとなっています。
微分から自分は学びました
先に結論
先ほどのgetNormal関数は言ってしまえばこちらの距離函数を使った法線の公式
を求めたものになります。
そして、xの偏微分の定義が以下となるので、
getNormal関数で求められるわけですが、理解できなかったので一から説明していこうと思います。
参考サイト様 hackerslab.aktsk.jp
偏微分を理解するには、まず微分からだと思うので簡単に解説していきます。
微分
微分は一言でいうと、グラフの傾きのことです。
ここにのグラフがあります。
次に上のグラフを0.5付近で拡大したものを用意しました。
この拡大したグラフで見て欲しいところは
- 曲線であるのグラフの一部を拡大すると直線に見える
- x = 0.5で拡大した際のの傾きはだいたい1である
以上の二つです。
直線にみえるやだいたい1といった数学らしくない曖昧なところがありますが、そこは後で説明します。
x = 1 の時の傾き
x = 1で拡大した際ののグラフになります。
xが1増えると、yが2増えているので傾きは2となります。
傾きを実際に出してみる
グラフだけだとわかりにくい部分があるので、計算してみます。
例えば、のグラフにおけるx = 1.0 から x = 1.1までの変化の割合は
となるので、傾きは2.1となります。
次に、2点間の距離を縮めてみます。
のグラフにおけるx = 1.00 から x = 1.01までの変化の割合は
となるので、傾きは2.01になります。
これを先ほど出したx = 1の時の傾きである2に近づけるため、増加量を減らしていきます。
傾きの証明
次は2点間の距離をhとして、変化の割合を求めます。
hに0.1を入れると2.1となり、hに0.01を入れると2.01となるので、傾きを実際に出してみるの見出しで出しているものが証明されました。
を微分する
一般のxの点における傾きを求めます
hを限りなく0にすると、この式は2xとなります。
これにより、 を微分すると2xになることが証明されました。
記号で表す
ここまで実数で表していたので、記号で数学っぽく表します。
今回のグラフはと定義します。
先ほど、hを限りなく0にすると表現したのですが、それはで表されています。
この
を導関数の定義と呼びます。
この数式、どこかで見覚えがありませんか?
最初に説明した、xの偏微分の
に似ています。
この偏微分に関しては次回説明します。
これで微分は終了です。
だいぶ噛み砕いて説明したので、言葉足らずの部分があるかもしれないのですが、ご了承ください。
参考サイト様
今回はここまでとなります。
ここまでご視聴ありがとうございました!