1 // Created on: 2013-08-27
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 2013 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
17 // On Windows, function TryEnterCriticalSection has appeared in Windows NT
18 // and is surrounded by #ifdef in MS VC++ 7.1 headers.
19 // Thus to use it we need to define appropriate macro saying that we will
20 // run on Windows NT 4.0 at least
21 #if defined(_WIN32) && !defined(_WIN32_WINNT)
22 #define _WIN32_WINNT 0x0501
28 #include <OpenGl_SceneGeometry.hxx>
30 #include <OpenGl_ArbTexBindless.hxx>
31 #include <OpenGl_PrimitiveArray.hxx>
32 #include <OpenGl_Structure.hxx>
33 #include <OSD_Timer.hxx>
34 #include <Standard_Assert.hxx>
36 //! Use this macro to output BVH profiling info
37 // #define RAY_TRACE_PRINT_INFO
41 //! Useful constant for null floating-point 4D vector.
42 static const BVH_Vec4f ZERO_VEC_4F;
45 // =======================================================================
46 // function : OpenGl_RaytraceMaterial
47 // purpose : Creates new default material
48 // =======================================================================
49 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial()
50 : Ambient (ZERO_VEC_4F),
51 Diffuse (ZERO_VEC_4F),
52 Specular (ZERO_VEC_4F),
53 Emission (ZERO_VEC_4F),
54 Reflection (ZERO_VEC_4F),
55 Refraction (ZERO_VEC_4F),
56 Transparency (ZERO_VEC_4F)
59 // =======================================================================
60 // function : OpenGl_RaytraceMaterial
61 // purpose : Creates new material with specified properties
62 // =======================================================================
63 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
64 const BVH_Vec4f& theDiffuse,
65 const BVH_Vec4f& theSpecular)
66 : Ambient (theAmbient),
68 Specular (theSpecular),
69 Emission (ZERO_VEC_4F),
70 Reflection (ZERO_VEC_4F),
71 Refraction (ZERO_VEC_4F),
72 Transparency (ZERO_VEC_4F)
77 // =======================================================================
78 // function : OpenGl_RaytraceMaterial
79 // purpose : Creates new material with specified properties
80 // =======================================================================
81 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
82 const BVH_Vec4f& theDiffuse,
83 const BVH_Vec4f& theSpecular,
84 const BVH_Vec4f& theEmission,
85 const BVH_Vec4f& theTranspar)
86 : Ambient (theAmbient),
88 Specular (theSpecular),
89 Emission (theEmission),
90 Reflection (ZERO_VEC_4F),
91 Refraction (ZERO_VEC_4F),
92 Transparency (theTranspar)
97 // =======================================================================
98 // function : OpenGl_RaytraceMaterial
99 // purpose : Creates new material with specified properties
100 // =======================================================================
101 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
102 const BVH_Vec4f& theDiffuse,
103 const BVH_Vec4f& theSpecular,
104 const BVH_Vec4f& theEmission,
105 const BVH_Vec4f& theTranspar,
106 const BVH_Vec4f& theReflection,
107 const BVH_Vec4f& theRefraction)
108 : Ambient (theAmbient),
109 Diffuse (theDiffuse),
110 Specular (theSpecular),
111 Emission (theEmission),
112 Reflection (theReflection),
113 Refraction (theRefraction),
114 Transparency (theTranspar)
119 // =======================================================================
120 // function : OpenGl_LightSource
121 // purpose : Creates new light source
122 // =======================================================================
123 OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theDiffuse,
124 const BVH_Vec4f& thePosition)
125 : Diffuse (theDiffuse),
126 Position (thePosition)
131 // =======================================================================
133 // purpose : Returns centroid position along the given axis
134 // =======================================================================
135 Standard_ShortReal OpenGl_TriangleSet::Center (
136 const Standard_Integer theIndex, const Standard_Integer theAxis) const
138 // Note: Experiments show that the use of the box centroid (instead
139 // of the triangle centroid) increases render performance up to 12%
141 const BVH_Vec4i& aTriangle = Elements[theIndex];
143 const Standard_ShortReal aVertex0 =
144 BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.x()], theAxis);
145 const Standard_ShortReal aVertex1 =
146 BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.y()], theAxis);
147 const Standard_ShortReal aVertex2 =
148 BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.z()], theAxis);
150 return (Min (Min (aVertex0, aVertex1), aVertex2) +
151 Max (Max (aVertex0, aVertex1), aVertex2)) * 0.5f;
154 // =======================================================================
156 // purpose : Returns AABB of primitive set
157 // =======================================================================
158 OpenGl_TriangleSet::BVH_BoxNt OpenGl_TriangleSet::Box() const
160 const BVH_Transform<Standard_ShortReal, 4>* aTransform =
161 dynamic_cast<const BVH_Transform<Standard_ShortReal, 4>* > (Properties().operator->());
163 BVH_BoxNt aBox = BVH_PrimitiveSet<Standard_ShortReal, 3>::Box();
165 if (aTransform != NULL)
167 BVH_BoxNt aTransformedBox;
169 for (Standard_Integer aX = 0; aX <= 1; ++aX)
171 for (Standard_Integer aY = 0; aY <= 1; ++aY)
173 for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
175 BVH_Vec4f aCorner = aTransform->Transform() * BVH_Vec4f (
176 aX == 0 ? aBox.CornerMin().x() : aBox.CornerMax().x(),
177 aY == 0 ? aBox.CornerMin().y() : aBox.CornerMax().y(),
178 aZ == 0 ? aBox.CornerMin().z() : aBox.CornerMax().z(),
181 aTransformedBox.Add (reinterpret_cast<BVH_Vec3f&> (aCorner));
186 return aTransformedBox;
192 // =======================================================================
194 // purpose : Clears ray-tracing geometry
195 // =======================================================================
196 void OpenGl_RaytraceGeometry::Clear()
198 BVH_Geometry<Standard_ShortReal, 3>::BVH_Geometry::Clear();
200 std::vector<OpenGl_RaytraceLight,
201 NCollection_StdAllocator<OpenGl_RaytraceLight> > anEmptySources;
203 Sources.swap (anEmptySources);
205 std::vector<OpenGl_RaytraceMaterial,
206 NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
208 Materials.swap (anEmptyMaterials);
213 struct OpenGL_BVHParallelBuilder
215 BVH_ObjectSet<Standard_ShortReal, 3>* Set;
217 OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 3>* theSet)
223 void operator() (const tbb::blocked_range<size_t>& theRange) const
225 for (size_t anObjectIdx = theRange.begin(); anObjectIdx != theRange.end(); ++anObjectIdx)
227 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
228 Set->Objects().ChangeValue (static_cast<Standard_Integer> (anObjectIdx)).operator->());
230 if (aTriangleSet != NULL)
240 // =======================================================================
241 // function : ProcessAcceleration
242 // purpose : Performs post-processing of high-level BVH
243 // =======================================================================
244 Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
246 #ifdef RAY_TRACE_PRINT_INFO
250 MarkDirty(); // force BVH rebuilding
252 #ifdef RAY_TRACE_PRINT_INFO
258 // If Intel TBB is available, perform the preliminary
259 // construction of bottom-level scene BVHs
260 tbb::parallel_for (tbb::blocked_range<size_t> (0, Size()),
261 OpenGL_BVHParallelBuilder (this));
264 myBottomLevelTreeDepth = 0;
266 for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx)
268 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
269 myObjects.ChangeValue (anObjectIdx).operator->());
271 Standard_ASSERT_RETURN (aTriangleSet != NULL,
272 "Error! Failed to get triangulation of OpenGL element", Standard_False);
274 Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(),
275 "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
277 myBottomLevelTreeDepth = Max (myBottomLevelTreeDepth, aTriangleSet->BVH()->Depth());
280 #ifdef RAY_TRACE_PRINT_INFO
283 std::cout << "Updating bottom-level BVHs (sec): " <<
284 aTimer.ElapsedTime() << std::endl;
287 #ifdef RAY_TRACE_PRINT_INFO
292 NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> > aBVH = BVH();
294 #ifdef RAY_TRACE_PRINT_INFO
297 std::cout << "Updating high-level BVH (sec): " <<
298 aTimer.ElapsedTime() << std::endl;
301 Standard_ASSERT_RETURN (!aBVH.IsNull(),
302 "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False);
304 myHighLevelTreeDepth = aBVH->Depth();
306 Standard_Integer aVerticesOffset = 0;
307 Standard_Integer aElementsOffset = 0;
308 Standard_Integer aBVHNodesOffset = BVH()->Length();
310 for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
312 if (!aBVH->IsOuter (aNodeIdx))
315 Standard_ASSERT_RETURN (aBVH->BegPrimitive (aNodeIdx) == aBVH->EndPrimitive (aNodeIdx),
316 "Error! Invalid leaf node in high-level BVH (contains several objects)", Standard_False);
318 Standard_Integer anObjectIdx = aBVH->BegPrimitive (aNodeIdx);
320 Standard_ASSERT_RETURN (anObjectIdx < myObjects.Size(),
321 "Error! Invalid leaf node in high-level BVH (contains out-of-range object)", Standard_False);
323 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
324 myObjects.ChangeValue (anObjectIdx).operator->());
326 // Note: We overwrite node info record to store parameters
327 // of bottom-level BVH and triangulation of OpenGL element
329 aBVH->NodeInfoBuffer().at (aNodeIdx) = BVH_Vec4i (
330 anObjectIdx + 1 /* to keep leaf flag */, aBVHNodesOffset, aVerticesOffset, aElementsOffset);
332 aVerticesOffset += (int)aTriangleSet->Vertices.size();
333 aElementsOffset += (int)aTriangleSet->Elements.size();
334 aBVHNodesOffset += aTriangleSet->BVH()->Length();
337 return Standard_True;
340 // =======================================================================
341 // function : AccelerationOffset
342 // purpose : Returns offset of bottom-level BVH for given leaf node
343 // =======================================================================
344 Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer theNodeIdx)
346 const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
348 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
349 return INVALID_OFFSET;
351 return aBVH->NodeInfoBuffer().at (theNodeIdx).y();
354 // =======================================================================
355 // function : VerticesOffset
356 // purpose : Returns offset of triangulation vertices for given leaf node
357 // =======================================================================
358 Standard_Integer OpenGl_RaytraceGeometry::VerticesOffset (Standard_Integer theNodeIdx)
360 const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
362 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
363 return INVALID_OFFSET;
365 return aBVH->NodeInfoBuffer().at (theNodeIdx).z();
368 // =======================================================================
369 // function : ElementsOffset
370 // purpose : Returns offset of triangulation elements for given leaf node
371 // =======================================================================
372 Standard_Integer OpenGl_RaytraceGeometry::ElementsOffset (Standard_Integer theNodeIdx)
374 const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
376 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
377 return INVALID_OFFSET;
379 return aBVH->NodeInfoBuffer().at (theNodeIdx).w();
382 // =======================================================================
383 // function : TriangleSet
384 // purpose : Returns triangulation data for given leaf node
385 // =======================================================================
386 OpenGl_TriangleSet* OpenGl_RaytraceGeometry::TriangleSet (Standard_Integer theNodeIdx)
388 const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
390 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
393 if (aBVH->NodeInfoBuffer().at (theNodeIdx).x() > myObjects.Size())
396 return dynamic_cast<OpenGl_TriangleSet*> (myObjects.ChangeValue (
397 aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).operator->());
400 // =======================================================================
401 // function : AcquireTextures
402 // purpose : Makes the OpenGL texture handles resident
403 // =======================================================================
404 Standard_Boolean OpenGl_RaytraceGeometry::AcquireTextures (const Handle(OpenGl_Context)& theContext) const
406 if (theContext->arbTexBindless == NULL)
408 return Standard_True;
411 #if !defined(GL_ES_VERSION_2_0)
412 for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
414 theContext->arbTexBindless->glMakeTextureHandleResidentARB (myTextureHandles[anIdx]);
416 if (glGetError() != GL_NO_ERROR)
418 #ifdef RAY_TRACE_PRINT_INFO
419 std::cout << "Error: Failed to make OpenGL texture resident" << std::endl;
421 return Standard_False;
426 return Standard_True;
429 // =======================================================================
430 // function : ReleaseTextures
431 // purpose : Makes the OpenGL texture handles non-resident
432 // =======================================================================
433 Standard_Boolean OpenGl_RaytraceGeometry::ReleaseTextures (const Handle(OpenGl_Context)& theContext) const
435 if (theContext->arbTexBindless == NULL)
437 return Standard_True;
440 #if !defined(GL_ES_VERSION_2_0)
441 for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
443 theContext->arbTexBindless->glMakeTextureHandleNonResidentARB (myTextureHandles[anIdx]);
445 if (glGetError() != GL_NO_ERROR)
447 #ifdef RAY_TRACE_PRINT_INFO
448 std::cout << "Error: Failed to make OpenGL texture non-resident" << std::endl;
450 return Standard_False;
455 return Standard_True;
458 // =======================================================================
459 // function : AddTexture
460 // purpose : Adds new OpenGL texture to the scene and returns its index
461 // =======================================================================
462 Standard_Integer OpenGl_RaytraceGeometry::AddTexture (const Handle(OpenGl_Texture)& theTexture)
464 NCollection_Vector<Handle (OpenGl_Texture)>::iterator anIter =
465 std::find (myTextures.begin(), myTextures.end(), theTexture);
467 if (anIter == myTextures.end())
469 if (myTextures.Size() >= MAX_TEX_NUMBER)
474 myTextures.Append (theTexture);
477 return static_cast<Standard_Integer> (anIter - myTextures.begin());
480 // =======================================================================
481 // function : UpdateTextureHandles
482 // purpose : Updates unique 64-bit texture handles to use in shaders
483 // =======================================================================
484 Standard_Boolean OpenGl_RaytraceGeometry::UpdateTextureHandles (const Handle(OpenGl_Context)& theContext)
486 if (theContext->arbTexBindless == NULL)
488 return Standard_False;
491 myTextureHandles.clear();
493 #if !defined(GL_ES_VERSION_2_0)
494 for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
496 const GLuint64 aHandle = theContext->arbTexBindless->glGetTextureHandleARB (
497 myTextures.Value (anIdx)->TextureId());
499 if (glGetError() != GL_NO_ERROR)
501 #ifdef RAY_TRACE_PRINT_INFO
502 std::cout << "Error: Failed to get 64-bit handle of OpenGL texture" << std::endl;
504 return Standard_False;
507 myTextureHandles.push_back (aHandle);
511 return Standard_True;
514 namespace OpenGl_Raytrace
516 // =======================================================================
517 // function : IsRaytracedElement
518 // purpose : Checks to see if the element contains ray-trace geometry
519 // =======================================================================
520 Standard_Boolean IsRaytracedElement (const OpenGl_ElementNode* theNode)
522 OpenGl_PrimitiveArray* anArray = dynamic_cast<OpenGl_PrimitiveArray*> (theNode->elem);
523 return anArray != NULL
524 && anArray->DrawMode() >= GL_TRIANGLES;
527 // =======================================================================
528 // function : IsRaytracedElement
529 // purpose : Checks to see if the element contains ray-trace geometry
530 // =======================================================================
531 Standard_Boolean IsRaytracedElement (const OpenGl_Element* theElement)
533 const OpenGl_PrimitiveArray* anArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
534 return anArray != NULL
535 && anArray->DrawMode() >= GL_TRIANGLES;
538 // =======================================================================
539 // function : IsRaytracedGroup
540 // purpose : Checks to see if the group contains ray-trace geometry
541 // =======================================================================
542 Standard_Boolean IsRaytracedGroup (const OpenGl_Group *theGroup)
544 const OpenGl_ElementNode* aNode;
545 for (aNode = theGroup->FirstNode(); aNode != NULL; aNode = aNode->next)
547 if (IsRaytracedElement (aNode))
549 return Standard_True;
552 return Standard_False;
555 // =======================================================================
556 // function : IsRaytracedStructure
557 // purpose : Checks to see if the structure contains ray-trace geometry
558 // =======================================================================
559 Standard_Boolean IsRaytracedStructure (const OpenGl_Structure* theStructure)
561 for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups());
562 aGroupIter.More(); aGroupIter.Next())
564 if (aGroupIter.Value()->IsRaytracable())
565 return Standard_True;
567 for (OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures());
568 anIts.More(); anIts.Next())
570 if (IsRaytracedStructure (anIts.Value()))
571 return Standard_True;
573 return Standard_False;