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 <OSD_Timer.hxx>
17 #include <OSD_Parallel.hxx>
18 #include <Standard_Assert.hxx>
19 #include <OpenGl_ArbTexBindless.hxx>
20 #include <OpenGl_PrimitiveArray.hxx>
21 #include <OpenGl_SceneGeometry.hxx>
22 #include <OpenGl_Structure.hxx>
23 #include <Graphic3d_GraphicDriver.hxx>
25 //! Use this macro to output BVH profiling info
26 // #define RAY_TRACE_PRINT_INFO
30 //! Useful constant for null floating-point 4D vector.
31 static const BVH_Vec4f ZERO_VEC_4F;
34 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_TriangleSet, OpenGl_BVHTriangulation3f)
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& theEmission,
115 const BVH_Vec4f& thePosition)
116 : Emission (theEmission),
117 Position (thePosition)
122 // =======================================================================
123 // function : QuadBVH
124 // purpose : Returns quad BVH (QBVH) tree produced from binary BVH
125 // =======================================================================
126 const QuadBvhHandle& OpenGl_TriangleSet::QuadBVH()
130 Standard_ASSERT_RAISE (!myQuadBVH.IsNull(), "Error! BVH was not collapsed into QBVH");
134 myQuadBVH = BVH()->CollapseToQuadTree(); // build binary BVH and collapse it
136 myBVH->Clear(); // erase binary BVH
142 // =======================================================================
144 // purpose : Returns centroid position along the given axis
145 // =======================================================================
146 Standard_ShortReal OpenGl_TriangleSet::Center (
147 const Standard_Integer theIndex, const Standard_Integer theAxis) const
149 // Note: Experiments show that the use of the box centroid (instead
150 // of the triangle centroid) increases render performance up to 12%
152 const BVH_Vec4i& aTriangle = Elements[theIndex];
154 const Standard_ShortReal aVertex0 =
155 BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.x()], theAxis);
156 const Standard_ShortReal aVertex1 =
157 BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.y()], theAxis);
158 const Standard_ShortReal aVertex2 =
159 BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.z()], theAxis);
161 return (Min (Min (aVertex0, aVertex1), aVertex2) +
162 Max (Max (aVertex0, aVertex1), aVertex2)) * 0.5f;
165 // =======================================================================
167 // purpose : Returns AABB of primitive set
168 // =======================================================================
169 OpenGl_TriangleSet::BVH_BoxNt OpenGl_TriangleSet::Box() const
171 BVH_BoxNt aBox = BVH_PrimitiveSet<Standard_ShortReal, 3>::Box();
172 const BVH_Transform<Standard_ShortReal, 4>* aTransform = dynamic_cast<const BVH_Transform<Standard_ShortReal, 4>* > (Properties().get());
173 if (aTransform == NULL)
178 BVH_BoxNt aTransformedBox;
179 for (Standard_Integer aX = 0; aX <= 1; ++aX)
181 for (Standard_Integer aY = 0; aY <= 1; ++aY)
183 for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
185 BVH_Vec4f aCorner = aTransform->Transform() * BVH_Vec4f (
186 aX == 0 ? aBox.CornerMin().x() : aBox.CornerMax().x(),
187 aY == 0 ? aBox.CornerMin().y() : aBox.CornerMax().y(),
188 aZ == 0 ? aBox.CornerMin().z() : aBox.CornerMax().z(),
191 aTransformedBox.Add (aCorner.xyz());
195 return aTransformedBox;
198 // =======================================================================
199 // function : OpenGl_TriangleSet
200 // purpose : Creates new OpenGL element triangulation
201 // =======================================================================
202 OpenGl_TriangleSet::OpenGl_TriangleSet (const Standard_Size theArrayID,
203 const opencascade::handle<BVH_Builder<Standard_ShortReal, 3> >& theBuilder)
204 : BVH_Triangulation<Standard_ShortReal, 3> (theBuilder),
205 myArrayID (theArrayID)
210 // =======================================================================
212 // purpose : Clears ray-tracing geometry
213 // =======================================================================
214 void OpenGl_RaytraceGeometry::Clear()
216 BVH_Geometry<Standard_ShortReal, 3>::BVH_Geometry::Clear();
218 std::vector<OpenGl_RaytraceLight,
219 NCollection_StdAllocator<OpenGl_RaytraceLight> > anEmptySources;
221 Sources.swap (anEmptySources);
223 std::vector<OpenGl_RaytraceMaterial,
224 NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
226 Materials.swap (anEmptyMaterials);
229 struct OpenGL_BVHParallelBuilder
231 BVH_ObjectSet<Standard_ShortReal, 3>* Set;
233 OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 3>* theSet)
239 void operator() (const Standard_Integer theObjectIdx) const
241 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
242 Set->Objects().ChangeValue (static_cast<Standard_Integer> (theObjectIdx)).operator->());
244 if (aTriangleSet != NULL)
245 aTriangleSet->QuadBVH();
249 // =======================================================================
250 // function : ProcessAcceleration
251 // purpose : Performs post-processing of high-level BVH
252 // =======================================================================
253 Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
255 #ifdef RAY_TRACE_PRINT_INFO
259 MarkDirty(); // force BVH rebuilding
261 #ifdef RAY_TRACE_PRINT_INFO
266 OSD_Parallel::For (0, Size(), OpenGL_BVHParallelBuilder (this));
268 myBotLevelTreeDepth = 1;
270 for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx)
272 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
273 myObjects.ChangeValue (anObjectIdx).operator->());
275 Standard_ASSERT_RETURN (aTriangleSet != NULL,
276 "Error! Failed to get triangulation of OpenGL element", Standard_False);
278 Standard_ASSERT_RETURN (!aTriangleSet->QuadBVH().IsNull(),
279 "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
281 QuadBvhHandle aBVH = aTriangleSet->QuadBVH();
283 // correct data array of bottom-level BVH to set special flag for outer
284 // nodes in order to distinguish them from outer nodes of top-level BVH
285 for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
287 if (aBVH->IsOuter (aNodeIdx))
289 aBVH->NodeInfoBuffer()[aNodeIdx].x() = -1;
293 myBotLevelTreeDepth = Max (myBotLevelTreeDepth, aTriangleSet->QuadBVH()->Depth());
296 #ifdef RAY_TRACE_PRINT_INFO
299 std::cout << "Updating bottom-level BVHs (sec): " <<
300 aTimer.ElapsedTime() << std::endl;
303 #ifdef RAY_TRACE_PRINT_INFO
308 QuadBvhHandle aBVH = QuadBVH();
310 Standard_ASSERT_RETURN (!aBVH.IsNull(),
311 "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False);
313 myTopLevelTreeDepth = aBVH->Depth();
315 #ifdef RAY_TRACE_PRINT_INFO
318 std::cout << "Updating high-level BVH (sec): " <<
319 aTimer.ElapsedTime() << std::endl;
322 Standard_Integer aVerticesOffset = 0;
323 Standard_Integer aElementsOffset = 0;
324 Standard_Integer aBvhNodesOffset = QuadBVH()->Length();
326 for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
328 if (aBVH->IsOuter (aNodeIdx))
330 Standard_ASSERT_RETURN (aBVH->BegPrimitive (aNodeIdx) == aBVH->EndPrimitive (aNodeIdx),
331 "Error! Invalid leaf node in high-level BVH (contains several objects)", Standard_False);
333 const Standard_Integer anObjectIdx = aBVH->BegPrimitive (aNodeIdx);
335 Standard_ASSERT_RETURN (anObjectIdx < myObjects.Size(),
336 "Error! Invalid leaf node in high-level BVH (contains out-of-range object)", Standard_False);
338 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (myObjects (anObjectIdx).get());
340 // Note: We overwrite node info record to store parameters
341 // of bottom-level BVH and triangulation of OpenGL element
343 aBVH->NodeInfoBuffer()[aNodeIdx] = BVH_Vec4i (anObjectIdx + 1, // to keep leaf flag
348 aVerticesOffset += static_cast<Standard_Integer> (aTriangleSet->Vertices.size());
349 aElementsOffset += static_cast<Standard_Integer> (aTriangleSet->Elements.size());
351 aBvhNodesOffset += aTriangleSet->QuadBVH()->Length();
355 return Standard_True;
358 // =======================================================================
359 // function : QuadBVH
360 // purpose : Returns quad BVH (QBVH) tree produced from binary BVH
361 // =======================================================================
362 const QuadBvhHandle& OpenGl_RaytraceGeometry::QuadBVH()
366 Standard_ASSERT_RAISE (!myQuadBVH.IsNull(), "Error! BVH was not collapsed into QBVH");
370 myQuadBVH = BVH()->CollapseToQuadTree(); // build binary BVH and collapse it
372 myBVH->Clear(); // erase binary BVH
378 // =======================================================================
379 // function : AccelerationOffset
380 // purpose : Returns offset of bottom-level BVH for given leaf node
381 // =======================================================================
382 Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer theNodeIdx)
384 const QuadBvhHandle& aBVH = QuadBVH();
386 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
387 return INVALID_OFFSET;
389 return aBVH->NodeInfoBuffer().at (theNodeIdx).y();
392 // =======================================================================
393 // function : VerticesOffset
394 // purpose : Returns offset of triangulation vertices for given leaf node
395 // =======================================================================
396 Standard_Integer OpenGl_RaytraceGeometry::VerticesOffset (Standard_Integer theNodeIdx)
398 const QuadBvhHandle& aBVH = QuadBVH();
400 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
401 return INVALID_OFFSET;
403 return aBVH->NodeInfoBuffer().at (theNodeIdx).z();
406 // =======================================================================
407 // function : ElementsOffset
408 // purpose : Returns offset of triangulation elements for given leaf node
409 // =======================================================================
410 Standard_Integer OpenGl_RaytraceGeometry::ElementsOffset (Standard_Integer theNodeIdx)
412 const QuadBvhHandle& aBVH = QuadBVH();
414 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
415 return INVALID_OFFSET;
417 return aBVH->NodeInfoBuffer().at (theNodeIdx).w();
420 // =======================================================================
421 // function : TriangleSet
422 // purpose : Returns triangulation data for given leaf node
423 // =======================================================================
424 OpenGl_TriangleSet* OpenGl_RaytraceGeometry::TriangleSet (Standard_Integer theNodeIdx)
426 const QuadBvhHandle& aBVH = QuadBVH();
428 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
431 if (aBVH->NodeInfoBuffer().at (theNodeIdx).x() > myObjects.Size())
434 return dynamic_cast<OpenGl_TriangleSet*> (
435 myObjects (aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).get());
438 // =======================================================================
439 // function : AcquireTextures
440 // purpose : Makes the OpenGL texture handles resident
441 // =======================================================================
442 Standard_Boolean OpenGl_RaytraceGeometry::AcquireTextures (const Handle(OpenGl_Context)& theContext)
444 if (theContext->arbTexBindless == NULL)
446 return Standard_True;
449 #if !defined(GL_ES_VERSION_2_0)
450 Standard_Integer aTexIter = 0;
451 for (NCollection_Vector<Handle(OpenGl_Texture)>::Iterator aTexSrcIter (myTextures); aTexSrcIter.More(); aTexSrcIter.Next(), ++aTexIter)
453 GLuint64& aHandle = myTextureHandles[aTexIter];
454 const Handle(OpenGl_Texture)& aTexture = aTexSrcIter.Value();
455 if (!aTexture->Sampler()->IsValid()
456 || !aTexture->Sampler()->IsImmutable())
458 // need to recreate texture sampler handle
459 aHandle = GLuint64(-1); // specs do not define value for invalid handle, set -1 to initialize something
460 if (!aTexture->InitSamplerObject (theContext))
465 aTexture->Sampler()->SetImmutable();
466 aHandle = theContext->arbTexBindless->glGetTextureSamplerHandleARB (aTexture->TextureId(), aTexture->Sampler()->SamplerID());
467 const GLenum anErr = glGetError();
468 if (anErr != GL_NO_ERROR)
470 theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
471 TCollection_AsciiString ("Error: Failed to get 64-bit handle of OpenGL texture #") + int(anErr));
472 myTextureHandles.clear();
473 return Standard_False;
477 theContext->arbTexBindless->glMakeTextureHandleResidentARB (aHandle);
478 const GLenum anErr = glGetError();
479 if (anErr != GL_NO_ERROR)
481 theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
482 TCollection_AsciiString ("Error: Failed to make OpenGL texture resident #") + int(anErr));
483 return Standard_False;
488 return Standard_True;
491 // =======================================================================
492 // function : ReleaseTextures
493 // purpose : Makes the OpenGL texture handles non-resident
494 // =======================================================================
495 Standard_Boolean OpenGl_RaytraceGeometry::ReleaseTextures (const Handle(OpenGl_Context)& theContext) const
497 if (theContext->arbTexBindless == NULL)
499 return Standard_True;
502 #if !defined(GL_ES_VERSION_2_0)
503 for (size_t aTexIter = 0; aTexIter < myTextureHandles.size(); ++aTexIter)
505 theContext->arbTexBindless->glMakeTextureHandleNonResidentARB (myTextureHandles[aTexIter]);
506 const GLenum anErr = glGetError();
507 if (anErr != GL_NO_ERROR)
509 theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
510 TCollection_AsciiString("Error: Failed to make OpenGL texture non-resident #") + int(anErr));
511 return Standard_False;
516 return Standard_True;
519 // =======================================================================
520 // function : AddTexture
521 // purpose : Adds new OpenGL texture to the scene and returns its index
522 // =======================================================================
523 Standard_Integer OpenGl_RaytraceGeometry::AddTexture (const Handle(OpenGl_Texture)& theTexture)
525 if (theTexture->TextureId() == OpenGl_Texture::NO_TEXTURE)
530 NCollection_Vector<Handle (OpenGl_Texture)>::iterator anIter =
531 std::find (myTextures.begin(), myTextures.end(), theTexture);
533 if (anIter == myTextures.end())
535 if (myTextures.Size() >= MAX_TEX_NUMBER)
540 myTextures.Append (theTexture);
543 return static_cast<Standard_Integer> (anIter - myTextures.begin());
546 // =======================================================================
547 // function : UpdateTextureHandles
548 // purpose : Updates unique 64-bit texture handles to use in shaders
549 // =======================================================================
550 Standard_Boolean OpenGl_RaytraceGeometry::UpdateTextureHandles (const Handle(OpenGl_Context)& theContext)
552 if (theContext->arbTexBindless == NULL)
554 return Standard_False;
557 myTextureHandles.clear();
558 myTextureHandles.resize (myTextures.Size());
560 #if !defined(GL_ES_VERSION_2_0)
561 Standard_Integer aTexIter = 0;
562 for (NCollection_Vector<Handle(OpenGl_Texture)>::Iterator aTexSrcIter (myTextures); aTexSrcIter.More(); aTexSrcIter.Next(), ++aTexIter)
564 GLuint64& aHandle = myTextureHandles[aTexIter];
565 aHandle = GLuint64(-1); // specs do not define value for invalid handle, set -1 to initialize something
567 const Handle(OpenGl_Texture)& aTexture = aTexSrcIter.Value();
568 if (!aTexture->Sampler()->IsValid()
569 && !aTexture->InitSamplerObject (theContext))
574 aTexture->Sampler()->SetImmutable();
575 aHandle = theContext->arbTexBindless->glGetTextureSamplerHandleARB (aTexture->TextureId(), aTexture->Sampler()->SamplerID());
576 const GLenum anErr = glGetError();
577 if (anErr != GL_NO_ERROR)
579 theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
580 TCollection_AsciiString ("Error: Failed to get 64-bit handle of OpenGL texture #") + int(anErr));
581 myTextureHandles.clear();
582 return Standard_False;
587 return Standard_True;
590 namespace OpenGl_Raytrace
592 // =======================================================================
593 // function : IsRaytracedElement
594 // purpose : Checks to see if the element contains ray-trace geometry
595 // =======================================================================
596 Standard_Boolean IsRaytracedElement (const OpenGl_ElementNode* theNode)
598 OpenGl_PrimitiveArray* anArray = dynamic_cast<OpenGl_PrimitiveArray*> (theNode->elem);
599 return anArray != NULL
600 && anArray->DrawMode() >= GL_TRIANGLES;
603 // =======================================================================
604 // function : IsRaytracedElement
605 // purpose : Checks to see if the element contains ray-trace geometry
606 // =======================================================================
607 Standard_Boolean IsRaytracedElement (const OpenGl_Element* theElement)
609 const OpenGl_PrimitiveArray* anArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
610 return anArray != NULL
611 && anArray->DrawMode() >= GL_TRIANGLES;
614 // =======================================================================
615 // function : IsRaytracedGroup
616 // purpose : Checks to see if the group contains ray-trace geometry
617 // =======================================================================
618 Standard_Boolean IsRaytracedGroup (const OpenGl_Group* theGroup)
620 for (const OpenGl_ElementNode* aNode = theGroup->FirstNode(); aNode != NULL; aNode = aNode->next)
622 if (IsRaytracedElement (aNode))
624 return Standard_True;
627 return Standard_False;