1 // Copyright (c) 1999-2012 OPEN CASCADE SAS
3 // The content of this file is subject to the Open CASCADE Technology Public
4 // License Version 6.5 (the "License"). You may not use the content of this file
5 // except in compliance with the License. Please obtain a copy of the License
6 // at http://www.opencascade.org and read it completely before using this file.
8 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
9 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11 // The Original Code and all software distributed under the License is
12 // distributed on an "AS IS" basis, without warranty of any kind, and the
13 // Initial Developer hereby disclaims all such warranties, including without
14 // limitation, any warranties of merchantability, fitness for a particular
15 // purpose or non-infringement. Please see the License for the specific terms
16 // and conditions governing the rights and limitations under the License.
18 /***********************************************************************
22 File OpenGl_telem_view :
24 ************************************************************************/
26 #include <OpenGl_GlCore11.hxx>
27 #include <OpenGl_telem_view.hxx>
28 #include <OpenGl_telem_util.hxx>
29 #include <OpenGl_Display.hxx>
32 EvalViewMappingMatrix (const Handle(OpenGl_Display)& theGlDisplay,
33 tel_view_mapping mapping /* View Mapping */,
34 Tint* error_ind /* Out: Error Indicator */,
35 Tmatrix3 mat /* Out: Mapping Matrix * */,
40 Tlimit3* /*clip_limit*/
43 Tfloat gx, gy, xsf, ysf, zsf;
47 Tfloat n, f, r, l, t, b, Zprp, dx, dy, VPD;
51 Tlimit3 vp = { ( float )-1.0, ( float )1.0, ( float )-1.0, ( float )1.0, ( float )1.0, ( float )-1.0 };
52 Tmatrix3 pmat = { { ( float )1.0, ( float )0.0, ( float )0.0, ( float )0.0 },
53 { ( float )0.0, ( float )1.0, ( float )0.0, ( float )0.0 },
54 { ( float )0.0, ( float )0.0, ( float )1.0, ( float )0.0 },
55 { ( float )0.0, ( float )0.0, ( float )0.0, ( float )1.0 } };
56 Tmatrix3 mmat = { { ( float )1.0, ( float )0.0, ( float )0.0, ( float )0.0 },
57 { ( float )0.0, ( float )1.0, ( float )0.0, ( float )0.0 },
58 { ( float )0.0, ( float )0.0, ( float )1.0, ( float )0.0 },
59 { ( float )0.0, ( float )0.0, ( float )0.0, ( float )1.0 } };
65 if( mapping->window.xmin >= mapping->window.xmax ||
66 mapping->window.ymin >= mapping->window.ymax )
72 /* invalid viewport */
73 if( mapping->viewport.xmin >= mapping->viewport.xmax ||
74 mapping->viewport.ymin >= mapping->viewport.ymax ||
75 mapping->viewport.zmin >= mapping->viewport.zmax )
81 /* invalid back/front plane distances */
82 if( mapping->bpd >= mapping->fpd )
88 /* prp between front and back planes */
89 if (theGlDisplay.IsNull() || !theGlDisplay->Walkthrough())
91 if( mapping->prp[2] < mapping->fpd &&
92 mapping->prp[2] > mapping->bpd )
99 if( mapping->prp[2] == mapping->vpd )
101 *error_ind = 5; /* prp on view plane */
105 if( mapping->viewport.xmin < 0 ||
106 mapping->viewport.xmax > 1 ||
107 mapping->viewport.ymin < 0 ||
108 mapping->viewport.ymax > 1 ||
109 mapping->viewport.zmin < 0 ||
110 mapping->viewport.zmax > 1 )
112 *error_ind = 6; /* viewport limits outside NPC space */
118 /* OCC18942: Moved here while debugging perspective projection matrix */
122 cx = mapping->window.xmin + mapping->window.xmax, cx /= ( float )2.0;
123 cy = mapping->window.ymin + mapping->window.ymax, cy /= ( float )2.0;
126 gx = (cx - mapping->prp[0]) / (mapping->vpd - mapping->prp[2]);
127 gy = (cy - mapping->prp[1]) / (mapping->vpd - mapping->prp[2]);
130 printf("EvalViewMappingMatrix \n");
131 printf("prp %f %f %f \n", mapping->prp[0], mapping->prp[1], mapping->prp[2]);
132 printf("vpd fpd bpd %f %f %f \n", mapping->vpd, mapping->fpd, mapping->bpd);
133 printf("window limit %f %f %f %f\n", mapping->window.xmin, mapping->window.xmax,
134 mapping->window.ymin, mapping->window.ymax);
135 printf("viewport limit %f %f %f %f\n", mapping->viewport.xmin, mapping->viewport.xmax,
136 mapping->viewport.ymin, mapping->viewport.ymax);
139 /* projection matrix */
140 if( mapping->proj == TelParallel )
143 pmat[2][0] = -gx; pmat[3][0] = mapping->vpd*gx;
144 pmat[2][1] = -gy; pmat[3][1] = mapping->vpd*gy;
146 else if (!theGlDisplay.IsNull() && !theGlDisplay->SymPerspective())/* TelPerspective */
148 pmat[0][0] = pmat[1][1] = mapping->prp[2] - mapping->vpd;
151 pmat[2][3] = ( float )-1.0;
152 pmat[3][0] = mapping->vpd * gx;
153 pmat[3][1] = mapping->vpd * gy;
154 pmat[3][3] = mapping->prp[2];
156 /* modify the next two cells to change clipping policy */
157 if (!theGlDisplay.IsNull() && !theGlDisplay->Walkthrough())
159 pmat[2][2] = mapping->prp[2] - ( fpd + bpd );
160 pmat[3][2] = fpd * bpd;
163 /* OCC18942: New approach to calculation of mapping (projection) matrix */
166 dx = mapping->window.xmax - mapping->window.xmin;
167 dy = mapping->window.ymax - mapping->window.ymin;
168 Zprp = mapping->prp[2];
169 VPD = Zprp - mapping->vpd;
172 Calculate canonical perspective projection parameters as if we were about
173 to use glFrustum() to create symmetric perspective frustum.
175 After the view orientation matrix is applied, the coordinate system origin is located
176 at the VRP and oriented properly. However, the viewplane has width = dx and height = dy
177 and its center (cx, cy, VPD) is not always located at the view Z axis.
178 The canonical perspective projection matrix assumes the eye is located at (0, 0, 0).
179 Thus the old approach resulted in a non-symmetric perspective,
180 as X and Y coordinates of the projection reference point (PRP) were not updated
181 when cx and cy changed. Moreover, such "static" perspective had some other disadvantages,
182 such as non-realistic panning, i.e. instead of moving the eye (or camera) over the model
183 a sort of "frame" moved over the static perspective projection picture,
184 exposing a part of this static picture to the user.
186 In order to make the perspective symmetric, we need to translate
187 the coordinate system to PRP before projection.
188 Thus we translate X, Y and Z co-ordinates by -cx, -cy and -Zprp respectively.
190 NOTE: mat[i][j] means j-th element of i-th column, as OpenGL accepts the matrices
191 in column-major order, while in C two-dimensional arrays are stored in memory
194 VPD is used below instead of near clipping plane dispance (n) in order to simplify
195 calculation of l and r values. If we did not use VPD in the matrix calculation, we would have to
196 project 0.5 * dx, -0.5 * dx, 0.5 * dy and - 0.5 * dy onto the near clipping plane
197 to calculate these values.
200 1. It is still necessary to find a way to calculate the perspective projection matrix
201 for TPM_WALKTHROUGH projection model. This projection model is not supported yet
208 n = Zprp - fpd; f = Zprp - bpd;
210 mat[0][0] = 2.f * VPD / (r - l);
211 mat[1][1] = 2.f * VPD / (t - b);
212 mat[2][0] = (r + l) / (r - l);
213 mat[2][1] = (t + b) / (t - b);
214 mat[2][2] = - (f + n) / (f - n);
217 The last column takes into account translation along X, Y and Z axis
218 before projecting. This can be considered as a result of right-multiplying the canonical
219 perspective projection matrix P by a translation matrix T
220 (it differs form the canonical matrix by the last column only):
223 mat = P * T, where T = | 0 0 1 -Zprp |
226 mat[3][0] = -mat[2][0] * Zprp - mat[0][0] * cx;
227 mat[3][1] = -mat[2][1] * Zprp - mat[1][1] * cy;
228 mat[3][2] = -2.f * f * n / (f - n) - mat[2][2] * Zprp;
232 printf("r l t b n f: %f %f %f %f %f %f \n", r,l,t,b,n,f);
233 printf( "mapping_matrix (new code):\n" );
237 /* return here, as further calculations are related to the old approach */
242 xsf = (vp.xmax - vp.xmin) / (mapping->window.xmax - mapping->window.xmin);
243 ysf = (vp.ymax - vp.ymin) / (mapping->window.ymax - mapping->window.ymin);
244 zsf = (vp.zmax - vp.zmin) / (fpd - bpd);
247 mmat[0][0] = xsf, mmat[1][1] = ysf, mmat[2][2] = zsf;
248 mmat[3][0] = vp.xmin - xsf*mapping->window.xmin;
249 mmat[3][1] = vp.ymin - ysf*mapping->window.ymin;
250 mmat[3][2] = vp.zmin - zsf*bpd;
252 /* multiply to obtain mapping matrix */
253 TelMultiplymat3( mat, pmat, mmat );
256 printf( "mapping_matrix :\n" );
262 TelEvalViewOrientationMatrix( Tfloat *vrp /* View Reference Point */,
263 Tfloat *vpn /* View Plane Normal */,
264 Tfloat *vup /* View Up Vector */,
265 Tfloat *asf /* Axial Scale Factors */,
266 Tint *error_ind/* Out: Error indicator */,
267 Tmatrix3 rmat /* Out: Orientation Matrix */
270 Tfloat u[3], v[3], n[3], f;
272 /* view plane normal of zero length */
273 if( vecmag(vpn) == 0.0 )
279 /* view up vector of zero length */
280 if( vecmag(vup) == 0.0 )
286 /* view up vector parallel to view plane normal */
300 veccrs(u,v,n); /* up vector cross plane normal gives U axis */
303 veccrs(v,n,u); /* plane normal cross U axis gives modified up vector */
304 vecnrm(v); /* redundant ? */
306 /* rotate to align along u, v, n */
307 rmat[0][0] = ( float )u[0] * asf[0],
308 rmat[0][1] = ( float )v[0] * asf[0],
309 rmat[0][2] = ( float )n[0] * asf[0],
310 rmat[0][3] = ( float )0.0;
312 rmat[1][0] = ( float )u[1] * asf[1],
313 rmat[1][1] = ( float )v[1] * asf[1],
314 rmat[1][2] = ( float )n[1] * asf[1],
315 rmat[1][3] = ( float )0.0;
317 rmat[2][0] = ( float )u[2] * asf[2],
318 rmat[2][1] = ( float )v[2] * asf[2],
319 rmat[2][2] = ( float )n[2] * asf[2],
320 rmat[2][3] = ( float )0.0;
322 /* translate to centre at vrp */
324 rmat[3][0] = - ( float ) (u[0]*vrp[0] + u[1]*vrp[1] + u[2]*vrp[2]);
325 rmat[3][1] = - ( float ) (v[0]*vrp[0] + v[1]*vrp[1] + v[2]*vrp[2]);
326 rmat[3][2] = - ( float ) (n[0]*vrp[0] + n[1]*vrp[1] + n[2]*vrp[2]);
327 rmat[3][3] = ( float )1.0;
330 printf("TelEvalViewOrientationMatrix \n");
331 printf("view_ref_pt %f %f %f \n", vrp[0], vrp[1], vrp[2]);
332 printf("view_up_vec %f %f %f \n", vup[0], vup[1], vup[2]);
333 printf("view_plane_normal %f %f %f \n", vpn[0], vpn[1], vpn[2]);
340 void TelEvalViewMappingMatrix (const Handle(OpenGl_Display)& theGlDisplay,
341 tel_view_mapping mapping /* View Mapping */,
342 Tint *error_ind /* Out: Error Indicator */,
343 Tmatrix3 mat /* Out: Mapping Matrix */
346 EvalViewMappingMatrix (theGlDisplay, mapping, error_ind, mat, 0, ( float )0.0, ( float )0.0, 0, 0);