website articles
box functions

Intro

A sphere are simple geometry shape described by a simple equation and therefore it accepts analytic solutions to many problems involving projections, occlusion, shadows, motion blur, etc. Similary, boxes are simple shapes that also accept closed form expresions for many such problems. This page collects some of those that I have collected (more often than not, derived myself).

Functions

 Box Intersection ```// Calcs intersection and exit distances, and normal at intersection // // The box is axis aligned and at the origin, but has any size. // For arbirarily oriented and located boxes, simply transform // the ray accordingly and reverse the transformation for the // returning normal(without translation) // vec2 boxIntersection( vec3 ro, vec3 rd, vec3 boxSize, out vec3 outNormal ) { vec3 m = 1.0/rd; vec3 n = m*ro; vec3 k = abs(m)*boxSize; vec3 t1 = -n - k; vec3 t2 = -n + k; float tN = max( max( t1.x, t1.y ), t1.z ); float tF = min( min( t2.x, t2.y ), t2.z ); if( tN > tF || tF < 0.0) return vec2(-1.0); // no intersection outNormal = -sign(rdd)*step(t1.yzx,t1.xyz)*step(t1.zxy,t1.xyz); return vec2( tN, tF ); }``` Example / Code Box Density ```float boxDensity( vec3 wro, vec3 wrd, // ray origin and direction mat4 boxTx, vec3 boxSize, // box rot+pos, and size float dbuffer ) { vec3 d = (boxTx*vec4(wrd,0.0)).xyz; vec3 o = (boxTx*vec4(wro,1.0)).xyz; // ray-box intersection in box space vec3 m = 1.0/d; vec3 n = m*o; vec3 k = abs(m)*boxSize; vec3 ta = -n - k; vec3 tb = -n + k; float tN = max( max( ta.x, ta.y ), ta.z ); float tF = min( min( tb.x, tb.y ), tb.z ); if( tN > tF || tF < 0.0) return 0.0; // not visible (behind camera or behind dbuffer) if( tF<0.0 || tN>dbuffer ) return 0.0; // clip integration segment from camera to dbuffer tN = max( tN, 0.0 ); tF = min( tF, dbuffer ); // move ray to the intersection point o += tN*d; tF=tF-tN; tN=0.0; // density d(x,y,z) = [1-(x/rx)^2]*[1-(y/ry)^2]*[1-(z/rz)^2] // is analytically integrable: float ir2 = 1.0/(boxSize*boxSize); vec3 a = 1.0 - (o*o)*ir2; vec3 b = - 2.0*(o*d)*ir2; vec3 c = - (d*d)*ir2; float t1 = tF; float t2 = t1*t1; float t3 = t2*t1; float t4 = t2*t2; float t5 = t2*t3; float t6 = t3*t3; float t7 = t3*t4; return (t1/1.0)*(a.x*a.y*a.z) + (t2/2.0)*(a.x*a.y*b.z + a.x*b.y*a.z + b.x*a.y*a.z) + (t3/3.0)*(a.x*a.y*c.z + a.x*b.y*b.z + a.x*c.y*a.z + b.x*a.y*b.z + b.x*b.y*a.z + c.x*a.y*a.z) + (t4/4.0)*(a.x*b.y*c.z + a.x*c.y*b.z + b.x*a.y*c.z + b.x*b.y*b.z + b.x*c.y*a.z + c.x*a.y*b.z + c.x*b.y*a.z) + (t5/5.0)*(a.x*c.y*c.z + b.x*b.y*c.z + b.x*c.y*b.z + c.x*a.y*c.z + c.x*b.y*b.z + c.x*c.y*a.z) + (t6/6.0)*(b.x*c.y*c.z + c.x*b.y*c.z + c.x*c.y*b.z) + (t7/7.0)*(c.x*c.y*c.z); }``` Example / Code Box Ambient Occlusion ```float boxOcclusion( vec3 pos, vec3 nor, mat4 boxTx, // box rotation+position vec3 boxSize ) // box size { vec3 p = (boxTx*vec4(pos,1.0)).xyz; vec3 n = (boxTx*vec4(nor,0.0)).xyz; // 8 verts vec3 v0 = normalize( vec3(-1.0,-1.0,-1.0)*boxSize - p); vec3 v1 = normalize( vec3( 1.0,-1.0,-1.0)*boxSize - p); vec3 v2 = normalize( vec3(-1.0, 1.0,-1.0)*boxSize - p); vec3 v3 = normalize( vec3( 1.0, 1.0,-1.0)*boxSize - p); vec3 v4 = normalize( vec3(-1.0,-1.0, 1.0)*boxSize - p); vec3 v5 = normalize( vec3( 1.0,-1.0, 1.0)*boxSize - p); vec3 v6 = normalize( vec3(-1.0, 1.0, 1.0)*boxSize - p); vec3 v7 = normalize( vec3( 1.0, 1.0, 1.0)*boxSize - p); // 12 edges float k02 = dot(n,normalize(cross(v2,v0)))*acos(dot(v0,v2)); float k23 = dot(n,normalize(cross(v3,v2)))*acos(dot(v2,v3)); float k31 = dot(n,normalize(cross(v1,v3)))*acos(dot(v3,v1)); float k10 = dot(n,normalize(cross(v0,v1)))*acos(dot(v1,v0)); float k45 = dot(n,normalize(cross(v5,v4)))*acos(dot(v4,v5)); float k57 = dot(n,normalize(cross(v7,v5)))*acos(dot(v5,v7)); float k76 = dot(n,normalize(cross(v6,v7)))*acos(dot(v7,v6)); float k37 = dot(n,normalize(cross(v7,v3)))*acos(dot(v3,v7)); float k64 = dot(n,normalize(cross(v4,v6)))*acos(dot(v6,v4)); float k51 = dot(n,normalize(cross(v1,v5)))*acos(dot(v5,v1)); float k04 = dot(n,normalize(cross(v4,v0)))*acos(dot(v0,v4)); float k62 = dot(n,normalize(cross(v2,v6)))*acos(dot(v6,v2)); // 6 faces float occ = 0.0; occ += ( k02 + k23 + k31 + k10) * step( 0.0, v0.z ); occ += ( k45 + k57 + k76 + k64) * step( 0.0, -v4.z ); occ += ( k51 - k31 + k37 - k57) * step( 0.0, -v5.x ); occ += ( k04 - k64 + k62 - k02) * step( 0.0, v0.x ); occ += (-k76 - k37 - k23 - k62) * step( 0.0, -v6.y ); occ += (-k10 - k51 - k45 - k04) * step( 0.0, v0.y ); return occ / 6.283185; }``` This code will work only when the box is fully visible from the shading point.For boxes that are partially below the visibility horizon, use this code that doesclipping in the polygons instead: https://www.shadertoy.com/view/4sSXDV Maths / Article Example / Code