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( tel_view_mapping mapping /* View Mapping */,
33 Tint* error_ind /* Out: Error Indicator */,
34 Tmatrix3 mat /* Out: Mapping Matrix * */,
39 Tlimit3* /*clip_limit*/
42 Tfloat gx, gy, xsf, ysf, zsf;
46 Tfloat n, f, r, l, t, b, Zprp, dx, dy, VPD;
50 Tlimit3 vp = { ( float )-1.0, ( float )1.0, ( float )-1.0, ( float )1.0, ( float )1.0, ( float )-1.0 };
51 Tmatrix3 pmat = { { ( float )1.0, ( float )0.0, ( float )0.0, ( float )0.0 },
52 { ( float )0.0, ( float )1.0, ( float )0.0, ( float )0.0 },
53 { ( float )0.0, ( float )0.0, ( float )1.0, ( float )0.0 },
54 { ( float )0.0, ( float )0.0, ( float )0.0, ( float )1.0 } };
55 Tmatrix3 mmat = { { ( float )1.0, ( float )0.0, ( float )0.0, ( float )0.0 },
56 { ( float )0.0, ( float )1.0, ( float )0.0, ( float )0.0 },
57 { ( float )0.0, ( float )0.0, ( float )1.0, ( float )0.0 },
58 { ( float )0.0, ( float )0.0, ( float )0.0, ( float )1.0 } };
64 if( mapping->window.xmin >= mapping->window.xmax ||
65 mapping->window.ymin >= mapping->window.ymax )
71 /* invalid viewport */
72 if( mapping->viewport.xmin >= mapping->viewport.xmax ||
73 mapping->viewport.ymin >= mapping->viewport.ymax ||
74 mapping->viewport.zmin >= mapping->viewport.zmax )
80 /* invalid back/front plane distances */
81 if( mapping->bpd >= mapping->fpd )
87 /* prp between front and back planes */
88 if (openglDisplay.IsNull() || !openglDisplay->Walkthrough())
90 if( mapping->prp[2] < mapping->fpd &&
91 mapping->prp[2] > mapping->bpd )
98 if( mapping->prp[2] == mapping->vpd )
100 *error_ind = 5; /* prp on view plane */
104 if( mapping->viewport.xmin < 0 ||
105 mapping->viewport.xmax > 1 ||
106 mapping->viewport.ymin < 0 ||
107 mapping->viewport.ymax > 1 ||
108 mapping->viewport.zmin < 0 ||
109 mapping->viewport.zmax > 1 )
111 *error_ind = 6; /* viewport limits outside NPC space */
117 /* OCC18942: Moved here while debugging perspective projection matrix */
121 cx = mapping->window.xmin + mapping->window.xmax, cx /= ( float )2.0;
122 cy = mapping->window.ymin + mapping->window.ymax, cy /= ( float )2.0;
125 gx = (cx - mapping->prp[0]) / (mapping->vpd - mapping->prp[2]);
126 gy = (cy - mapping->prp[1]) / (mapping->vpd - mapping->prp[2]);
129 printf("EvalViewMappingMatrix \n");
130 printf("prp %f %f %f \n", mapping->prp[0], mapping->prp[1], mapping->prp[2]);
131 printf("vpd fpd bpd %f %f %f \n", mapping->vpd, mapping->fpd, mapping->bpd);
132 printf("window limit %f %f %f %f\n", mapping->window.xmin, mapping->window.xmax,
133 mapping->window.ymin, mapping->window.ymax);
134 printf("viewport limit %f %f %f %f\n", mapping->viewport.xmin, mapping->viewport.xmax,
135 mapping->viewport.ymin, mapping->viewport.ymax);
138 /* projection matrix */
139 if( mapping->proj == TelParallel )
142 pmat[2][0] = -gx; pmat[3][0] = mapping->vpd*gx;
143 pmat[2][1] = -gy; pmat[3][1] = mapping->vpd*gy;
145 else if (!openglDisplay.IsNull() && !openglDisplay->SymPerspective())/* TelPerspective */
147 pmat[0][0] = pmat[1][1] = mapping->prp[2] - mapping->vpd;
150 pmat[2][3] = ( float )-1.0;
151 pmat[3][0] = mapping->vpd * gx;
152 pmat[3][1] = mapping->vpd * gy;
153 pmat[3][3] = mapping->prp[2];
155 /* modify the next two cells to change clipping policy */
156 if (!openglDisplay.IsNull() && !openglDisplay->Walkthrough())
158 pmat[2][2] = mapping->prp[2] - ( fpd + bpd );
159 pmat[3][2] = fpd * bpd;
162 /* OCC18942: New approach to calculation of mapping (projection) matrix */
165 dx = mapping->window.xmax - mapping->window.xmin;
166 dy = mapping->window.ymax - mapping->window.ymin;
167 Zprp = mapping->prp[2];
168 VPD = Zprp - mapping->vpd;
171 Calculate canonical perspective projection parameters as if we were about
172 to use glFrustum() to create symmetric perspective frustum.
174 After the view orientation matrix is applied, the coordinate system origin is located
175 at the VRP and oriented properly. However, the viewplane has width = dx and height = dy
176 and its center (cx, cy, VPD) is not always located at the view Z axis.
177 The canonical perspective projection matrix assumes the eye is located at (0, 0, 0).
178 Thus the old approach resulted in a non-symmetric perspective,
179 as X and Y coordinates of the projection reference point (PRP) were not updated
180 when cx and cy changed. Moreover, such "static" perspective had some other disadvantages,
181 such as non-realistic panning, i.e. instead of moving the eye (or camera) over the model
182 a sort of "frame" moved over the static perspective projection picture,
183 exposing a part of this static picture to the user.
185 In order to make the perspective symmetric, we need to translate
186 the coordinate system to PRP before projection.
187 Thus we translate X, Y and Z co-ordinates by -cx, -cy and -Zprp respectively.
189 NOTE: mat[i][j] means j-th element of i-th column, as OpenGL accepts the matrices
190 in column-major order, while in C two-dimensional arrays are stored in memory
193 VPD is used below instead of near clipping plane dispance (n) in order to simplify
194 calculation of l and r values. If we did not use VPD in the matrix calculation, we would have to
195 project 0.5 * dx, -0.5 * dx, 0.5 * dy and - 0.5 * dy onto the near clipping plane
196 to calculate these values.
199 1. It is still necessary to find a way to calculate the perspective projection matrix
200 for TPM_WALKTHROUGH projection model. This projection model is not supported yet
207 n = Zprp - fpd; f = Zprp - bpd;
209 mat[0][0] = 2.f * VPD / (r - l);
210 mat[1][1] = 2.f * VPD / (t - b);
211 mat[2][0] = (r + l) / (r - l);
212 mat[2][1] = (t + b) / (t - b);
213 mat[2][2] = - (f + n) / (f - n);
216 The last column takes into account translation along X, Y and Z axis
217 before projecting. This can be considered as a result of right-multiplying the canonical
218 perspective projection matrix P by a translation matrix T
219 (it differs form the canonical matrix by the last column only):
222 mat = P * T, where T = | 0 0 1 -Zprp |
225 mat[3][0] = -mat[2][0] * Zprp - mat[0][0] * cx;
226 mat[3][1] = -mat[2][1] * Zprp - mat[1][1] * cy;
227 mat[3][2] = -2.f * f * n / (f - n) - mat[2][2] * Zprp;
231 printf("r l t b n f: %f %f %f %f %f %f \n", r,l,t,b,n,f);
232 printf( "mapping_matrix (new code):\n" );
236 /* return here, as further calculations are related to the old approach */
241 xsf = (vp.xmax - vp.xmin) / (mapping->window.xmax - mapping->window.xmin);
242 ysf = (vp.ymax - vp.ymin) / (mapping->window.ymax - mapping->window.ymin);
243 zsf = (vp.zmax - vp.zmin) / (fpd - bpd);
246 mmat[0][0] = xsf, mmat[1][1] = ysf, mmat[2][2] = zsf;
247 mmat[3][0] = vp.xmin - xsf*mapping->window.xmin;
248 mmat[3][1] = vp.ymin - ysf*mapping->window.ymin;
249 mmat[3][2] = vp.zmin - zsf*bpd;
251 /* multiply to obtain mapping matrix */
252 TelMultiplymat3( mat, pmat, mmat );
255 printf( "mapping_matrix :\n" );
261 TelEvalViewOrientationMatrix( Tfloat *vrp /* View Reference Point */,
262 Tfloat *vpn /* View Plane Normal */,
263 Tfloat *vup /* View Up Vector */,
264 Tfloat *asf /* Axial Scale Factors */,
265 Tint *error_ind/* Out: Error indicator */,
266 Tmatrix3 rmat /* Out: Orientation Matrix */
269 Tfloat u[3], v[3], n[3], f;
271 /* view plane normal of zero length */
272 if( vecmag(vpn) == 0.0 )
278 /* view up vector of zero length */
279 if( vecmag(vup) == 0.0 )
285 /* view up vector parallel to view plane normal */
299 veccrs(u,v,n); /* up vector cross plane normal gives U axis */
302 veccrs(v,n,u); /* plane normal cross U axis gives modified up vector */
303 vecnrm(v); /* redundant ? */
305 /* rotate to align along u, v, n */
306 rmat[0][0] = ( float )u[0] * asf[0],
307 rmat[0][1] = ( float )v[0] * asf[0],
308 rmat[0][2] = ( float )n[0] * asf[0],
309 rmat[0][3] = ( float )0.0;
311 rmat[1][0] = ( float )u[1] * asf[1],
312 rmat[1][1] = ( float )v[1] * asf[1],
313 rmat[1][2] = ( float )n[1] * asf[1],
314 rmat[1][3] = ( float )0.0;
316 rmat[2][0] = ( float )u[2] * asf[2],
317 rmat[2][1] = ( float )v[2] * asf[2],
318 rmat[2][2] = ( float )n[2] * asf[2],
319 rmat[2][3] = ( float )0.0;
321 /* translate to centre at vrp */
323 rmat[3][0] = - ( float ) (u[0]*vrp[0] + u[1]*vrp[1] + u[2]*vrp[2]);
324 rmat[3][1] = - ( float ) (v[0]*vrp[0] + v[1]*vrp[1] + v[2]*vrp[2]);
325 rmat[3][2] = - ( float ) (n[0]*vrp[0] + n[1]*vrp[1] + n[2]*vrp[2]);
326 rmat[3][3] = ( float )1.0;
329 printf("TelEvalViewOrientationMatrix \n");
330 printf("view_ref_pt %f %f %f \n", vrp[0], vrp[1], vrp[2]);
331 printf("view_up_vec %f %f %f \n", vup[0], vup[1], vup[2]);
332 printf("view_plane_normal %f %f %f \n", vpn[0], vpn[1], vpn[2]);
340 TelEvalViewMappingMatrix( tel_view_mapping mapping /* View Mapping */,
341 Tint *error_ind /* Out: Error Indicator */,
342 Tmatrix3 mat /* Out: Mapping Matrix */
345 EvalViewMappingMatrix( mapping, error_ind, mat, 0, ( float )0.0, ( float )0.0, 0, 0 );