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.
16 #include <Standard_Assert.hxx>
17 #include <OSD_Parallel.hxx>
19 #include <OpenGl_SceneGeometry.hxx>
21 #include <OpenGl_ArbTexBindless.hxx>
22 #include <OpenGl_PrimitiveArray.hxx>
23 #include <OpenGl_Structure.hxx>
24 #include <OSD_Timer.hxx>
25 #include <Standard_Assert.hxx>
27 //! Use this macro to output BVH profiling info
28 // #define RAY_TRACE_PRINT_INFO
32 //! Useful constant for null floating-point 4D vector.
33 static const BVH_Vec4f ZERO_VEC_4F;
36 // =======================================================================
37 // function : OpenGl_RaytraceMaterial
38 // purpose : Creates new default material
39 // =======================================================================
40 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial()
41 : Ambient (ZERO_VEC_4F),
42 Diffuse (ZERO_VEC_4F),
43 Specular (ZERO_VEC_4F),
44 Emission (ZERO_VEC_4F),
45 Reflection (ZERO_VEC_4F),
46 Refraction (ZERO_VEC_4F),
47 Transparency (ZERO_VEC_4F)
50 // =======================================================================
51 // function : OpenGl_RaytraceMaterial
52 // purpose : Creates new material with specified properties
53 // =======================================================================
54 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
55 const BVH_Vec4f& theDiffuse,
56 const BVH_Vec4f& theSpecular)
57 : Ambient (theAmbient),
59 Specular (theSpecular),
60 Emission (ZERO_VEC_4F),
61 Reflection (ZERO_VEC_4F),
62 Refraction (ZERO_VEC_4F),
63 Transparency (ZERO_VEC_4F)
68 // =======================================================================
69 // function : OpenGl_RaytraceMaterial
70 // purpose : Creates new material with specified properties
71 // =======================================================================
72 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
73 const BVH_Vec4f& theDiffuse,
74 const BVH_Vec4f& theSpecular,
75 const BVH_Vec4f& theEmission,
76 const BVH_Vec4f& theTranspar)
77 : Ambient (theAmbient),
79 Specular (theSpecular),
80 Emission (theEmission),
81 Reflection (ZERO_VEC_4F),
82 Refraction (ZERO_VEC_4F),
83 Transparency (theTranspar)
88 // =======================================================================
89 // function : OpenGl_RaytraceMaterial
90 // purpose : Creates new material with specified properties
91 // =======================================================================
92 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
93 const BVH_Vec4f& theDiffuse,
94 const BVH_Vec4f& theSpecular,
95 const BVH_Vec4f& theEmission,
96 const BVH_Vec4f& theTranspar,
97 const BVH_Vec4f& theReflection,
98 const BVH_Vec4f& theRefraction)
99 : Ambient (theAmbient),
100 Diffuse (theDiffuse),
101 Specular (theSpecular),
102 Emission (theEmission),
103 Reflection (theReflection),
104 Refraction (theRefraction),
105 Transparency (theTranspar)
110 // =======================================================================
111 // function : OpenGl_LightSource
112 // purpose : Creates new light source
113 // =======================================================================
114 OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theDiffuse,
115 const BVH_Vec4f& thePosition)
116 : Diffuse (theDiffuse),
117 Position (thePosition)
122 // =======================================================================
124 // purpose : Returns centroid position along the given axis
125 // =======================================================================
126 Standard_ShortReal OpenGl_TriangleSet::Center (
127 const Standard_Integer theIndex, const Standard_Integer theAxis) const
129 // Note: Experiments show that the use of the box centroid (instead
130 // of the triangle centroid) increases render performance up to 12%
132 const BVH_Vec4i& aTriangle = Elements[theIndex];
134 const Standard_ShortReal aVertex0 =
135 BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.x()], theAxis);
136 const Standard_ShortReal aVertex1 =
137 BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.y()], theAxis);
138 const Standard_ShortReal aVertex2 =
139 BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.z()], theAxis);
141 return (Min (Min (aVertex0, aVertex1), aVertex2) +
142 Max (Max (aVertex0, aVertex1), aVertex2)) * 0.5f;
145 // =======================================================================
147 // purpose : Returns AABB of primitive set
148 // =======================================================================
149 OpenGl_TriangleSet::BVH_BoxNt OpenGl_TriangleSet::Box() const
151 const BVH_Transform<Standard_ShortReal, 4>* aTransform =
152 dynamic_cast<const BVH_Transform<Standard_ShortReal, 4>* > (Properties().operator->());
154 BVH_BoxNt aBox = BVH_PrimitiveSet<Standard_ShortReal, 3>::Box();
156 if (aTransform != NULL)
158 BVH_BoxNt aTransformedBox;
160 for (Standard_Integer aX = 0; aX <= 1; ++aX)
162 for (Standard_Integer aY = 0; aY <= 1; ++aY)
164 for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
166 BVH_Vec4f aCorner = aTransform->Transform() * BVH_Vec4f (
167 aX == 0 ? aBox.CornerMin().x() : aBox.CornerMax().x(),
168 aY == 0 ? aBox.CornerMin().y() : aBox.CornerMax().y(),
169 aZ == 0 ? aBox.CornerMin().z() : aBox.CornerMax().z(),
172 aTransformedBox.Add (reinterpret_cast<BVH_Vec3f&> (aCorner));
177 return aTransformedBox;
183 // =======================================================================
185 // purpose : Clears ray-tracing geometry
186 // =======================================================================
187 void OpenGl_RaytraceGeometry::Clear()
189 BVH_Geometry<Standard_ShortReal, 3>::BVH_Geometry::Clear();
191 std::vector<OpenGl_RaytraceLight,
192 NCollection_StdAllocator<OpenGl_RaytraceLight> > anEmptySources;
194 Sources.swap (anEmptySources);
196 std::vector<OpenGl_RaytraceMaterial,
197 NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
199 Materials.swap (anEmptyMaterials);
202 struct OpenGL_BVHParallelBuilder
204 BVH_ObjectSet<Standard_ShortReal, 3>* Set;
206 OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 3>* theSet)
212 void operator() (const Standard_Integer theObjectIdx) const
214 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
215 Set->Objects().ChangeValue (static_cast<Standard_Integer> (theObjectIdx)).operator->());
217 if (aTriangleSet != NULL)
222 // =======================================================================
223 // function : ProcessAcceleration
224 // purpose : Performs post-processing of high-level BVH
225 // =======================================================================
226 Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
228 #ifdef RAY_TRACE_PRINT_INFO
232 MarkDirty(); // force BVH rebuilding
234 #ifdef RAY_TRACE_PRINT_INFO
239 OSD_Parallel::For(0, Size(), OpenGL_BVHParallelBuilder(this));
241 myBottomLevelTreeDepth = 0;
243 for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx)
245 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
246 myObjects.ChangeValue (anObjectIdx).operator->());
248 Standard_ASSERT_RETURN (aTriangleSet != NULL,
249 "Error! Failed to get triangulation of OpenGL element", Standard_False);
251 Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(),
252 "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
254 myBottomLevelTreeDepth = Max (myBottomLevelTreeDepth, aTriangleSet->BVH()->Depth());
257 #ifdef RAY_TRACE_PRINT_INFO
260 std::cout << "Updating bottom-level BVHs (sec): " <<
261 aTimer.ElapsedTime() << std::endl;
264 #ifdef RAY_TRACE_PRINT_INFO
269 NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> > aBVH = BVH();
271 #ifdef RAY_TRACE_PRINT_INFO
274 std::cout << "Updating high-level BVH (sec): " <<
275 aTimer.ElapsedTime() << std::endl;
278 Standard_ASSERT_RETURN (!aBVH.IsNull(),
279 "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False);
281 myHighLevelTreeDepth = aBVH->Depth();
283 Standard_Integer aVerticesOffset = 0;
284 Standard_Integer aElementsOffset = 0;
285 Standard_Integer aBVHNodesOffset = BVH()->Length();
287 for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
289 if (!aBVH->IsOuter (aNodeIdx))
292 Standard_ASSERT_RETURN (aBVH->BegPrimitive (aNodeIdx) == aBVH->EndPrimitive (aNodeIdx),
293 "Error! Invalid leaf node in high-level BVH (contains several objects)", Standard_False);
295 Standard_Integer anObjectIdx = aBVH->BegPrimitive (aNodeIdx);
297 Standard_ASSERT_RETURN (anObjectIdx < myObjects.Size(),
298 "Error! Invalid leaf node in high-level BVH (contains out-of-range object)", Standard_False);
300 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
301 myObjects.ChangeValue (anObjectIdx).operator->());
303 // Note: We overwrite node info record to store parameters
304 // of bottom-level BVH and triangulation of OpenGL element
306 aBVH->NodeInfoBuffer().at (aNodeIdx) = BVH_Vec4i (
307 anObjectIdx + 1 /* to keep leaf flag */, aBVHNodesOffset, aVerticesOffset, aElementsOffset);
309 aVerticesOffset += (int)aTriangleSet->Vertices.size();
310 aElementsOffset += (int)aTriangleSet->Elements.size();
311 aBVHNodesOffset += aTriangleSet->BVH()->Length();
314 return Standard_True;
317 // =======================================================================
318 // function : AccelerationOffset
319 // purpose : Returns offset of bottom-level BVH for given leaf node
320 // =======================================================================
321 Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer theNodeIdx)
323 const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
325 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
326 return INVALID_OFFSET;
328 return aBVH->NodeInfoBuffer().at (theNodeIdx).y();
331 // =======================================================================
332 // function : VerticesOffset
333 // purpose : Returns offset of triangulation vertices for given leaf node
334 // =======================================================================
335 Standard_Integer OpenGl_RaytraceGeometry::VerticesOffset (Standard_Integer theNodeIdx)
337 const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
339 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
340 return INVALID_OFFSET;
342 return aBVH->NodeInfoBuffer().at (theNodeIdx).z();
345 // =======================================================================
346 // function : ElementsOffset
347 // purpose : Returns offset of triangulation elements for given leaf node
348 // =======================================================================
349 Standard_Integer OpenGl_RaytraceGeometry::ElementsOffset (Standard_Integer theNodeIdx)
351 const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
353 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
354 return INVALID_OFFSET;
356 return aBVH->NodeInfoBuffer().at (theNodeIdx).w();
359 // =======================================================================
360 // function : TriangleSet
361 // purpose : Returns triangulation data for given leaf node
362 // =======================================================================
363 OpenGl_TriangleSet* OpenGl_RaytraceGeometry::TriangleSet (Standard_Integer theNodeIdx)
365 const NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> >& aBVH = BVH();
367 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
370 if (aBVH->NodeInfoBuffer().at (theNodeIdx).x() > myObjects.Size())
373 return dynamic_cast<OpenGl_TriangleSet*> (myObjects.ChangeValue (
374 aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).operator->());
377 // =======================================================================
378 // function : AcquireTextures
379 // purpose : Makes the OpenGL texture handles resident
380 // =======================================================================
381 Standard_Boolean OpenGl_RaytraceGeometry::AcquireTextures (const Handle(OpenGl_Context)& theContext) const
383 if (theContext->arbTexBindless == NULL)
385 return Standard_True;
388 #if !defined(GL_ES_VERSION_2_0)
389 for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
391 theContext->arbTexBindless->glMakeTextureHandleResidentARB (myTextureHandles[anIdx]);
393 if (glGetError() != GL_NO_ERROR)
395 #ifdef RAY_TRACE_PRINT_INFO
396 std::cout << "Error: Failed to make OpenGL texture resident" << std::endl;
398 return Standard_False;
403 return Standard_True;
406 // =======================================================================
407 // function : ReleaseTextures
408 // purpose : Makes the OpenGL texture handles non-resident
409 // =======================================================================
410 Standard_Boolean OpenGl_RaytraceGeometry::ReleaseTextures (const Handle(OpenGl_Context)& theContext) const
412 if (theContext->arbTexBindless == NULL)
414 return Standard_True;
417 #if !defined(GL_ES_VERSION_2_0)
418 for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
420 theContext->arbTexBindless->glMakeTextureHandleNonResidentARB (myTextureHandles[anIdx]);
422 if (glGetError() != GL_NO_ERROR)
424 #ifdef RAY_TRACE_PRINT_INFO
425 std::cout << "Error: Failed to make OpenGL texture non-resident" << std::endl;
427 return Standard_False;
432 return Standard_True;
435 // =======================================================================
436 // function : AddTexture
437 // purpose : Adds new OpenGL texture to the scene and returns its index
438 // =======================================================================
439 Standard_Integer OpenGl_RaytraceGeometry::AddTexture (const Handle(OpenGl_Texture)& theTexture)
441 NCollection_Vector<Handle (OpenGl_Texture)>::iterator anIter =
442 std::find (myTextures.begin(), myTextures.end(), theTexture);
444 if (anIter == myTextures.end())
446 if (myTextures.Size() >= MAX_TEX_NUMBER)
451 myTextures.Append (theTexture);
454 return static_cast<Standard_Integer> (anIter - myTextures.begin());
457 // =======================================================================
458 // function : UpdateTextureHandles
459 // purpose : Updates unique 64-bit texture handles to use in shaders
460 // =======================================================================
461 Standard_Boolean OpenGl_RaytraceGeometry::UpdateTextureHandles (const Handle(OpenGl_Context)& theContext)
463 if (theContext->arbTexBindless == NULL)
465 return Standard_False;
468 myTextureHandles.clear();
470 #if !defined(GL_ES_VERSION_2_0)
471 for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
473 const GLuint64 aHandle = theContext->arbTexBindless->glGetTextureHandleARB (
474 myTextures.Value (anIdx)->TextureId());
476 if (glGetError() != GL_NO_ERROR)
478 #ifdef RAY_TRACE_PRINT_INFO
479 std::cout << "Error: Failed to get 64-bit handle of OpenGL texture" << std::endl;
481 return Standard_False;
484 myTextureHandles.push_back (aHandle);
488 return Standard_True;
491 namespace OpenGl_Raytrace
493 // =======================================================================
494 // function : IsRaytracedElement
495 // purpose : Checks to see if the element contains ray-trace geometry
496 // =======================================================================
497 Standard_Boolean IsRaytracedElement (const OpenGl_ElementNode* theNode)
499 OpenGl_PrimitiveArray* anArray = dynamic_cast<OpenGl_PrimitiveArray*> (theNode->elem);
500 return anArray != NULL
501 && anArray->DrawMode() >= GL_TRIANGLES;
504 // =======================================================================
505 // function : IsRaytracedElement
506 // purpose : Checks to see if the element contains ray-trace geometry
507 // =======================================================================
508 Standard_Boolean IsRaytracedElement (const OpenGl_Element* theElement)
510 const OpenGl_PrimitiveArray* anArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
511 return anArray != NULL
512 && anArray->DrawMode() >= GL_TRIANGLES;
515 // =======================================================================
516 // function : IsRaytracedGroup
517 // purpose : Checks to see if the group contains ray-trace geometry
518 // =======================================================================
519 Standard_Boolean IsRaytracedGroup (const OpenGl_Group* theGroup)
521 for (const OpenGl_ElementNode* aNode = theGroup->FirstNode(); aNode != NULL; aNode = aNode->next)
523 if (IsRaytracedElement (aNode))
525 return Standard_True;
528 return Standard_False;
531 // =======================================================================
532 // function : IsRaytracedStructure
533 // purpose : Checks to see if the structure contains ray-trace geometry
534 // =======================================================================
535 Standard_Boolean IsRaytracedStructure (const OpenGl_Structure* theStructure)
537 for (OpenGl_Structure::GroupIterator anIter (theStructure->DrawGroups()); anIter.More(); anIter.Next())
539 if (anIter.Value()->IsRaytracable())
541 return Standard_True;
544 return Standard_False;