{ RCSid $Id: fovsample.cal,v 1.5 2019/04/09 00:52:55 greg Exp $ } { Foveated sampling based on central direction vector, magnification factor at center, and central field of view. Greg Ward April 2019 Preset constants: Cx, Cy, Cz : central view direction M : central FOV magnification factor D : field of view (full angle in degrees) Inputs: forward = 1 if forward conversion, -1 if reverse iDx, iDy, iDz = input sampling vector Outputs: oDx, oDy, oDz = output sample direction (normalized) Other variables computed: iTheta = input angle to center (radians) oTheta = output angle to center (radians) } r : PI/360 * D; { half-angle of foveal region in radians } rp : M * r; { half-angle of mapped boundary } len(x,y,z) : sqrt(x*x + y*y + z*z); sq(x) : x*x; { normalize central vector } Clen : len(Cx,Cy,Cz); nCx : Cx/Clen; nCy : Cy/Clen; nCz : Cz/Clen; { normalize input direction } iDnf = 1/len(iDx,iDy,iDz); niDx = iDx*iDnf; niDy = iDy*iDnf; niDz = iDz*iDnf; { check for degenerate case (center of fovea or opposite) } iDot = nCx*niDx + nCy*niDy + nCz*niDz; degen0 = iDot - cos(.05*PI/180); degen1 = cos(179.95*PI/180) - iDot; iTheta = acos(iDot); { quadratic function coefficients mate to linear ramp } qa : (PI - PI/M)/sq(PI - rp); qb : 1/M - 2*PI*r*(M - 1)/sq(PI - rp); qc : (PI - PI/M)/sq(PI/rp - 1); oTheta = if (forward, if(rp-iTheta, iTheta/M, qa*iTheta*iTheta + qb*iTheta + qc), if(r-iTheta, iTheta*M, (sqrt(qb*qb - 4*qa*(qc - iTheta)) - qb)/(2*qa)) ); { normalized "up" vector for rotation } Unf = 1/sqrt(1 - iDot*iDot); nUx = (nCy*niDz - nCz*niDy)*Unf; nUy = (nCz*niDx - nCx*niDz)*Unf; nUz = (nCx*niDy - nCy*niDx)*Unf; { rotate central vector by oTheta to get new output } rcos = cos(oTheta); rsin = sqrt(1 - rcos*rcos); { foveated sample direction } rDx = nCx*rcos + (nUy*nCz - nUz*nCy)*rsin; rDy = nCy*rcos + (nUz*nCx - nUx*nCz)*rsin; rDz = nCz*rcos + (nUx*nCy - nUy*nCx)*rsin; { substitute approximation in degenerate case } oDx = if(degen0, nCx+(niDx-nCx)*if(forward,1/M,M), if(degen1, niDx, rDx)); oDy = if(degen0, nCy+(niDy-nCy)*if(forward,1/M,M), if(degen1, niDy, rDy)); oDz = if(degen0, nCz+(niDz-nCz)*if(forward,1/M,M), if(degen1, niDz, rDz));