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

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

shader マンデルバルブの移植1

Shader - Shadertoy BETA

 

 

Shader "Custom/1" {
	Properties{
		_MainTex("MainTex",2D) = "white"{}
	}
	SubShader{
		Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
		Blend SrcAlpha OneMinusSrcAlpha

		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f {
				float4 pos:SV_POSITION;
				float4 uv:TEXCOORD0;
			};

			v2f vert(appdata v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}

			/*
				Emin Kura - http://emin.me
			*/
			float3 rotate( float3 pos, float x, float y, float z )
			{
				float3x3 rotX = float3x3( 1.0, 0.0, 0.0, 0.0, cos( x ), -sin( x ), 0.0, sin( x ), cos( x ) );
				float3x3 rotY = float3x3( cos( y ), 0.0, sin( y ), 0.0, 1.0, 0.0, -sin(y), 0.0, cos(y) );
				float3x3 rotZ = float3x3( cos( z ), -sin( z ), 0.0, sin( z ), cos( z ), 0.0, 0.0, 0.0, 1.0 );
				//return rotX * rotY * rotZ * pos;
				return mul(mul(mul(rotX,rotY),rotZ),pos);
			}

			float hit( float3 r )
			{
				r = rotate( r, sin(_Time.y), cos(_Time.y), 0.0 );
				float3 zn = float3( r.xyz );
				float rad = 0.0;
				float hit = 0.0;
				float p = 8.0;
				float d = 1.0;
				for( int i = 0; i < 10; i++ ){
						rad = length( zn );
						if( rad > 2.0 ){
							hit = 0.5 * log(rad) * rad / d;
						}else{
							float th = atan2( length( zn.xy ), zn.z );
							float phi = atan2( zn.y, zn.x );
							float rado = pow(rad,8.0);
							d = pow(rad, 7.0) * 7.0 * d + 1.0;
							float sint = sin( th * p );
							zn.x = rado * sint * cos( phi * p );
							zn.y = rado * sint * sin( phi * p );
							zn.z = rado * cos( th * p ) ;
							zn += r;
						}
				}
				return hit;
			}



			float4 frag(v2f i) :SV_Target {
				float2 pos = -1.0 + 2.0 * i.uv;

				pos.x *= _ScreenParams.x / _ScreenParams.y;

				float3 ro = float3( pos, -1.2 );
				float3 la = float3( 0.0, 0.0, 1.0 );

				float3 cameraDir = normalize( la - ro );
				float3 cameraRight = normalize( cross( cameraDir, float3( 0.0, 1.0, 0.0 ) ) );
				float3 cameraUp = normalize( cross( cameraRight, cameraDir ) );


				float3 rd = normalize( cameraDir + float3( pos, 0.0 ) );

				float t = 0.0;
				float d = 200.0;

				float3 r;
				float3 color = float3(0,0,0);
				int rayCnt = 0;
				for(rayCnt = 0; rayCnt < 100; rayCnt++ ){
					if( d > .001 ){
						r = ro + rd * t;
						d = hit( r );
						t+=d;
					}
				}


				float3 eps = float3( .1, 0.0, 0.0 );
				float3 n = float3( hit( r + eps ) - hit( r - eps ),
			  							 hit( r + eps.yxz ) - hit( r - eps.yxz ),
				  					 	 hit( r + eps.zyx ) - hit( r - eps.zyx ) );

				float3 mat = float3( .5, .1, .3 );
			 	float3 light = float3( .5, .5, -2.0 );
				float3 lightCol = float3(.6, .4, .5);

				float3 ldir = normalize( light - r );
			  float3 diff = dot( ldir, n ) * lightCol * 60.0;

				color = diff * mat;
			  return float4( color, 1.0 );
			}


			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}

私の解釈コメントありver

Shader "Custom/1" {
	Properties{
		_MainTex("MainTex",2D) = "white"{}
	}
	SubShader{
		Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
		Blend SrcAlpha OneMinusSrcAlpha

		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f {
				float4 pos:SV_POSITION;
				float4 uv:TEXCOORD0;
			};

			v2f vert(appdata v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}

			/*
				Emin Kura - http://emin.me
			*/
			float3 rotate( float3 pos, float x, float y, float z )
			{
				float3x3 rotX = float3x3( 1.0, 0.0, 0.0, 0.0, cos( x ), -sin( x ), 0.0, sin( x ), cos( x ) );
				float3x3 rotY = float3x3( cos( y ), 0.0, sin( y ), 0.0, 1.0, 0.0, -sin(y), 0.0, cos(y) );
				float3x3 rotZ = float3x3( cos( z ), -sin( z ), 0.0, sin( z ), cos( z ), 0.0, 0.0, 0.0, 1.0 );
				//return rotX * rotY * rotZ * pos;
				return mul(mul(mul(rotX,rotY),rotZ),pos);
			}

			//マンデルバルブの距離関数
			float hit( float3 r )
			{
				//r = rotate( r, sin(_Time.y), cos(_Time.y), 0.0 );
				//レイの現在地を回転させている-これでオブジェクトも回転する

				float3 zn = r;
				float rad = 0.0; //znベクトルの距離
				float hit = 0.0; //レイとオブジェクトとの距離
				float p = 8.0;
				float d = 1.0;
				for( int i = 0; i < 10; i++ ){
						rad = length( zn );
						if( rad > 2.0 ){
							hit = 0.5 * log(rad) * rad / d;
							//距離推定式、なぜか分からないがこれで距離を割り出せる
							//http://blog.hvidtfeldts.net/index.php/2011/09/distance-estimated-3d-fractals-iv-the-holy-grail/
						}else{
							//極座標系への変換
							float th = atan2( length( zn.xy ), zn.z );
							//=>float th = acos(zn.z/rad);これと同じ結果を得られる
							float phi = atan2( zn.y, zn.x );
							d = pow(rad, 7.0) * 7.0 * d + 1.0;
							//極座標系への変換
							//http://blog.hvidtfeldts.net/index.php/2011/09/distance-estimated-3d-fractals-v-the-mandelbulb-different-de-approximations/

							float rado = pow(rad,8.0);
							float sint = sin( th * p );
							zn.x = rado * sint * cos( phi * p );
							zn.y = rado * sint * sin( phi * p );
							zn.z = rado * cos( th * p ) ;
							//th*p,phi*pで拡大縮小と回転、デカルト座標系に戻している
							//これなんでsin(th*p)だけ事前に計算してるんだろうか?
							zn += r;
						}
				}
				return hit;
			}



			float4 frag(v2f i) :SV_Target {
				float2 pos = 2.0 * i.uv - 1;
				//i.uvはデフォルトで0~1,
				//2倍して1引くことで-1~1に変換している

				//pos.x *= _ScreenParams.x / _ScreenParams.y;
				//これはない方がきれいになる

				float3 ro = float3( pos, -1.0 );
				//レイの発射地点・値を小さくするとオブジェクトが小さくなる

				float3 la = float3( 0.0, 0.0, 1.0 );

				float3 cameraDir = normalize( la - ro );
				//レイを飛ばす方向(-pos,2.0) roからlaへのベクトル

				//float3 cameraRight = normalize( cross( cameraDir, float3( 0.0, 1.0, 0.0 ) ) );
				//float3 cameraUp = normalize( cross( cameraRight, cameraDir ) );
				//外積でカメラの右方向と上方向を取得-導出されているけど使われてないのでコメントアウト

				float3 rd = normalize( cameraDir + float3( pos, 0.0 ) );
				//レイを伸ばす1単位あたりの距離

				//これのレイマーチの仕組みがよく分からない

				float t = 0.0;
				float d = 200.0;

				float3 r;
				float3 color = float3(0,0,0);
				int rayCnt = 0;
				for(rayCnt = 0; rayCnt < 100; rayCnt++ ){
					/*
					if( d > .001 ){
						r = ro + rd * t;
						d = hit( r );
						t+=d;
					}*/
					if(d < 0.001 || t>100) break; //こうした方がスマートでは?
					r = ro + rd * t;
					d = hit(r);
					t+=d;
				}


				float3 eps = float3( 0.1, 0, 0.0 );
				float3 n = float3( hit( r + eps ) - hit( r - eps ),
			  							 hit( r + eps.yxz ) - hit( r - eps.yxz ),
				  					 	 hit( r + eps.zyx ) - hit( r - eps.zyx ) );
				//法線方向の取得-だと思うが原理不明

				float3 mat = float3( .5, .1, .3 );
				//オブジェクトの色?

			 	float3 light = float3( .5, .5, -2.0 );
				//ライトの位置

				float3 lightCol = float3(.6, .4, .5);
				//ライトの色

				float3 ldir = normalize( light - r );
				//r(レイのヒット地点)からライトへの方向ベクトル

			 	float3 diff = dot( ldir, n ) * lightCol * 60.0;
				//法線方向(オブジェクトの面の向きとldirとの内積、
				//ベクトルが垂直であるほど0に近く、平行であるほど-1 or 1に近づく
				color = diff * mat;
			  return float4( color, 1.0 );
			}


			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}

色々いじったver

Shader "Custom/1" {
	Properties{
		_DiffCameraPos("DiffCameraPos",Vector) = (0,0,0,0)
		_P1("P1",Float) = 0
		_S("S",Float) = 1
	}
	SubShader{
		Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
		Blend SrcAlpha OneMinusSrcAlpha
		Cull Off
		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f {
				float4 pos:SV_POSITION;
				float4 lpos:POSITION1;
				float4 uv:TEXCOORD0;
			};

			float4 _DiffCameraPos;
			float _P1;
			float _S;

			v2f vert(appdata v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.lpos = v.vertex;
				o.uv = v.uv;
				return o;
			}

			/*
				Emin Kura - http://emin.me
			*/
			float3 rotate( float3 pos, float x, float y, float z )
			{
				float3x3 rotX = float3x3( 1.0, 0.0, 0.0, 0.0, cos( x ), -sin( x ), 0.0, sin( x ), cos( x ) );
				float3x3 rotY = float3x3( cos( y ), 0.0, sin( y ), 0.0, 1.0, 0.0, -sin(y), 0.0, cos(y) );
				float3x3 rotZ = float3x3( cos( z ), -sin( z ), 0.0, sin( z ), cos( z ), 0.0, 0.0, 0.0, 1.0 );
				//return rotX * rotY * rotZ * pos;
				return mul(mul(mul(rotX,rotY),rotZ),pos);
			}

			float3 scale(float3 pos){
				float3x3 sl = float3x3(_S,0,0,
															 0,_S,0,
															 0,0,_S);
				return mul(sl,pos);
			}

			//マンデルバルブの距離関数
			float hit( float3 r ){
				//r = rotate( r, sin(_Time.y), cos(_Time.y), 0.0 );
				//レイの現在地を回転させている-これでオブジェクトも回転する
				r = scale(r);
				float3 zn = r;
				float rad = 0.0; //znベクトルの距離
				float hit = 0.0; //レイとオブジェクトとの距離
				float p = 8.0;
				float d = 1.0;
				for( int i = 0; i < 10; i++ ){
						rad = length( zn );
						if( rad > 2.0 ){
							hit = 0.5 * log(rad) * rad / d;
							//距離推定式、なぜか分からないがこれで距離を割り出せる
							//http://blog.hvidtfeldts.net/index.php/2011/09/distance-estimated-3d-fractals-iv-the-holy-grail/
						}else{
							//極座標系への変換
							//float th = atan2( length( zn.xy ), zn.z ) - _P1;
							//沸きだす感じになる
							float th = atan2( length( zn.xy ), zn.z );
							//=>float th = acos(zn.z/rad);これと同じ結果を得られる
							//float phi = atan2( zn.y, zn.x ) - _P1;
							//回転
							float phi = atan2( zn.y, zn.x );
							//d = pow(rad, 7.0) * 7.0 * d + 1.0-_P1;
							//面白い、言葉にしにくい
							//d = pow(rad, 7.0) * 7.0 * d + 1.0;
							//d = pow(rad, 7.0) * 7.0 * d + 1.0;
							d = pow(rad, _P1) * _P1 * d + 1.0;
							//極座標系への変換
							//http://blog.hvidtfeldts.net/index.php/2011/09/distance-estimated-3d-fractals-v-the-mandelbulb-different-de-approximations/
							//float rado = pow(rad,8.0) - _P1;
							//面白い
							float rado = pow(rad,8.0);
							//zn.x = rado * sin( th * p ) * cos( phi * p ) + _P1;
							//面白い
							//zn.x = rado * (sin( th * p ) + _P1) * cos( phi * p );
							//尖る-cos,zn.yについても同じ
							//zn.x = (rado+_P1) * sin( th * p ) * cos( phi * p );
							//全体的に砂になって消える感じ
							//zn.x = (rado+_P1) * sin( th * p ) * cos( phi * p );
							//zn.y = (rado+_P1) * sin( th * p ) * sin( phi * p );
							//zn.z = (rado+_P1) * cos( th * p );
							//全体的に砂になって消えるー良い感じ
							//zn.y = rado * sin( th * p ) * sin( phi * p );
							//zn.z = rado * cos( th * p ) + _P1;
							//面白い
							//zn.z = rado * cos( th * p ) + _P1;
							//面白い
							zn.x = rado * sin( th * p ) * cos( phi * p );
							zn.y = rado * sin( th * p ) * sin( phi * p );
							zn.z = rado * cos( th * p );
							//th*p,phi*pで拡大縮小と回転、デカルト座標系に戻している
							//原理は分からん
							zn += r;
						}
				}
				return hit;
			}



			float4 frag(v2f i) :SV_Target {
				//float2 pos = 2.0 * i.uv - 1;
				//i.uvはデフォルトで0~1,
				//2倍して1引くことで-1~1に変換している

				//pos.x *= _ScreenParams.x / _ScreenParams.y;
				//これはない方がきれいになる

				//float3 ro = float3( pos, -1.0 );
				//レイの発射地点・値を小さくするとオブジェクトが小さくなる

				//float3 la = float3( 0.0, 0.0, 1.0 );

				//float3 cameraDir = normalize( la - ro );
				//レイを飛ばす方向(-pos,2.0) roからlaへのベクトル

				//float3 cameraRight = normalize( cross( cameraDir, float3( 0.0, 1.0, 0.0 ) ) );
				//float3 cameraUp = normalize( cross( cameraRight, cameraDir ) );
				//外積でカメラの右方向と上方向を取得-導出されているけど使われてないのでコメントアウト

				//float3 rd = normalize( cameraDir + float3( pos, 0.0 ) );
				//レイを伸ばす1単位あたりの距離

				float3 ro = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz;
				ro += _DiffCameraPos;
				//float3 rd = normalize((i.lpos.xyz*_P1) - mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz);
				//オブジェクトの縮小
				float3 rd = normalize((i.lpos.xyz) - mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz);


				float t = 0.0;
				float d = 200.0;

				float3 r;
				float3 color = float3(0,0,0);
				int rayCnt = 0;
				for(rayCnt = 0; rayCnt < 50; rayCnt++ ){
					/*
					if( d > .001 ){
						r = ro + rd * t;
						d = hit( r );
						t+=d;
					}*/
					r = ro + rd * t;
					d = hit(r);
					t+=d;
					if(d < 0.001 || t>100) break; //こうした方がスマートでは?
				}


				float3 eps = float3( 0.1, 0, 0.0 );
				float3 n = float3( hit( r + eps ) - hit( r - eps ),
			  							 hit( r + eps.yxz ) - hit( r - eps.yxz ),
				  					 	 hit( r + eps.zyx ) - hit( r - eps.zyx ) );
				//法線方向の取得-だと思うが原理不明

				float3 mat = float3( .5, .1, .3 );
				//オブジェクトの色?

			 	float3 light = float3( .5, .5, -2.0 );
				//ライトの位置

				float3 lightCol = float3(.6, .4, .5);
				//ライトの色

				float3 ldir = normalize( light - r );
				//r(レイのヒット地点)からライトへの方向ベクトル

			 	//float3 diff = dot( ldir, n ) * lightCol * 60.0;
				float3 diff = abs(dot( ldir, n )) * lightCol * 60.0;
				//法線方向(オブジェクトの面の向きとldirとの内積、
				//ベクトルが垂直であるほど0に近く、平行であるほど-1 or 1に近づく
				color = diff * mat;
			  return float4( color, 1.0 );
			}


			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}

レイマーチミスって離れると切れるの修正したver

Shader "Custom/1" {
	Properties{
		_DiffCameraPos("DiffCameraPos",Vector) = (0,0,0,0)
		_P1("P1",Float) = 0
		_S("S",Float) = 1
		_R("R",Vector) = (0,0,0,0)
		_RayUpLimit("RayUpLimit",Float) = 50
	}
	SubShader{
		Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
		Blend SrcAlpha OneMinusSrcAlpha
		Cull Off
		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f {
				float4 pos:SV_POSITION;
				float4 lpos:POSITION1;
				float4 wpos:POSITION2;
				float4 uv:TEXCOORD0;
			};

			float4 _DiffCameraPos;
			float _P1;
			float _S;
			float4 _R;
			float _RayUpLimit;

			v2f vert(appdata v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.lpos = v.vertex;
				o.wpos = mul(unity_ObjectToWorld,v.vertex);
				o.uv = v.uv;
				return o;
			}

			/*
				Emin Kura - http://emin.me
			*/
			float3 rotate(float3 pos){
				float x = _R.x+_Time.y/2;
				float y = _R.y+_Time.y/3;
				float z = _R.z+_Time.y/4;
				float3x3 rotX = float3x3( 1.0, 0.0, 0.0, 0.0, cos( x ), -sin( x ), 0.0, sin( x ), cos( x ) );
				float3x3 rotY = float3x3( cos( y ), 0.0, sin( y ), 0.0, 1.0, 0.0, -sin(y), 0.0, cos(y) );
				float3x3 rotZ = float3x3( cos( z ), -sin( z ), 0.0, sin( z ), cos( z ), 0.0, 0.0, 0.0, 1.0 );
				//return rotX * rotY * rotZ * pos;
				return mul(mul(mul(rotX,rotY),rotZ),pos);
			}

			//マンデルバルブの距離関数
			float hit( float3 r ){
				r = rotate(r);
				//レイの現在地を回転させている-これでオブジェクトも回転する
				float3 zn = r;
				float rad = 0.0; //znベクトルの距離
				float hit = 0.0; //レイとオブジェクトとの距離
				float p = 8.0;
				float d = 1.0;
				for( int i = 0; i < 10; i++ ){
						rad = length( zn );
						if( rad > 2.0 ){
							hit = 0.5 * log(rad) * rad / d;
							//距離推定式、なぜか分からないがこれで距離を割り出せる
							//http://blog.hvidtfeldts.net/index.php/2011/09/distance-estimated-3d-fractals-iv-the-holy-grail/
						}else{
							//極座標系への変換
							//float th = atan2( length( zn.xy ), zn.z ) - _P1;
							//沸きだす感じになる
							float th = atan2( length( zn.xy ), zn.z );
							//=>float th = acos(zn.z/rad);これと同じ結果を得られる
							//float phi = atan2( zn.y, zn.x ) - _P1;
							//回転
							float phi = atan2( zn.y, zn.x );
							//d = pow(rad, 7.0) * 7.0 * d + 1.0-_P1;
							//面白い、言葉にしにくい
							d = pow(rad, 7.0) * 7.0 * d + 1.0;
							//極座標系への変換
							//http://blog.hvidtfeldts.net/index.php/2011/09/distance-estimated-3d-fractals-v-the-mandelbulb-different-de-approximations/
							//float rado = pow(rad,8.0) + _P1;
							//面白い
							float rado = pow(rad,8.0);
							//zn.x = rado * sin( th * p ) * cos( phi * p ) + _P1;
							//面白い
							//zn.x = rado * (sin( th * p ) + _P1) * cos( phi * p );
							//尖る-cos,zn.yについても同じ
							//zn.x = (rado+_P1) * sin( th * p ) * cos( phi * p );
							//全体的に砂になって消える感じ
							//zn.x = (rado+_P1) * sin( th * p ) * cos( phi * p );
							//zn.y = (rado+_P1) * sin( th * p ) * sin( phi * p );
							//zn.z = (rado+_P1) * cos( th * p );
							//全体的に砂になって消えるー良い感じ
							//zn.y = rado * sin( th * p ) * sin( phi * p );
							//zn.z = rado * cos( th * p ) + _P1;
							//面白い
							//zn.z = rado * cos( th * p ) + _P1;
							//面白い
							zn.x = rado * sin( th * p ) * cos( phi * p );
							zn.y = rado * sin( th * p ) * sin( phi * p );
							zn.z = rado * cos( th * p );
							//th*p,phi*pで拡大縮小と回転、デカルト座標系に戻している
							//原理は分からん
							zn += r;
						}
				}
				return hit;
			}



			float4 frag(v2f i) :SV_Target {
				float3 ro = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz;
				float3 rd = normalize((i.lpos.xyz) - mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz);
				ro = i.lpos.xyz;
				ro += _DiffCameraPos;
				ro *= _S;//なぜか縮小出来る

				float t = 0.0;
				float d = 200.0;

				float3 r;
				float3 color = float3(0,0,0);
				int rayCnt = 0;
				for(rayCnt = 0; rayCnt < 50+_P1; rayCnt++ ){
					r = ro + rd * t;
					d = hit(r);
					t+=d;
					if(d < 0.001 || t>_RayUpLimit) break; //こうした方がスマートでは?
				}


				float3 eps = float3( 0.1, 0, 0.0 );
				float3 n = float3( hit( r + eps ) - hit( r - eps ),
			  							 hit( r + eps.yxz ) - hit( r - eps.yxz ),
				  					 	 hit( r + eps.zyx ) - hit( r - eps.zyx ) );
				//法線方向の取得-だと思うが原理不明

				float3 mat = float3( .5, .1, .3 );
				//オブジェクトの色?

			 	float3 light = float3( .5, .5, -2.0 );
				//ライトの位置

				float3 lightCol = float3(.6, .4, .5);
				//ライトの色

				float3 ldir = normalize( light - r );
				//r(レイのヒット地点)からライトへの方向ベクトル

				float3 diff = abs(dot( ldir, n )) * lightCol * 60.0;
				//法線方向(オブジェクトの面の向きとldirとの内積、
				//ベクトルが垂直であるほど0に近く、平行であるほど-1 or 1に近づく

				color = diff * mat;
				if(color.g > 0.9) clip(-1);
			  return float4( color, 1.0 );
			}


			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}