1 |
{ RCSid $Id: fovsample.cal,v 1.4 2019/04/07 15:38:35 greg Exp $ } |
2 |
{ |
3 |
Foveated sampling based on central direction vector, |
4 |
magnification factor at center, and central field of view. |
5 |
|
6 |
Greg Ward April 2019 |
7 |
|
8 |
Preset constants: |
9 |
Cx, Cy, Cz : central view direction |
10 |
M : central FOV magnification factor |
11 |
D : field of view (full angle in degrees) |
12 |
|
13 |
Inputs: |
14 |
forward = 1 if forward conversion, -1 if reverse |
15 |
iDx, iDy, iDz = input sampling vector |
16 |
|
17 |
Outputs: |
18 |
oDx, oDy, oDz = output sample direction (normalized) |
19 |
|
20 |
Other variables computed: |
21 |
iTheta = input angle to center (radians) |
22 |
oTheta = output angle to center (radians) |
23 |
} |
24 |
|
25 |
r : PI/360 * D; { half-angle of foveal region in radians } |
26 |
rp : M * r; { half-angle of mapped boundary } |
27 |
|
28 |
len(x,y,z) : sqrt(x*x + y*y + z*z); |
29 |
sq(x) : x*x; |
30 |
{ normalize central vector } |
31 |
Clen : len(Cx,Cy,Cz); |
32 |
nCx : Cx/Clen; |
33 |
nCy : Cy/Clen; |
34 |
nCz : Cz/Clen; |
35 |
{ normalize input direction } |
36 |
iDnf = 1/len(iDx,iDy,iDz); |
37 |
niDx = iDx*iDnf; |
38 |
niDy = iDy*iDnf; |
39 |
niDz = iDz*iDnf; |
40 |
{ check for degenerate case (center of fovea or opposite) } |
41 |
iDot = nCx*niDx + nCy*niDy + nCz*niDz; |
42 |
degen0 = iDot - cos(.05*PI/180); |
43 |
degen1 = cos(179.95*PI/180) - iDot; |
44 |
|
45 |
iTheta = acos(iDot); |
46 |
{ quadratic function coefficients mate to linear ramp } |
47 |
qa : (PI - PI/M)/sq(PI - rp); |
48 |
qb : 1/M - 2*PI*r*(M - 1)/sq(PI - rp); |
49 |
qc : (PI - PI/M)/sq(PI/rp - 1); |
50 |
|
51 |
oTheta = if (forward, |
52 |
if(rp-iTheta, iTheta/M, qa*iTheta*iTheta + qb*iTheta + qc), |
53 |
if(r-iTheta, iTheta*M, (sqrt(qb*qb - 4*qa*(qc - iTheta)) - qb)/(2*qa)) |
54 |
); |
55 |
{ normalized "up" vector for rotation } |
56 |
Unf = 1/sqrt(1 - iDot*iDot); |
57 |
nUx = (nCy*niDz - nCz*niDy)*Unf; |
58 |
nUy = (nCz*niDx - nCx*niDz)*Unf; |
59 |
nUz = (nCx*niDy - nCy*niDx)*Unf; |
60 |
{ rotate central vector by oTheta to get new output } |
61 |
rcos = cos(oTheta); |
62 |
rsin = sqrt(1 - rcos*rcos); |
63 |
{ foveated sample direction } |
64 |
rDx = nCx*rcos + (nUy*nCz - nUz*nCy)*rsin; |
65 |
rDy = nCy*rcos + (nUz*nCx - nUx*nCz)*rsin; |
66 |
rDz = nCz*rcos + (nUx*nCy - nUy*nCx)*rsin; |
67 |
{ substitute approximation in degenerate case } |
68 |
oDx = if(degen0, nCx+(niDx-nCx)*if(forward,1/M,M), if(degen1, niDx, rDx)); |
69 |
oDy = if(degen0, nCy+(niDy-nCy)*if(forward,1/M,M), if(degen1, niDy, rDy)); |
70 |
oDz = if(degen0, nCz+(niDz-nCz)*if(forward,1/M,M), if(degen1, niDz, rDz)); |