c5751993 |
1 | // Created on: 2014-03-31 |
2 | // Created by: Danila ULYANOV |
3 | // Copyright (c) 2014 OPEN CASCADE SAS |
4 | // |
5 | // This file is part of Open CASCADE Technology software library. |
6 | // |
0a36ca0a |
7 | // This library is free software; you can redistribute it and/or modify it under |
8 | // the terms of the GNU Lesser General Public License version 2.1 as published |
c5751993 |
9 | // by the Free Software Foundation, with special exception defined in the file |
10 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
11 | // distribution for complete text of the license and disclaimer of any warranty. |
12 | // |
13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. |
15 | |
16 | #include <OpenGl_Layer.hxx> |
a1954302 |
17 | |
18 | #include <OpenGl_BVHTreeSelector.hxx> |
19 | #include <OpenGl_Structure.hxx> |
7c3ef2f7 |
20 | #include <OpenGl_ShaderManager.hxx> |
a1954302 |
21 | #include <OpenGl_View.hxx> |
550f3b8b |
22 | #include <OpenGl_Workspace.hxx> |
c04c30b3 |
23 | #include <Graphic3d_GraphicDriver.hxx> |
c5751993 |
24 | |
f5b72419 |
25 | IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Layer, Standard_Transient) |
26 | |
a1954302 |
27 | // ======================================================================= |
825aa485 |
28 | // function : OpenGl_Layer |
a1954302 |
29 | // purpose : |
30 | // ======================================================================= |
f5b72419 |
31 | OpenGl_Layer::OpenGl_Layer (const Standard_Integer theNbPriorities, |
32 | const Handle(Select3D_BVHBuilder3d)& theBuilder) |
50d06d8f |
33 | : myArray (0, theNbPriorities - 1), |
34 | myNbStructures (0), |
15669413 |
35 | myNbStructuresNotCulled (0), |
f5b72419 |
36 | myBVHPrimitivesTrsfPers (theBuilder), |
a1954302 |
37 | myBVHIsLeftChildQueuedFirst (Standard_True), |
15669413 |
38 | myIsBVHPrimitivesNeedsReset (Standard_False) |
c5751993 |
39 | { |
50d06d8f |
40 | myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true; |
c5751993 |
41 | } |
42 | |
a1954302 |
43 | // ======================================================================= |
44 | // function : ~OpenGl_Layer |
45 | // purpose : |
46 | // ======================================================================= |
47 | OpenGl_Layer::~OpenGl_Layer() |
48 | { |
49 | // |
50 | } |
51 | |
52 | // ======================================================================= |
53 | // function : Add |
54 | // purpose : |
55 | // ======================================================================= |
56 | void OpenGl_Layer::Add (const OpenGl_Structure* theStruct, |
57 | const Standard_Integer thePriority, |
58 | Standard_Boolean isForChangePriority) |
59 | { |
60 | const Standard_Integer anIndex = Min (Max (thePriority, 0), myArray.Length() - 1); |
61 | if (theStruct == NULL) |
62 | { |
63 | return; |
64 | } |
65 | |
9f112210 |
66 | myArray (anIndex).Add (theStruct); |
a1954302 |
67 | if (theStruct->IsAlwaysRendered()) |
68 | { |
69 | theStruct->MarkAsNotCulled(); |
3fe9ce0e |
70 | if (!isForChangePriority) |
71 | { |
72 | myAlwaysRenderedMap.Add (theStruct); |
73 | } |
a1954302 |
74 | } |
75 | else if (!isForChangePriority) |
76 | { |
778cd667 |
77 | if (theStruct->TransformPersistence().IsNull()) |
825aa485 |
78 | { |
79 | myBVHPrimitives.Add (theStruct); |
80 | } |
81 | else |
82 | { |
83 | myBVHPrimitivesTrsfPers.Add (theStruct); |
84 | } |
a1954302 |
85 | } |
86 | ++myNbStructures; |
87 | } |
88 | |
89 | // ======================================================================= |
90 | // function : Remove |
91 | // purpose : |
92 | // ======================================================================= |
93 | bool OpenGl_Layer::Remove (const OpenGl_Structure* theStruct, |
94 | Standard_Integer& thePriority, |
95 | Standard_Boolean isForChangePriority) |
96 | { |
97 | if (theStruct == NULL) |
98 | { |
99 | thePriority = -1; |
100 | return false; |
101 | } |
102 | |
103 | const Standard_Integer aNbPriorities = myArray.Length(); |
104 | for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter) |
105 | { |
9f112210 |
106 | OpenGl_IndexedMapOfStructure& aStructures = myArray (aPriorityIter); |
107 | |
108 | const Standard_Integer anIndex = aStructures.FindIndex (theStruct); |
109 | if (anIndex != 0) |
a1954302 |
110 | { |
9f112210 |
111 | aStructures.Swap (anIndex, aStructures.Size()); |
112 | aStructures.RemoveLast(); |
113 | |
3fe9ce0e |
114 | if (!isForChangePriority) |
a1954302 |
115 | { |
ef9a9362 |
116 | Standard_Boolean isAlwaysRend = theStruct->IsAlwaysRendered(); |
117 | if (!isAlwaysRend) |
825aa485 |
118 | { |
ef9a9362 |
119 | if (!myBVHPrimitives.Remove (theStruct)) |
3fe9ce0e |
120 | { |
ef9a9362 |
121 | if (!myBVHPrimitivesTrsfPers.Remove (theStruct)) |
122 | { |
123 | isAlwaysRend = Standard_True; |
124 | } |
3fe9ce0e |
125 | } |
126 | } |
ef9a9362 |
127 | if (isAlwaysRend) |
3fe9ce0e |
128 | { |
ef9a9362 |
129 | const Standard_Integer anIndex2 = myAlwaysRenderedMap.FindIndex (theStruct); |
130 | if (anIndex2 != 0) |
3fe9ce0e |
131 | { |
ef9a9362 |
132 | myAlwaysRenderedMap.Swap (myAlwaysRenderedMap.Size(), anIndex2); |
133 | myAlwaysRenderedMap.RemoveLast(); |
3fe9ce0e |
134 | } |
825aa485 |
135 | } |
a1954302 |
136 | } |
9f112210 |
137 | --myNbStructures; |
138 | thePriority = aPriorityIter; |
139 | return true; |
a1954302 |
140 | } |
141 | } |
142 | |
143 | thePriority = -1; |
144 | return false; |
145 | } |
146 | |
147 | // ======================================================================= |
148 | // function : InvalidateBVHData |
149 | // purpose : |
150 | // ======================================================================= |
2b8832bb |
151 | void OpenGl_Layer::InvalidateBVHData() |
a1954302 |
152 | { |
153 | myIsBVHPrimitivesNeedsReset = Standard_True; |
154 | } |
155 | |
3fe9ce0e |
156 | //! Calculate a finite bounding box of infinite object as its middle point. |
7c3ef2f7 |
157 | inline Graphic3d_BndBox3d centerOfinfiniteBndBox (const Graphic3d_BndBox3d& theBndBox) |
3fe9ce0e |
158 | { |
159 | // bounding borders of infinite line has been calculated as own point in center of this line |
7c3ef2f7 |
160 | const Graphic3d_Vec3d aDiagVec = theBndBox.CornerMax() - theBndBox.CornerMin(); |
161 | return aDiagVec.SquareModulus() >= 500000.0 * 500000.0 |
162 | ? Graphic3d_BndBox3d ((theBndBox.CornerMin() + theBndBox.CornerMax()) * 0.5) |
163 | : Graphic3d_BndBox3d(); |
3fe9ce0e |
164 | } |
165 | |
166 | //! Return true if at least one vertex coordinate out of float range. |
7c3ef2f7 |
167 | inline bool isInfiniteBndBox (const Graphic3d_BndBox3d& theBndBox) |
3fe9ce0e |
168 | { |
169 | return Abs (theBndBox.CornerMax().x()) >= ShortRealLast() |
170 | || Abs (theBndBox.CornerMax().y()) >= ShortRealLast() |
171 | || Abs (theBndBox.CornerMax().z()) >= ShortRealLast() |
172 | || Abs (theBndBox.CornerMin().x()) >= ShortRealLast() |
173 | || Abs (theBndBox.CornerMin().y()) >= ShortRealLast() |
174 | || Abs (theBndBox.CornerMin().z()) >= ShortRealLast(); |
175 | } |
176 | |
a1954302 |
177 | // ======================================================================= |
50d06d8f |
178 | // function : BoundingBox |
179 | // purpose : |
180 | // ======================================================================= |
7c3ef2f7 |
181 | Bnd_Box OpenGl_Layer::BoundingBox (const Standard_Integer theViewId, |
182 | const Handle(Graphic3d_Camera)& theCamera, |
183 | const Standard_Integer theWindowWidth, |
184 | const Standard_Integer theWindowHeight, |
185 | const Standard_Boolean theToIncludeAuxiliary) const |
50d06d8f |
186 | { |
150ed3d5 |
187 | updateBVH(); |
188 | |
3fe9ce0e |
189 | const Standard_Integer aBoxId = !theToIncludeAuxiliary ? 0 : 1; |
7c3ef2f7 |
190 | const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix(); |
191 | const Graphic3d_Mat4d& aWorldViewMat = theCamera->OrientationMatrix(); |
50d06d8f |
192 | if (myIsBoundingBoxNeedsReset[aBoxId]) |
193 | { |
194 | // Recompute layer bounding box |
7c3ef2f7 |
195 | myBoundingBox[aBoxId].SetVoid(); |
50d06d8f |
196 | |
7c3ef2f7 |
197 | for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
50d06d8f |
198 | { |
7c3ef2f7 |
199 | const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value(); |
200 | for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
50d06d8f |
201 | { |
7c3ef2f7 |
202 | const OpenGl_Structure* aStructure = aStructIter.Value(); |
3fe9ce0e |
203 | if (!aStructure->IsVisible (theViewId)) |
50d06d8f |
204 | { |
205 | continue; |
206 | } |
207 | |
208 | // "FitAll" operation ignores object with transform persistence parameter |
209 | // but adds transform persistence point in a bounding box of layer (only zoom pers. objects). |
778cd667 |
210 | if (!aStructure->TransformPersistence().IsNull()) |
50d06d8f |
211 | { |
3fe9ce0e |
212 | if (!theToIncludeAuxiliary |
778cd667 |
213 | && aStructure->TransformPersistence()->IsZoomOrRotate()) |
50d06d8f |
214 | { |
778cd667 |
215 | const gp_Pnt anAnchor = aStructure->TransformPersistence()->AnchorPoint(); |
7c3ef2f7 |
216 | myBoundingBox[aBoxId].Add (anAnchor); |
50d06d8f |
217 | continue; |
218 | } |
219 | // Panning and 2d persistence apply changes to projection or/and its translation components. |
220 | // It makes them incompatible with z-fitting algorithm. Ignored by now. |
3fe9ce0e |
221 | else if (!theToIncludeAuxiliary |
778cd667 |
222 | || aStructure->TransformPersistence()->IsTrihedronOr2d()) |
50d06d8f |
223 | { |
224 | continue; |
225 | } |
226 | } |
227 | |
7c3ef2f7 |
228 | Graphic3d_BndBox3d aBox = aStructure->BoundingBox(); |
3fe9ce0e |
229 | if (!aBox.IsValid()) |
230 | { |
231 | continue; |
232 | } |
50d06d8f |
233 | |
234 | if (aStructure->IsInfinite |
3fe9ce0e |
235 | && !theToIncludeAuxiliary) |
50d06d8f |
236 | { |
3fe9ce0e |
237 | // include center of infinite object |
238 | aBox = centerOfinfiniteBndBox (aBox); |
50d06d8f |
239 | } |
240 | |
778cd667 |
241 | if (!aStructure->TransformPersistence().IsNull()) |
50d06d8f |
242 | { |
778cd667 |
243 | aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox); |
50d06d8f |
244 | } |
245 | |
3fe9ce0e |
246 | // skip too big boxes to prevent float overflow at camera parameters calculation |
7c3ef2f7 |
247 | if (aBox.IsValid() |
248 | && !isInfiniteBndBox (aBox)) |
50d06d8f |
249 | { |
7c3ef2f7 |
250 | myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z())); |
251 | myBoundingBox[aBoxId].Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z())); |
50d06d8f |
252 | } |
50d06d8f |
253 | } |
254 | } |
255 | |
256 | myIsBoundingBoxNeedsReset[aBoxId] = false; |
257 | } |
258 | |
7c3ef2f7 |
259 | Bnd_Box aResBox = myBoundingBox[aBoxId]; |
3fe9ce0e |
260 | if (!theToIncludeAuxiliary |
261 | || myAlwaysRenderedMap.IsEmpty()) |
262 | { |
7c3ef2f7 |
263 | return aResBox; |
3fe9ce0e |
264 | } |
265 | |
266 | // add transformation-persistent objects which depend on camera position (and thus can not be cached) for operations like Z-fit |
3fe9ce0e |
267 | for (NCollection_IndexedMap<const OpenGl_Structure*>::Iterator aStructIter (myAlwaysRenderedMap); aStructIter.More(); aStructIter.Next()) |
268 | { |
269 | const OpenGl_Structure* aStructure = aStructIter.Value(); |
270 | if (!aStructure->IsVisible (theViewId)) |
271 | { |
272 | continue; |
273 | } |
778cd667 |
274 | else if (aStructure->TransformPersistence().IsNull() |
275 | || !aStructure->TransformPersistence()->IsTrihedronOr2d()) |
3fe9ce0e |
276 | { |
277 | continue; |
278 | } |
279 | |
7c3ef2f7 |
280 | Graphic3d_BndBox3d aBox = aStructure->BoundingBox(); |
3fe9ce0e |
281 | if (!aBox.IsValid()) |
282 | { |
283 | continue; |
284 | } |
285 | |
778cd667 |
286 | aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox); |
7c3ef2f7 |
287 | if (aBox.IsValid() |
288 | && !isInfiniteBndBox (aBox)) |
3fe9ce0e |
289 | { |
7c3ef2f7 |
290 | aResBox.Add (gp_Pnt (aBox.CornerMin().x(), aBox.CornerMin().y(), aBox.CornerMin().z())); |
291 | aResBox.Add (gp_Pnt (aBox.CornerMax().x(), aBox.CornerMax().y(), aBox.CornerMax().z())); |
3fe9ce0e |
292 | } |
293 | } |
294 | |
295 | return aResBox; |
50d06d8f |
296 | } |
297 | |
298 | // ======================================================================= |
299 | // function : considerZoomPersistenceObjects |
300 | // purpose : |
301 | // ======================================================================= |
302 | Standard_Real OpenGl_Layer::considerZoomPersistenceObjects (const Standard_Integer theViewId, |
303 | const Handle(Graphic3d_Camera)& theCamera, |
304 | Standard_Integer theWindowWidth, |
3fe9ce0e |
305 | Standard_Integer theWindowHeight) const |
50d06d8f |
306 | { |
307 | if (NbOfTransformPersistenceObjects() == 0) |
308 | { |
309 | return 1.0; |
310 | } |
311 | |
7c3ef2f7 |
312 | const Graphic3d_Mat4d& aProjectionMat = theCamera->ProjectionMatrix(); |
313 | const Graphic3d_Mat4d& aWorldViewMat = theCamera->OrientationMatrix(); |
50d06d8f |
314 | Standard_Real aMaxCoef = -std::numeric_limits<double>::max(); |
315 | |
7c3ef2f7 |
316 | for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
50d06d8f |
317 | { |
7c3ef2f7 |
318 | const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value(); |
319 | for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
50d06d8f |
320 | { |
7c3ef2f7 |
321 | const OpenGl_Structure* aStructure = aStructIter.Value(); |
3fe9ce0e |
322 | if (!aStructure->IsVisible (theViewId) |
778cd667 |
323 | || aStructure->TransformPersistence().IsNull() |
324 | || !aStructure->TransformPersistence()->IsZoomOrRotate()) |
50d06d8f |
325 | { |
326 | continue; |
327 | } |
328 | |
7c3ef2f7 |
329 | Graphic3d_BndBox3d aBox = aStructure->BoundingBox(); |
3fe9ce0e |
330 | if (!aBox.IsValid()) |
50d06d8f |
331 | { |
332 | continue; |
333 | } |
334 | |
778cd667 |
335 | aStructure->TransformPersistence()->Apply (theCamera, aProjectionMat, aWorldViewMat, theWindowWidth, theWindowHeight, aBox); |
50d06d8f |
336 | |
7c3ef2f7 |
337 | const BVH_Vec3d& aCornerMin = aBox.CornerMin(); |
338 | const BVH_Vec3d& aCornerMax = aBox.CornerMax(); |
50d06d8f |
339 | const Standard_Integer aNbOfPoints = 8; |
340 | const gp_Pnt aPoints[aNbOfPoints] = { gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMin.z()), |
341 | gp_Pnt (aCornerMin.x(), aCornerMin.y(), aCornerMax.z()), |
342 | gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMin.z()), |
343 | gp_Pnt (aCornerMin.x(), aCornerMax.y(), aCornerMax.z()), |
344 | gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMin.z()), |
345 | gp_Pnt (aCornerMax.x(), aCornerMin.y(), aCornerMax.z()), |
346 | gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMin.z()), |
347 | gp_Pnt (aCornerMax.x(), aCornerMax.y(), aCornerMax.z()) }; |
348 | gp_Pnt aConvertedPoints[aNbOfPoints]; |
349 | Standard_Real aConvertedMinX = std::numeric_limits<double>::max(); |
350 | Standard_Real aConvertedMaxX = -std::numeric_limits<double>::max(); |
351 | Standard_Real aConvertedMinY = std::numeric_limits<double>::max(); |
352 | Standard_Real aConvertedMaxY = -std::numeric_limits<double>::max(); |
353 | for (Standard_Integer anIdx = 0; anIdx < aNbOfPoints; ++anIdx) |
354 | { |
355 | aConvertedPoints[anIdx] = theCamera->Project (aPoints[anIdx]); |
356 | |
357 | aConvertedMinX = Min (aConvertedMinX, aConvertedPoints[anIdx].X()); |
358 | aConvertedMaxX = Max (aConvertedMaxX, aConvertedPoints[anIdx].X()); |
359 | |
360 | aConvertedMinY = Min (aConvertedMinY, aConvertedPoints[anIdx].Y()); |
361 | aConvertedMaxY = Max (aConvertedMaxY, aConvertedPoints[anIdx].Y()); |
362 | } |
363 | |
364 | const Standard_Boolean isBigObject = (Abs (aConvertedMaxX - aConvertedMinX) > 2.0) // width of zoom pers. object greater than width of window |
365 | || (Abs (aConvertedMaxY - aConvertedMinY) > 2.0); // height of zoom pers. object greater than height of window |
366 | const Standard_Boolean isAlreadyInScreen = (aConvertedMinX > -1.0 && aConvertedMinX < 1.0) |
367 | && (aConvertedMaxX > -1.0 && aConvertedMaxX < 1.0) |
368 | && (aConvertedMinY > -1.0 && aConvertedMinY < 1.0) |
369 | && (aConvertedMaxY > -1.0 && aConvertedMaxY < 1.0); |
370 | if (isBigObject || isAlreadyInScreen) |
371 | { |
372 | continue; |
373 | } |
374 | |
778cd667 |
375 | const gp_Pnt aTPPoint = aStructure->TransformPersistence()->AnchorPoint(); |
50d06d8f |
376 | gp_Pnt aConvertedTPPoint = theCamera->Project (aTPPoint); |
377 | aConvertedTPPoint.SetZ (0.0); |
378 | |
379 | if (aConvertedTPPoint.Coord().Modulus() < Precision::Confusion()) |
380 | { |
381 | continue; |
382 | } |
383 | |
384 | Standard_Real aShiftX = 0.0; |
385 | if (aConvertedMinX < -1.0) |
386 | { |
387 | aShiftX = ((aConvertedMaxX < -1.0) ? (-(1.0 + aConvertedMaxX) + (aConvertedMaxX - aConvertedMinX)) : -(1.0 + aConvertedMinX)); |
388 | } |
389 | else if (aConvertedMaxX > 1.0) |
390 | { |
391 | aShiftX = ((aConvertedMinX > 1.0) ? ((aConvertedMinX - 1.0) + (aConvertedMaxX - aConvertedMinX)) : (aConvertedMaxX - 1.0)); |
392 | } |
393 | |
394 | Standard_Real aShiftY = 0.0; |
395 | if (aConvertedMinY < -1.0) |
396 | { |
397 | aShiftY = ((aConvertedMaxY < -1.0) ? (-(1.0 + aConvertedMaxY) + (aConvertedMaxY - aConvertedMinY)) : -(1.0 + aConvertedMinY)); |
398 | } |
399 | else if (aConvertedMaxY > 1.0) |
400 | { |
401 | aShiftY = ((aConvertedMinY > 1.0) ? ((aConvertedMinY - 1.0) + (aConvertedMaxY - aConvertedMinY)) : (aConvertedMaxY - 1.0)); |
402 | } |
403 | |
404 | const Standard_Real aDifX = Abs (aConvertedTPPoint.X()) - aShiftX; |
405 | const Standard_Real aDifY = Abs (aConvertedTPPoint.Y()) - aShiftY; |
406 | if (aDifX > Precision::Confusion()) |
407 | { |
408 | aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.X()) / aDifX); |
409 | } |
410 | if (aDifY > Precision::Confusion()) |
411 | { |
412 | aMaxCoef = Max (aMaxCoef, Abs (aConvertedTPPoint.Y()) / aDifY); |
413 | } |
414 | } |
415 | } |
416 | |
417 | return (aMaxCoef > 0.0) ? aMaxCoef : 1.0; |
418 | } |
419 | |
420 | // ======================================================================= |
a1954302 |
421 | // function : renderAll |
422 | // purpose : |
423 | // ======================================================================= |
424 | void OpenGl_Layer::renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const |
425 | { |
7c3ef2f7 |
426 | const Standard_Integer aViewId = theWorkspace->View()->Identification(); |
427 | for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
a1954302 |
428 | { |
7c3ef2f7 |
429 | const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value(); |
430 | for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
a1954302 |
431 | { |
7c3ef2f7 |
432 | const OpenGl_Structure* aStruct = aStructIter.Value(); |
2b8832bb |
433 | if (aStruct->IsCulled() |
434 | || !aStruct->IsVisible (aViewId)) |
a272ed94 |
435 | { |
436 | continue; |
437 | } |
a1954302 |
438 | |
439 | aStruct->Render (theWorkspace); |
440 | } |
441 | } |
442 | } |
443 | |
444 | // ======================================================================= |
3fe9ce0e |
445 | // function : updateBVH |
a1954302 |
446 | // purpose : |
447 | // ======================================================================= |
3fe9ce0e |
448 | void OpenGl_Layer::updateBVH() const |
a1954302 |
449 | { |
3fe9ce0e |
450 | if (!myIsBVHPrimitivesNeedsReset) |
451 | { |
452 | return; |
453 | } |
454 | |
455 | myBVHPrimitives.Clear(); |
456 | myBVHPrimitivesTrsfPers.Clear(); |
150ed3d5 |
457 | myAlwaysRenderedMap.Clear(); |
3fe9ce0e |
458 | myIsBVHPrimitivesNeedsReset = Standard_False; |
7c3ef2f7 |
459 | for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
a1954302 |
460 | { |
7c3ef2f7 |
461 | const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value(); |
462 | for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
825aa485 |
463 | { |
3fe9ce0e |
464 | const OpenGl_Structure* aStruct = aStructIter.Value(); |
465 | if (aStruct->IsAlwaysRendered()) |
825aa485 |
466 | { |
150ed3d5 |
467 | aStruct->MarkAsNotCulled(); |
468 | myAlwaysRenderedMap.Add (aStruct); |
3fe9ce0e |
469 | } |
778cd667 |
470 | else if (aStruct->TransformPersistence().IsNull()) |
3fe9ce0e |
471 | { |
472 | myBVHPrimitives.Add (aStruct); |
473 | } |
474 | else |
475 | { |
476 | myBVHPrimitivesTrsfPers.Add (aStruct); |
825aa485 |
477 | } |
478 | } |
a1954302 |
479 | } |
3fe9ce0e |
480 | } |
481 | |
482 | // ======================================================================= |
2b8832bb |
483 | // function : UpdateCulling |
3fe9ce0e |
484 | // purpose : |
485 | // ======================================================================= |
5dc0517d |
486 | void OpenGl_Layer::UpdateCulling (const Standard_Integer theViewId, |
487 | const OpenGl_BVHTreeSelector& theSelector, |
0e3025bc |
488 | const Graphic3d_RenderingParams::FrustumCulling theFrustumCullingState) |
3fe9ce0e |
489 | { |
490 | updateBVH(); |
a1954302 |
491 | |
15669413 |
492 | myNbStructuresNotCulled = myNbStructures; |
0e3025bc |
493 | if (theFrustumCullingState != Graphic3d_RenderingParams::FrustumCulling_NoUpdate) |
a1954302 |
494 | { |
0e3025bc |
495 | Standard_Boolean toTraverse = |
496 | (theFrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On); |
497 | for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitives.Structures()); aStructIter.More(); aStructIter.Next()) |
498 | { |
499 | const OpenGl_Structure* aStruct = aStructIter.Value(); |
500 | aStruct->SetCulled (toTraverse); |
501 | } |
502 | for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (myBVHPrimitivesTrsfPers.Structures()); aStructIter.More(); aStructIter.Next()) |
503 | { |
504 | const OpenGl_Structure* aStruct = aStructIter.Value(); |
505 | aStruct->SetCulled (toTraverse); |
506 | } |
a1954302 |
507 | } |
a1954302 |
508 | |
0e3025bc |
509 | if (theFrustumCullingState != Graphic3d_RenderingParams::FrustumCulling_On) |
2b8832bb |
510 | { |
511 | return; |
512 | } |
513 | if (myBVHPrimitives .Size() == 0 |
514 | && myBVHPrimitivesTrsfPers.Size() == 0) |
515 | { |
516 | return; |
517 | } |
518 | |
15669413 |
519 | myNbStructuresNotCulled = myAlwaysRenderedMap.Extent(); |
2b8832bb |
520 | OpenGl_BVHTreeSelector::CullingContext aCullCtx; |
521 | theSelector.SetCullingDistance(aCullCtx, myLayerSettings.CullingDistance()); |
522 | theSelector.SetCullingSize (aCullCtx, myLayerSettings.CullingSize()); |
825aa485 |
523 | for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx) |
a1954302 |
524 | { |
825aa485 |
525 | const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1; |
2b8832bb |
526 | opencascade::handle<BVH_Tree<Standard_Real, 3> > aBVHTree; |
825aa485 |
527 | if (isTrsfPers) |
a1954302 |
528 | { |
825aa485 |
529 | if (myBVHPrimitivesTrsfPers.Size() == 0) |
825aa485 |
530 | continue; |
97f937cc |
531 | |
7c3ef2f7 |
532 | const OpenGl_Mat4d& aProjection = theSelector.ProjectionMatrix(); |
533 | const OpenGl_Mat4d& aWorldView = theSelector.WorldViewMatrix(); |
825aa485 |
534 | const Graphic3d_WorldViewProjState& aWVPState = theSelector.WorldViewProjState(); |
91d96372 |
535 | const Standard_Integer aViewportWidth = theSelector.ViewportWidth(); |
536 | const Standard_Integer aViewportHeight = theSelector.ViewportHeight(); |
537 | |
3fe9ce0e |
538 | aBVHTree = myBVHPrimitivesTrsfPers.BVH (theSelector.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState); |
825aa485 |
539 | } |
540 | else |
541 | { |
542 | if (myBVHPrimitives.Size() == 0) |
825aa485 |
543 | continue; |
97f937cc |
544 | |
825aa485 |
545 | aBVHTree = myBVHPrimitives.BVH(); |
546 | } |
547 | |
2b8832bb |
548 | if (theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (0), aBVHTree->MaxPoint (0))) |
825aa485 |
549 | { |
550 | continue; |
551 | } |
552 | |
f5b72419 |
553 | Standard_Integer aStack[BVH_Constants_MaxTreeDepth]; |
825aa485 |
554 | Standard_Integer aHead = -1; |
2b8832bb |
555 | Standard_Integer aNode = 0; // a root node |
825aa485 |
556 | for (;;) |
557 | { |
558 | if (!aBVHTree->IsOuter (aNode)) |
a1954302 |
559 | { |
f2474958 |
560 | const Standard_Integer aLeftChildIdx = aBVHTree->Child<0> (aNode); |
561 | const Standard_Integer aRightChildIdx = aBVHTree->Child<1> (aNode); |
2b8832bb |
562 | const Standard_Boolean isLeftChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aLeftChildIdx), aBVHTree->MaxPoint (aLeftChildIdx)); |
563 | const Standard_Boolean isRightChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aRightChildIdx), aBVHTree->MaxPoint (aRightChildIdx)); |
825aa485 |
564 | if (isLeftChildIn |
565 | && isRightChildIn) |
566 | { |
567 | aNode = myBVHIsLeftChildQueuedFirst ? aLeftChildIdx : aRightChildIdx; |
568 | aStack[++aHead] = myBVHIsLeftChildQueuedFirst ? aRightChildIdx : aLeftChildIdx; |
569 | myBVHIsLeftChildQueuedFirst = !myBVHIsLeftChildQueuedFirst; |
570 | } |
571 | else if (isLeftChildIn |
572 | || isRightChildIn) |
573 | { |
574 | aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx; |
575 | } |
576 | else |
577 | { |
578 | if (aHead < 0) |
579 | { |
580 | break; |
581 | } |
582 | |
583 | aNode = aStack[aHead--]; |
584 | } |
a1954302 |
585 | } |
586 | else |
587 | { |
825aa485 |
588 | Standard_Integer aIdx = aBVHTree->BegPrimitive (aNode); |
4ecf34cc |
589 | const OpenGl_Structure* aStruct = isTrsfPers |
590 | ? myBVHPrimitivesTrsfPers.GetStructureById (aIdx) |
591 | : myBVHPrimitives.GetStructureById (aIdx); |
5dc0517d |
592 | if (aStruct->IsVisible (theViewId)) |
593 | { |
594 | aStruct->MarkAsNotCulled(); |
595 | ++myNbStructuresNotCulled; |
596 | } |
a1954302 |
597 | if (aHead < 0) |
598 | { |
825aa485 |
599 | break; |
a1954302 |
600 | } |
601 | |
14a35e5d |
602 | aNode = aStack[aHead--]; |
a1954302 |
603 | } |
604 | } |
a1954302 |
605 | } |
606 | } |
607 | |
608 | // ======================================================================= |
609 | // function : Append |
610 | // purpose : |
611 | // ======================================================================= |
612 | Standard_Boolean OpenGl_Layer::Append (const OpenGl_Layer& theOther) |
613 | { |
614 | // the source priority list shouldn't have more priorities |
615 | const Standard_Integer aNbPriorities = theOther.NbPriorities(); |
616 | if (aNbPriorities > NbPriorities()) |
617 | { |
618 | return Standard_False; |
619 | } |
620 | |
621 | // add all structures to destination priority list |
622 | for (Standard_Integer aPriorityIter = 0; aPriorityIter < aNbPriorities; ++aPriorityIter) |
623 | { |
9f112210 |
624 | const OpenGl_IndexedMapOfStructure& aStructures = theOther.myArray (aPriorityIter); |
7c3ef2f7 |
625 | for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
a1954302 |
626 | { |
7c3ef2f7 |
627 | Add (aStructIter.Value(), aPriorityIter); |
a1954302 |
628 | } |
629 | } |
630 | |
631 | return Standard_True; |
632 | } |
633 | |
c5751993 |
634 | //======================================================================= |
7c3ef2f7 |
635 | //function : SetLayerSettings |
636 | //purpose : |
637 | //======================================================================= |
638 | void OpenGl_Layer::SetLayerSettings (const Graphic3d_ZLayerSettings& theSettings) |
639 | { |
640 | const Standard_Boolean toUpdateTrsf = !myLayerSettings.Origin().IsEqual (theSettings.Origin(), gp::Resolution()); |
641 | myLayerSettings = theSettings; |
642 | if (toUpdateTrsf) |
643 | { |
644 | for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next()) |
645 | { |
646 | OpenGl_IndexedMapOfStructure& aStructures = aMapIter.ChangeValue(); |
647 | for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next()) |
648 | { |
649 | OpenGl_Structure* aStructure = const_cast<OpenGl_Structure*> (aStructIter.Value()); |
650 | aStructure->updateLayerTransformation(); |
651 | } |
652 | } |
653 | } |
654 | } |
655 | |
656 | //======================================================================= |
c5751993 |
657 | //function : Render |
a1954302 |
658 | //purpose : |
c5751993 |
659 | //======================================================================= |
a1954302 |
660 | void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)& theWorkspace, |
661 | const OpenGl_GlobalLayerSettings& theDefaultSettings) const |
c5751993 |
662 | { |
8d1a539c |
663 | const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext(); |
b3eab8ef |
664 | // myLayerSettings.ToClearDepth() is handled outside |
eae454e3 |
665 | |
c5751993 |
666 | // handle depth test |
7c3ef2f7 |
667 | if (myLayerSettings.ToEnableDepthTest()) |
c5751993 |
668 | { |
550f3b8b |
669 | // assuming depth test is enabled by default |
670 | glDepthFunc (theDefaultSettings.DepthFunc); |
c5751993 |
671 | } |
672 | else |
673 | { |
674 | glDepthFunc (GL_ALWAYS); |
675 | } |
eae454e3 |
676 | |
83da37b1 |
677 | // save environment texture |
cc8cbabe |
678 | Handle(OpenGl_TextureSet) anEnvironmentTexture = theWorkspace->EnvironmentTexture(); |
7c3ef2f7 |
679 | if (!myLayerSettings.UseEnvironmentTexture()) |
83da37b1 |
680 | { |
cc8cbabe |
681 | theWorkspace->SetEnvironmentTexture (Handle(OpenGl_TextureSet)()); |
83da37b1 |
682 | } |
683 | |
c5751993 |
684 | // handle depth offset |
a6df1715 |
685 | const Graphic3d_PolygonOffset anAppliedOffsetParams = theWorkspace->SetDefaultPolygonOffset (myLayerSettings.PolygonOffset()); |
c5751993 |
686 | |
687 | // handle depth write |
a1073ae2 |
688 | theWorkspace->UseDepthWrite() = myLayerSettings.ToEnableDepthWrite() && theDefaultSettings.DepthMask == GL_TRUE; |
eae454e3 |
689 | glDepthMask (theWorkspace->UseDepthWrite() ? GL_TRUE : GL_FALSE); |
c5751993 |
690 | |
7c3ef2f7 |
691 | const Standard_Boolean hasLocalCS = !myLayerSettings.OriginTransformation().IsNull(); |
992ed6b3 |
692 | const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager(); |
693 | Handle(Graphic3d_LightSet) aLightsBack = aManager->LightSourceState().LightSources(); |
694 | const bool hasOwnLights = aCtx->ColorMask() && !myLayerSettings.Lights().IsNull() && myLayerSettings.Lights() != aLightsBack; |
695 | if (hasOwnLights) |
696 | { |
697 | myLayerSettings.Lights()->UpdateRevision(); |
698 | aManager->UpdateLightSourceStateTo (myLayerSettings.Lights()); |
699 | } |
700 | |
7c3ef2f7 |
701 | const Handle(Graphic3d_Camera)& aWorldCamera = theWorkspace->View()->Camera(); |
7c3ef2f7 |
702 | if (hasLocalCS) |
703 | { |
704 | // Apply local camera transformation. |
705 | // The vertex position is computed by the following formula in GLSL program: |
706 | // gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex; |
707 | // where: |
708 | // occProjectionMatrix - matrix defining orthographic/perspective/stereographic projection |
709 | // occWorldViewMatrix - world-view matrix defining Camera position and orientation |
710 | // occModelWorldMatrix - model-world matrix defining Object transformation from local coordinate system to the world coordinate system |
711 | // occVertex - input vertex position |
712 | // |
713 | // Since double precision is quite expensive on modern GPUs, and not available on old hardware, |
714 | // all these values are passed with single float precision to the shader. |
715 | // As result, single precision become insufficient for handling objects far from the world origin. |
716 | // |
717 | // Several approaches can be used to solve precision issues: |
718 | // - [Broute force] migrate to double precision for all matrices and vertex position. |
719 | // This is too expensive for most hardware. |
720 | // - Store only translation part with double precision and pass it to GLSL program. |
721 | // This requires modified GLSL programs for computing transformation |
722 | // and extra packing mechanism for hardware not supporting double precision natively. |
723 | // This solution is less expensive then previous one. |
724 | // - Move translation part of occModelWorldMatrix into occWorldViewMatrix. |
725 | // The main idea here is that while moving Camera towards the object, |
726 | // Camera translation part and Object translation part will compensate each other |
727 | // to fit into single float precision. |
728 | // But this operation should be performed with double precision - this is why we are moving |
729 | // translation part of occModelWorldMatrix to occWorldViewMatrix. |
730 | // |
731 | // All approaches might be useful in different scenarios, but for the moment we consider the last one as main scenario. |
732 | // Here we do the trick: |
733 | // - OpenGl_Layer defines the Local Origin, which is expected to be the center of objects stored within it. |
734 | // This Local Origin is included into occWorldViewMatrix during rendering. |
735 | // - OpenGl_Structure defines Object local transformation occModelWorldMatrix with subtracted Local Origin of the Layer. |
736 | // This means that Object itself should be defined within either Local Transformation equal or near to Local Origin of the Layer. |
737 | theWorkspace->View()->SetLocalOrigin (myLayerSettings.Origin()); |
738 | |
739 | NCollection_Mat4<Standard_Real> aWorldView = aWorldCamera->OrientationMatrix(); |
740 | Graphic3d_TransformUtils::Translate (aWorldView, myLayerSettings.Origin().X(), myLayerSettings.Origin().Y(), myLayerSettings.Origin().Z()); |
741 | |
742 | NCollection_Mat4<Standard_ShortReal> aWorldViewF; |
743 | aWorldViewF.ConvertFrom (aWorldView); |
744 | aCtx->WorldViewState.SetCurrent (aWorldViewF); |
745 | aCtx->ShaderManager()->UpdateClippingState(); |
746 | aCtx->ShaderManager()->UpdateLightSourceState(); |
747 | } |
748 | |
c5751993 |
749 | // render priority list |
2b8832bb |
750 | renderAll (theWorkspace); |
550f3b8b |
751 | |
992ed6b3 |
752 | if (hasOwnLights) |
753 | { |
754 | aManager->UpdateLightSourceStateTo (aLightsBack); |
755 | } |
7c3ef2f7 |
756 | if (hasLocalCS) |
757 | { |
758 | aCtx->ShaderManager()->RevertClippingState(); |
759 | aCtx->ShaderManager()->UpdateLightSourceState(); |
760 | |
761 | aCtx->WorldViewState.SetCurrent (aWorldCamera->OrientationMatrixF()); |
762 | theWorkspace->View() ->SetLocalOrigin (gp_XYZ (0.0, 0.0, 0.0)); |
763 | } |
764 | |
550f3b8b |
765 | // always restore polygon offset between layers rendering |
a6df1715 |
766 | theWorkspace->SetDefaultPolygonOffset (anAppliedOffsetParams); |
83da37b1 |
767 | |
768 | // restore environment texture |
7c3ef2f7 |
769 | if (!myLayerSettings.UseEnvironmentTexture()) |
83da37b1 |
770 | { |
771 | theWorkspace->SetEnvironmentTexture (anEnvironmentTexture); |
772 | } |
c5751993 |
773 | } |