イラスト、モデリング、Unity、VR関連

unityとかblenderとかvr関連の作業メモ

shader レイマーチ 変形テスト

参考

wgld.org | GLSL: オブジェクトを行列で捻じるように変換 |

Shader "Custom/Ray14"{
	Properties{
		_R1("R1",Float) = 0.3
		_R1Origin("R1Origin",Vector) = (-0.3,0,0,0)
		_R1SPD("R1SPD",float) = 50
		_R1AXIS("R1AXIS",Vector) = (1,0,0,0)
		_R1TwistPower("_R1TwistPower",Float) = 0

		_R2("R2",Float) = 0.3
		_R2Origin("R2Origin",Vector) = (0.3,0,0,0)
		_R2SPD("R2SPD",float) = 50
		_R2AXIS("R2AXIS",Vector) = (1,0,0,0)
		_R2TwistPower("_R2TwistPower",Float) = 0

		_Scale("Scale",Int) = 5
		_SplitNum("SplitNum",Range(0,100)) = 30
		_K("K",Range(0,70)) = 8

		_Normal("Normal",Range(0,0.1)) = 0.01
		_BoxTwistPower("BoxTwistPower",Range(0,80)) = 0
	}
	SubShader{
		Tags { "RenderType" = "Opaque" "LightMode" = "ForwardBase" }
		LOD 100
		Cull Off
		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			float _R1;
			float _R2;
			float _R1SPD;
			float _R2SPD;
			float4 _R1AXIS;
			float4 _R2AXIS;
			float _R1TwistPower;
			float _R2TwistPower;
			float _Scale;
			float4 _R1Origin;
			float4 _R2Origin;
			int _SplitNum;
			float _K;

			float _BoxTwistPower;
			float _Normal;

			struct appdata{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f{
				float2 uv : TEXCOORD0;
				float3 lpos : TEXCOORD1;
				float3 wpos : TEXCOORD2;
				float4 vertex : SV_POSITION;
			};

			v2f vert(appdata v){
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.lpos =v.vertex.xyz;//メッシュのローカル座標を代入
				o.wpos = mul(unity_ObjectToWorld,v.vertex);
				o.uv = v.uv;
				return o;
			}

			float3 twist(float3 p, float power){
    		float s = sin(power * p.y);
    		float c = cos(power * p.y);
    		float3x3 m = float3x3(
          						c, 0.0,  -s,
        							0.0, 1.0, 0.0,
          						s, 0.0,   c
    									);
    		return mul(m,p);
			}

			float3 rotate(float3 p, float angle, float3 axis){
    		float3 a = normalize(axis);
    		float s = sin(angle);
    		float c = cos(angle);
    		float r = 1.0 - c;
    		float3x3 m = float3x3(
        		a.x * a.x * r + c,
        		a.y * a.x * r + a.z * s,
        		a.z * a.x * r - a.y * s,
        		a.x * a.y * r - a.z * s,
        		a.y * a.y * r + c,
        		a.z * a.y * r + a.x * s,
        		a.x * a.z * r + a.y * s,
        		a.y * a.z * r - a.x * s,
        		a.z * a.z * r + c
    		);
    		return mul(m,p);
			}

			float box(float3 p){
				float s = 0.2;
				p = twist(p,_BoxTwistPower);
    		return length(max(abs(p) - float3(s,s,s),0.0));
			}

			float sphere(float3 p){
				p = twist(p,_R1TwistPower);
				return length(p) - 0.4;
			}

			float sphere1(float3 p){
				p = rotate(p, radians(_Time.y * _R1SPD), _R1AXIS.xyz);
				p = twist(p,_R1TwistPower);
				return length(p-_R1Origin) - _R1;
			}

			float sphere2(float3 p){
				p = rotate(p, radians(_Time.y * _R2SPD), _R2AXIS.xyz);
				p = twist(p,_R2TwistPower);
				return length(p-_R2Origin) - _R2;
			}

			float3 mod(float3 a, float3 b){
		 		return frac(abs(a / b)) * abs(b);
			}

			float3 trans(float3 p){
    		return mod(p, _Scale) - _Scale/2.0;
			}

			float smoothMin(float d1, float d2, float k){
			    float h = exp(-k * d1) + exp(-k * d2);
			    return -log(h) / k;
			}


			float dist(float3 p){
				//return sphere(p);
				return box(p);
				//return sphere1(p);
				//return smoothMin(sphere1(p),sphere2(p),_K);
				//return min(sphere1(p),sphere2(p));
				//return length(trans(p-_Origin)) - _R;
			}

			float3 getnormal(float3 p){
				//float d = 0.0001;
				float d= _Normal;
				return normalize(float3(
					dist(p + float3(d, 0.0, 0.0)) - dist(p + float3(-d, 0.0, 0.0)),
					dist(p + float3(0.0, d, 0.0)) - dist(p + float3(0.0, -d, 0.0)),
					dist(p + float3(0.0, 0.0, d)) - dist(p + float3(0.0, 0.0, -d))
				));
			}


			fixed4 frag(v2f i) : SV_Target{
				//メッシュのローカル座標の、視点のローカル座標からの方向を求めることでレイの方向を定義
				float3 start = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz;//レイのスタート位置をカメラのローカル座標とする
				float3 onelay = normalize(i.lpos.xyz - mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz);
				float d =0;
				float t=0.001;
				for (int i = 0; i < _SplitNum; ++i) { //レイマーチのループを実行
					d = dist(start + onelay * t);
						t += d;
						//レイがどこにもぶつからずはるか遠くに行くか、ほぼ衝突していて進む距離がほとんどなくなったらループを終了する
						if (d < 0.01 || t > 1000) {
							break;
						}
				}
				float4 col = 1;
				if (d > 0.01||t>1000) { //レイが遠くに行っているか、衝突していないと判断すれば描画しない
					clip(-1);
				}
				else {
					float3 normal = getnormal(start+onelay * t);
					float3 lightdir = normalize(mul(unity_WorldToObject, _WorldSpaceLightPos0).xyz);//オブジェクトスペースで計算しているので、ディレクショナルライトの角度もオブジェクトスペースにする
					float NdotL = max(0, dot(normal, lightdir));
					col = float4(float3(1,1,1)*NdotL,1);//ランバート反射を計算
				}
				return col;
			}
			ENDCG
		}//pass
	}//subshader
}