--shader(GLSL)の小技 10-- raymarchingでmod()を使わないで大量モデル描写
raymarchingでmod()を使わないで大量モデル描写する。TDFのデモで使った手法だけど、誰もとってくれないので、自分で解説する事にしました。
一個一個をバウンディングして範囲に入っていたら、z値を比較し、手前なら描写という手法。GPUによるがGeForce GTX 960で,500個くらいなら問題無く動いてます。
説明はソースの方に書いておいたので、そちらを見てください。
この手法のポイントは
if(length(cross(rd,q-ro))<1.0)
これです。length(cross(v,p-a))
は、a点を通る単位ベクトルvの直線の距離関数になります。
ベクトルがrdで通過点がroならば、映像的には円になります。実際にはシリンダーですが、機能的にはバインディング球になる感じです。
今回のshader (shadertoy rule)
// https://www.shadertoy.com/view/4lXyWN vec3 hash(uint i) { uvec3 x = uvec3(123,456,789)*(i+55u); uint k = 1103515245U; x*=k; x = ((x>>2u)^(x.yzx>>1u)^x.zxy)*k; return vec3(x)*(1.0/float(~0U)); } float deBox(vec3 p) { return length(max(abs(p)-vec3(0.5),0.0)); } float map(vec3 p) { return deBox(p); } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv=(fragCoord*2.0-iResolution.xy)/iResolution.y; vec3 ro=vec3(0,0,-20); vec3 rd=normalize(vec3(uv,2)); vec3 col=vec3(0); float z=99.0; for(uint j=1u;j<200u;j++){ // オブジェクトの座標を取得 // 乱数でベクトルを取得し時間を乗算 vec3 q=(hash(j)*2.0-1.0) *(iTime+20.0)*0.2; // この式で-1~1の間を行き来する // イメージで言えば3Dビリヤード q = (abs(fract(q)*2.0-1.0)*2.0-1.0)*15.0; // 座標からmaymarchingをするか決定する。 if(length(cross(rd,q-ro))<1.0) { float d,i,t=0.0; vec3 p=ro; for(i=1.0;i>0.0;i-=1./50.0) { t+=d=map(p-q); if(d<0.001) { // 視点と座標の距離を取得 float s = dot(rd,p-ro); // z値を比べて描写するか決定 if(s<z) { col=vec3(1); col*=i*i; col*=exp(-t*t*0.001); z=s; } break; } p+=rd*d; } } } fragColor=vec4(col,1.0); }