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" }