Shader "Unlit/ColorfulModSpheres" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert_img #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; float4 _MainTex_ST; //https://www.wwwmaplesyrup-cs6.work/entry/2019/07/16/112648 float mod(float y, float x) { return y - floor(y / x)*x; } float3 mod(float3 p, float a) { return p - floor(p / a)*a; } // hsv // 最初はsとvにはとりあえず1.0を与え、座標などからhに与える値を作り出して使います float3 hsv(float h, float s, float v) { float4 t = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); float3 p = abs(frac((h).xxx+t.xyz) * 6.0 - t.www); return v * lerp(t.xxx, clamp(p - t.xxx, 0.0, 1.0), s); } // 2次元座標での回転 float2 rot(float2 p, float a) { return float2(p.x*cos(a) - p.y*sin(a), p.x*sin(a) + p.y*cos(a)); } float ind; // object's index float distanceFunction(float3 pos, float size) { //距離関数 return length(pos) - size; } float map(float3 pos, float size) { // マンハッタン距離で色のインデックスを作る float ti = floor(mod(2.5 * _Time.y, 4)); float ia = ti * UNITY_TWO_PI / 4.; float3 ipos = pos + float3(1.5, 2., .0) * ti / 2.; ipos.xy = rot(ipos.xy, ia); ipos.yz = rot(ipos.yz, ia); ind = floor(1.5*ceil(.1*ipos.x) + 5.*ceil(.1*ipos.y) + 5.*ceil(.1*ipos.z)); return distanceFunction(mod(pos, 10.) - 5., size); } float3 normal(float3 p, float size) { //法線の取得  float2 e = float2(.01, 0); // 四面体アプローチでの法線推定 // refer iq's article return normalize(.000001 + map(p, size) - float3(map(p - e.xyy, size), map(p - e.yxy, size), map(p - e.yyx, size))); } float SSS(float3 ray, float3 rd, float d,float size) { return clamp(distanceFunction(ray + rd * d, size)*3., .0, 1.); } fixed4 frag (v2f_img i) : SV_Target { float ht = .5*_Time.y; //正規化 float2 uv = (i.uv.xy*2.0 - 1.); float size = clamp(1.25+sin(_Time.y*2.), 1., 2.); //オブジェクトのサイズ float3 CameraPos = float3(UNITY_PI + 7.*sin(_Time.y), UNITY_PI + 36.*sin(ht), -UNITY_PI + 24.*sin(ht)); //カメラのポジション float3 ta = (.0).xxx; CameraPos.xz = rot(CameraPos.xz, _Time.y); ta.xz = rot(ta.xz, _Time.y); float3 fwd = normalize(ta - CameraPos) , up = float3(.0, 1., .0) , side = normalize(cross(fwd, up)); up = normalize(cross(side, fwd)); float screenZ = UNITY_PI; //スクリーンポジション float3 RayDir = normalize(uv.x*side + uv.y*up + fwd * screenZ); //レイの方向 float3 lightDir; //ライトの位置 float depth = 0.0; //レイの進んだ距離 float dist = 0.0; float3 rayPos = (0.0).xxx; //レイの位置 float3 col = (0.0).xxx; //色 int j = 1; for (int i = 0; i < 99; i++) { rayPos = CameraPos + (RayDir * depth); //レイの位置を計算 dist = map(rayPos, size); //一番近いオブジェクトまでの距離を測る if (dist < 0.0001) break; //オブジェクトに例がぶつかったらfor文を抜ける depth += dist; //レイの進んだ距離の更新 j = i + 1; } lightDir = normalize(-rayPos + CameraPos); // インデックスをhueに与えてhsvで着色 float indh = ind * .15; col = hsv(indh, .8, .8); float diff=.0; if (dist < 0.0001) { float3 n = normal(rayPos, 1.0); //法線の取得 diff = max(dot(n, lightDir), .01); //法線と光の内積取得 } col *= diff; //色を混ぜる col += float(j) / 64.; // fog col += SSS(rayPos, RayDir, .05, size)*.005 + SSS(rayPos, RayDir, .025, size)*.0025; // SSS return fixed4(col, 1.0); } ENDCG } } }