TransformByViewport:
PUBLIC
PROC [viewer: Viewer, in: Matrix, out: Matrix ¬
NIL]
RETURNS [Matrix]
~ {
vp: Viewport ¬ GetViewport[viewer];
Translate and scale to viewport; don't scale z so can compare z with w for far clipping:
out ¬ G3dMatrix.DiffScale[in, [vp.scale.x, vp.scale.y, 1.0], out];
out ¬ G3dMatrix.Translate[out, [vp.translate.x, vp.translate.y, 0.0], out];
RETURN[out];
};
MakeCameraMatrix:
PUBLIC PROC [
worIncr: Matrix ¬ NIL,
scale: REAL ¬ 1.0,
move: Triple ¬ [0.0, 0.0, 0.0],
rotate: Triple ¬ [0.0, 0.0, 0.0],
eyeIncr: Matrix ¬ NIL,
fieldOfView: REAL ¬ 0.0,
swapYZ: BOOL ¬ TRUE,
out: Matrix ¬ NIL]
RETURNS [Matrix]
~ {
The canonical transformation sequence for cameras is:
(world) WiSTRXEi (eye) P (view) V (screen)
where S=scale, T=translate, R=RxRyRz=rotate around x, y, and z axes, X=swap y and z, P=perspective, V=view transform (a scale and translate), and the coordinate systems in parentheses are labels, not terms in the matrix product.
World space is right-handed, generally having x=right, y=away, z=up,
Eye and view spaces are left-handed with x=right, y=up, z=away.
(Screen space is typically x=right, y=up, z=away, but that's not really our concern here.)
View and Screen space are typically perspective spaces, but the others are orthogonal.
See the G3dControl Camera Model notes by Paul Heckbert.
out ¬ G3dMatrix.Identity[out];
At this point we're in WORLD SPACE
IF worIncr # NIL THEN [] ¬ G3dMatrix.Mul[out, worIncr, out];
Previously:
[] ← G3dMatrix.Scale[out, scale, out];
[] ← G3dMatrix.Translate[out, move, out];
[] ← G3dMatrix.Rotate[out, xAxis, rotate.x,,, out];
[] ← G3dMatrix.Rotate[out, yAxis, rotate.y,,, out];
[] ← G3dMatrix.Rotate[out, zAxis, rotate.z,,, out];
Try order used in G3dArcBallImpl:
[] ¬ G3dMatrix.Rotate[out, xAxis, rotate.x,,, out];
[] ¬ G3dMatrix.Rotate[out, yAxis, rotate.y,,, out];
[] ¬ G3dMatrix.Rotate[out, zAxis, rotate.z,,, out];
qAbs: Quaternion←G3dQuaternion.FromXYZAngles[rotate.x*deg,rotate.y*deg,rotate.z*deg];
deg: REAL ~ 3.1415926535/180.0;
out ← G3dQuaternion.ToMatrix[qAbs, out];
[] ¬ G3dMatrix.Scale[out, scale, out];
[] ¬ G3dMatrix.Translate[out, move, out];
IF swapYZ
THEN
FOR n:
NAT
IN [0..4)
DO
Go from right-handed world space to left-handed view space (swap y and z):
temp: REAL ¬ out[n][1];
out[n][1] ¬ out[n][2];
out[n][2] ¬ temp;
ENDLOOP;
At this point we're in EYE SPACE
IF eyeIncr # NIL THEN [] ¬ G3dMatrix.Mul[out, eyeIncr, out];
IF fieldOfView # 0.0
THEN {
t: Matrix ¬ G3dMatrix.ObtainMatrix[];
[] ¬ G3dMatrix.Mul[out, G3dMatrix.MakePerspective[--1e4-- 10., 0., fieldOfView, t], out];
G3dMatrix.ReleaseMatrix[t];
};
At this point we're in VIEW SPACE
RETURN[out];
};
WorldToViewFromVectors:
PUBLIC PROC [
eyePoint: Triple ¬ origin,
lookAt: Triple ¬ zAxis,
upDirection: Triple ¬ yAxis,
fieldOfView: REAL ¬ 40.0,
out: Matrix ¬ NIL]
RETURNS [Matrix]
~ {
in: Triple ¬ G3dVector.Unit[G3dVector.Sub[lookAt, eyePoint]];
right: Triple ¬ G3dVector.Unit[G3dVector.Cross[in, G3dVector.Unit[upDirection]]];
up: Triple ¬ G3dVector.Unit[G3dVector.Cross[right, in]];
IF G3dVector.Null[right] THEN {right ¬ [1.0, 0.0, 0.0]; up ¬ [0.0, -in.z, in.y];};
out ¬ G3dMatrix.MakeFromTriad[right, up, in, eyePoint, FALSE, out];
IF fieldOfView # 0.0
THEN {
t: Matrix ¬ G3dMatrix.ObtainMatrix[];
out ¬ G3dMatrix.Mul[out, G3dMatrix.MakePerspective[--1e4-- 10., 0, fieldOfView, t], out];
G3dMatrix.ReleaseMatrix[t];
};
RETURN[out];
};
FromScaleMovesRots:
PUBLIC
PROC [scale:
REAL, moves, rotates: Triple]
RETURNS [eyePoint, lookAt, upDirection: Triple]
~ {
m: Matrix ¬ G3dMatrix.ObtainMatrix[];
Formerly: right handed: x-axis to right, y into screen, z up;
Presently: right handed: x-axis to right, y up, z out of screen.
worldToEye: Matrix ¬ MakeCameraMatrix[, scale, moves, rotates,, 0.0, FALSE, m]; -- no persp
eyeToWorld: Matrix ¬ G3dMatrix.Invert[worldToEye, m];
upDirection ¬ G3dMatrix.TransformVec[[0., 1., 0.], eyeToWorld]; -- no differential scaling
eyePoint ¬ G3dMatrix.Transform[[0., 0., 0.], eyeToWorld];
lookAt ¬ G3dVector.Sub[G3dMatrix.Transform[[0., 0., 1.], eyeToWorld], eyePoint];
G3dMatrix.ReleaseMatrix[m];
};
FromEyeLookUp:
PUBLIC
PROC [eyePoint, lookAt, upDirection: Triple, fieldOfView:
REAL]
RETURNS [moves, rotates: Triple]
~ {
m: Matrix ¬ G3dMatrix.ObtainMatrix[];
worldToEye: Matrix ¬ G3dMatrix.Transpose[
WorldToViewFromVectors[eyePoint, G3dVector.Add[eyePoint, lookAt], upDirection, 0.0, m], m];
FOR n:
NAT
IN [0..4)
DO
Go from left-handed view space to right-handed world space (swap y and z):
temp: REAL ¬ worldToEye[n][1];
worldToEye[n][1] ¬ worldToEye[n][2];
worldToEye[n][2] ¬ temp;
ENDLOOP;
rotates ¬ G3dMatrix.ExtractRotate[worldToEye];
moves ¬ G3dVector.Negate[eyePoint];
G3dMatrix.ReleaseMatrix[m];
};