DIRECTORY G3dBasic, G3dMatrix, G3dVector, G3dView, Imager, ImagerBackdoor, Rope, ViewerClasses; G3dViewImpl: CEDAR PROGRAM IMPORTS G3dMatrix, G3dVector, Imager, ImagerBackdoor EXPORTS G3dView ~ BEGIN Error: PUBLIC SIGNAL [code: ATOM, reason: Rope.ROPE] ~ CODE; Pair: TYPE ~ G3dBasic.Pair; PairSequence: TYPE ~ G3dBasic.PairSequence; Quad: TYPE ~ G3dBasic.Quad; Triple: TYPE ~ G3dBasic.Triple; TripleSequence: TYPE ~ G3dBasic.TripleSequence; Matrix: TYPE ~ G3dMatrix.Matrix; Viewport: TYPE ~ G3dMatrix.Viewport; PairClip: TYPE ~ G3dView.PairClip; Viewer: TYPE ~ ViewerClasses.Viewer; origin: Triple ~ G3dBasic.origin; xAxis: Triple ~ G3dBasic.xAxis; yAxis: Triple ~ G3dBasic.yAxis; zAxis: Triple ~ G3dBasic.zAxis; GetViewport: PUBLIC PROC [viewer: Viewer ¬ NIL, context: Imager.Context ¬ NIL] RETURNS [v: Viewport] ~ { size: Pair; SELECT TRUE FROM viewer # NIL => size ¬ [viewer.cw, viewer.ch]; context # NIL => { b: Imager.Rectangle ¬ [0.0, 0.0, 8.5*72.0, 11.0*72.0]; b ¬ ImagerBackdoor.GetBounds[context ! Imager.Error => CONTINUE]; size ¬ [b.w, b.h]; }; ENDCASE => RETURN[[]]; v.scale ¬ v.translate ¬ [0.5*size.x, 0.5*size.y]; IF v.scale.x # 0.0 THEN v.aspectRecip ¬ v.scale.y/v.scale.x; }; TransformAndClipInZ: PUBLIC PROC [point: Triple, view: Matrix, viewport: Viewport ¬ []] RETURNS [pc: PairClip] ~ { IF G3dMatrix.HasPerspective[view] THEN { q: Quad ¬ G3dMatrix.TransformH[point, view]; pc ¬ IF q.w = 0.0 OR q.z+q.w < 0.0 THEN [G3dMatrix.TransformByViewport[[0.0, 0.0], viewport], TRUE] ELSE [G3dMatrix.TransformByViewport[[q.x/q.w, q.y/q.w], viewport], FALSE]; } ELSE pc ¬ [ G3dMatrix.TransformByViewport[G3dMatrix.TransformD[point, view], viewport], FALSE]; }; PairsFromTriples: PUBLIC PROC [ triples: TripleSequence, view: Matrix, pairs: PairSequence ¬ NIL] RETURNS [PairSequence] ~ { IF triples = NIL THEN RETURN[NIL]; IF pairs = NIL OR pairs.maxLength < triples.length THEN pairs ¬ NEW[G3dBasic.PairSequenceRep[triples.length]]; FOR n: NAT IN [0..pairs.length ¬ triples.length) DO pairs[n] ¬ G3dMatrix.TransformD[triples[n], view]; ENDLOOP; RETURN[pairs]; }; TransformByViewport: PUBLIC PROC [viewer: Viewer, in: Matrix, out: Matrix ¬ NIL] RETURNS [Matrix] ~ { vp: Viewport ¬ GetViewport[viewer]; 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] ~ { out ¬ G3dMatrix.Identity[out]; IF worIncr # NIL THEN [] ¬ G3dMatrix.Mul[out, worIncr, out]; [] ¬ G3dMatrix.Rotate[out, xAxis, rotate.x,,, out]; [] ¬ G3dMatrix.Rotate[out, yAxis, rotate.y,,, out]; [] ¬ G3dMatrix.Rotate[out, zAxis, rotate.z,,, out]; [] ¬ G3dMatrix.Scale[out, scale, out]; [] ¬ G3dMatrix.Translate[out, move, out]; IF swapYZ THEN FOR n: NAT IN [0..4) DO temp: REAL ¬ out[n][1]; out[n][1] ¬ out[n][2]; out[n][2] ¬ temp; ENDLOOP; 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]; }; 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[]; 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 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]; }; END.. WorldToViewFromVectors: PUBLIC PROC [ eyePoint: Triple ¬ origin, lookAt: Triple ¬ zAxis, upDirection: Triple ¬ yAxis, fieldOfView: REAL ¬ 40.0, out: Matrix ¬ NIL] RETURNS [Matrix] ~ { out ¬ G3dMatrix.Identity[out]; out ¬ G3dMatrix.Translate[out, G3dVector.Negate[eyePoint], out]; IF lookAt.x = 0.0 AND lookAt.z = 0.0 THEN out ¬ G3dMatrix.Rotate[out, xAxis, 90.0,,, out] ELSE { transformedY: Triple; phi, theta, gamma: REAL ¬ 0.0; xz: Triple ¬ G3dVector.Unit[[lookAt.x, 0.0, lookAt.z]]; lookAt ¬ G3dVector.Unit[lookAt]; upDirection ¬ G3dVector.Unit[upDirection]; phi ¬ G2dBasic.ArcCos[xz.z]; theta ¬ G2dBasic.ArcCos[G3dVector.Dot[xz, lookAt]]; out ¬ G3dMatrix.Rotate[out, xAxis, phi, FALSE,, out]; out ¬ G3dMatrix.Rotate[out, yAxis, theta, FALSE,, out]; transformedY ¬ G3dMatrix.TransformVec[yAxis, out]; gamma ¬ G2dBasic.ArcCos[G3dVector.Dot[upDirection, transformedY]]; out ¬ G3dMatrix.Rotate[out, zAxis, gamma,,, out]; }; out ¬ G3dMatrix.Translate[out, eyePoint, 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]; }; FromEyeLookUp: PUBLIC PROC [eyePoint, lookAt, upDirection: Triple, fieldOfView: REAL] RETURNS [moves, rotates: Triple] ~ { m: Matrix ¬ G3dMatrix.ObtainMatrix[]; eyeToWorld: Matrix ¬ WorldToViewFromVectors[eyePoint, lookAt, upDirection, fieldOfView, m]; temp: Triple ¬ rotates ¬ G3dMatrix.ExtractRotate[eyeToWorld]; worldToEye: Matrix ¬ G3dMatrix.Invert[eyeToWorld, m]; moves ¬ G3dMatrix.Transform[eyePoint, worldToEye]; G3dMatrix.ReleaseMatrix[m]; }; B G3dViewImpl.mesa Copyright Σ 1988, 1992 by Xerox Corporation. All rights reserved. Bloomenthal, April 6, 1993 11:30 pm PDT Ken Shoemake, August 30, 1989 8:21:04 pm PDT Errors, Types, and Constants viewer # NIL => size ¬ [viewer.ww-viewer.wx, viewer.wh-viewer.wy]; Transformation Transformation Procedures Translate and scale to viewport; don't scale z so can compare z with w for far clipping: 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. At this point we're in WORLD SPACE 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: qAbs: Quaternion_G3dQuaternion.FromXYZAngles[rotate.x*deg,rotate.y*deg,rotate.z*deg]; deg: REAL ~ 3.1415926535/180.0; out _ G3dQuaternion.ToMatrix[qAbs, out]; Go from right-handed world space to left-handed view space (swap y and z): At this point we're in EYE SPACE At this point we're in VIEW SPACE PrintMatrix: PROC [name: Rope.ROPE, matrix: Matrix] ~ { IF name # NIL THEN TerminalIO.PutF["%g\n", IO.rope[name]]; FOR i: NAT IN [0..3] DO TerminalIO.PutF["%6.3f\t%6.3f\t%6.3f\t%6.3f\n", IO.real[matrix[i][0]], IO.real[matrix[i][1]], IO.real[matrix[i][2]], IO.real[matrix[i][3]]]; ENDLOOP; TerminalIO.PutF["\n"]; }; 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. Go from left-handed view space to right-handed world space (swap y and z): Discarded code: Should we exchange y and z axes here (to go from right to left-handedness)? Alternatively, use G3dMatrix.MakeFromTriad: Κ ~–"cedarcode" style•NewlineDelimiter ™™Jšœ Οeœ6™BJ™'J™,J˜JšΟk œV˜_J˜—–0.320 0.931 0.362 textColoršΠbl œΠbkΟb ˜Jšžœ-˜4Jšžœ˜J˜—Jšœž˜head–0.0 24 .div 1 1 textColoršΟl™• CharProps&Postfix0.0 24 .div 1 1 textColor;š ‘œžžœžœžœžœžœ˜@J˜—J–'Postfix16.0 24 .div 1 1 textColorš‘œžœ˜J–' Postfix16.0 24 .div 1 1 textColor š‘ œžœ˜,J–'Postfix16.0 24 .div 1 1 textColorš‘œžœ˜J–'Postfix16.0 24 .div 1 1 textColorš‘œžœ˜"J–'Postfix16.0 24 .div 1 1 textColor!š‘œžœ˜/J–'Postfix16.0 24 .div 1 1 textColorš‘œžœ˜#J–'Postfix16.0 24 .div 1 1 textColorš‘œžœ˜&J–'Postfix16.0 24 .div 1 1 textColorš‘œžœ˜$–'Postfix16.0 24 .div 1 1 textColor!š‘œžœ˜'J˜—J–'Postfix16.0 24 .div 1 1 textColorš‘œ˜$J–'Postfix16.0 24 .div 1 1 textColorš‘œ˜"J–'Postfix16.0 24 .div 1 1 textColorš‘œ˜"–'Postfix16.0 24 .div 1 1 textColorš‘œ˜"J˜—–( Postfix0.320 0.931 0.362 textColorCš Οn œžœžœžœžœ˜NJšžœ˜Jšœ˜Jšœ ˜ šžœžœž˜Jšœ žœ"˜.Jšœ žœ6™Bšœ žœ˜J˜6Jšœ7žœ˜AJ˜J˜—J–) Postfix16.0 24 .div 1 1 textColoršžœ œ˜—J˜1Jšžœžœ%˜