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 // =======================================================================
35 // function : OpenGl_RaytraceMaterial
36 // purpose : Creates new default material
37 // =======================================================================
38 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial()
39 : Ambient (ZERO_VEC_4F),
40 Diffuse (ZERO_VEC_4F),
41 Specular (ZERO_VEC_4F),
42 Emission (ZERO_VEC_4F),
43 Reflection (ZERO_VEC_4F),
44 Refraction (ZERO_VEC_4F),
45 Transparency (ZERO_VEC_4F)
48 // =======================================================================
49 // function : OpenGl_RaytraceMaterial
50 // purpose : Creates new material with specified properties
51 // =======================================================================
52 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
53 const BVH_Vec4f& theDiffuse,
54 const BVH_Vec4f& theSpecular)
55 : Ambient (theAmbient),
57 Specular (theSpecular),
58 Emission (ZERO_VEC_4F),
59 Reflection (ZERO_VEC_4F),
60 Refraction (ZERO_VEC_4F),
61 Transparency (ZERO_VEC_4F)
66 // =======================================================================
67 // function : OpenGl_RaytraceMaterial
68 // purpose : Creates new material with specified properties
69 // =======================================================================
70 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
71 const BVH_Vec4f& theDiffuse,
72 const BVH_Vec4f& theSpecular,
73 const BVH_Vec4f& theEmission,
74 const BVH_Vec4f& theTranspar)
75 : Ambient (theAmbient),
77 Specular (theSpecular),
78 Emission (theEmission),
79 Reflection (ZERO_VEC_4F),
80 Refraction (ZERO_VEC_4F),
81 Transparency (theTranspar)
86 // =======================================================================
87 // function : OpenGl_RaytraceMaterial
88 // purpose : Creates new material with specified properties
89 // =======================================================================
90 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
91 const BVH_Vec4f& theDiffuse,
92 const BVH_Vec4f& theSpecular,
93 const BVH_Vec4f& theEmission,
94 const BVH_Vec4f& theTranspar,
95 const BVH_Vec4f& theReflection,
96 const BVH_Vec4f& theRefraction)
97 : Ambient (theAmbient),
99 Specular (theSpecular),
100 Emission (theEmission),
101 Reflection (theReflection),
102 Refraction (theRefraction),
103 Transparency (theTranspar)
108 // =======================================================================
109 // function : OpenGl_LightSource
110 // purpose : Creates new light source
111 // =======================================================================
112 OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theDiffuse,
113 const BVH_Vec4f& thePosition)
114 : Diffuse (theDiffuse),
115 Position (thePosition)
120 // =======================================================================
121 // function : QuadBVH
122 // purpose : Returns quad BVH (QBVH) tree produced from binary BVH
123 // =======================================================================
124 const QuadBvhHandle& OpenGl_TriangleSet::QuadBVH()
128 Standard_ASSERT_RAISE (!myQuadBVH.IsNull(), "Error! BVH was not collapsed into QBVH");
132 myQuadBVH = BVH()->CollapseToQuadTree(); // build binary BVH and collapse it
134 myBVH->Clear(); // erase binary BVH
140 // =======================================================================
142 // purpose : Returns centroid position along the given axis
143 // =======================================================================
144 Standard_ShortReal OpenGl_TriangleSet::Center (
145 const Standard_Integer theIndex, const Standard_Integer theAxis) const
147 // Note: Experiments show that the use of the box centroid (instead
148 // of the triangle centroid) increases render performance up to 12%
150 const BVH_Vec4i& aTriangle = Elements[theIndex];
152 const Standard_ShortReal aVertex0 =
153 BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.x()], theAxis);
154 const Standard_ShortReal aVertex1 =
155 BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.y()], theAxis);
156 const Standard_ShortReal aVertex2 =
157 BVH::VecComp<Standard_ShortReal, 3>::Get (Vertices[aTriangle.z()], theAxis);
159 return (Min (Min (aVertex0, aVertex1), aVertex2) +
160 Max (Max (aVertex0, aVertex1), aVertex2)) * 0.5f;
163 // =======================================================================
165 // purpose : Returns AABB of primitive set
166 // =======================================================================
167 OpenGl_TriangleSet::BVH_BoxNt OpenGl_TriangleSet::Box() const
169 const BVH_Transform<Standard_ShortReal, 4>* aTransform =
170 dynamic_cast<const BVH_Transform<Standard_ShortReal, 4>* > (Properties().operator->());
172 BVH_BoxNt aBox = BVH_PrimitiveSet<Standard_ShortReal, 3>::Box();
174 if (aTransform != NULL)
176 BVH_BoxNt aTransformedBox;
178 for (Standard_Integer aX = 0; aX <= 1; ++aX)
180 for (Standard_Integer aY = 0; aY <= 1; ++aY)
182 for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
184 BVH_Vec4f aCorner = aTransform->Transform() * BVH_Vec4f (
185 aX == 0 ? aBox.CornerMin().x() : aBox.CornerMax().x(),
186 aY == 0 ? aBox.CornerMin().y() : aBox.CornerMax().y(),
187 aZ == 0 ? aBox.CornerMin().z() : aBox.CornerMax().z(),
190 aTransformedBox.Add (aCorner.xyz());
195 return aTransformedBox;
201 // =======================================================================
202 // function : OpenGl_TriangleSet
203 // purpose : Creates new OpenGL element triangulation
204 // =======================================================================
205 OpenGl_TriangleSet::OpenGl_TriangleSet (const Standard_Size theArrayID)
206 : BVH_Triangulation<Standard_ShortReal, 3>(),
207 myArrayID (theArrayID)
209 myBuilder = new BVH_BinnedBuilder<Standard_ShortReal, 3 /* dim */, 48 /* bins */>
210 (5 /* leaf size */, 32 /* max height */, Standard_False, OSD_Parallel::NbLogicalProcessors() + 1 /* threads */);
213 // =======================================================================
215 // purpose : Clears ray-tracing geometry
216 // =======================================================================
217 void OpenGl_RaytraceGeometry::Clear()
219 BVH_Geometry<Standard_ShortReal, 3>::BVH_Geometry::Clear();
221 std::vector<OpenGl_RaytraceLight,
222 NCollection_StdAllocator<OpenGl_RaytraceLight> > anEmptySources;
224 Sources.swap (anEmptySources);
226 std::vector<OpenGl_RaytraceMaterial,
227 NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
229 Materials.swap (anEmptyMaterials);
232 struct OpenGL_BVHParallelBuilder
234 BVH_ObjectSet<Standard_ShortReal, 3>* Set;
236 OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 3>* theSet)
242 void operator() (const Standard_Integer theObjectIdx) const
244 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
245 Set->Objects().ChangeValue (static_cast<Standard_Integer> (theObjectIdx)).operator->());
247 if (aTriangleSet != NULL)
248 aTriangleSet->QuadBVH();
252 // =======================================================================
253 // function : ProcessAcceleration
254 // purpose : Performs post-processing of high-level BVH
255 // =======================================================================
256 Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
258 #ifdef RAY_TRACE_PRINT_INFO
262 MarkDirty(); // force BVH rebuilding
264 #ifdef RAY_TRACE_PRINT_INFO
269 OSD_Parallel::For (0, Size(), OpenGL_BVHParallelBuilder (this));
271 myBotLevelTreeDepth = 1;
273 for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx)
275 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
276 myObjects.ChangeValue (anObjectIdx).operator->());
278 Standard_ASSERT_RETURN (aTriangleSet != NULL,
279 "Error! Failed to get triangulation of OpenGL element", Standard_False);
281 Standard_ASSERT_RETURN (!aTriangleSet->QuadBVH().IsNull(),
282 "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
284 QuadBvhHandle aBVH = aTriangleSet->QuadBVH();
286 // correct data array of bottom-level BVH to set special flag for outer
287 // nodes in order to distinguish them from outer nodes of top-level BVH
288 for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
290 if (aBVH->IsOuter (aNodeIdx))
292 aBVH->NodeInfoBuffer()[aNodeIdx].x() = -1;
296 myBotLevelTreeDepth = Max (myBotLevelTreeDepth, aTriangleSet->QuadBVH()->Depth());
299 #ifdef RAY_TRACE_PRINT_INFO
302 std::cout << "Updating bottom-level BVHs (sec): " <<
303 aTimer.ElapsedTime() << std::endl;
306 #ifdef RAY_TRACE_PRINT_INFO
311 QuadBvhHandle aBVH = QuadBVH();
313 Standard_ASSERT_RETURN (!aBVH.IsNull(),
314 "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False);
316 myTopLevelTreeDepth = aBVH->Depth();
318 #ifdef RAY_TRACE_PRINT_INFO
321 std::cout << "Updating high-level BVH (sec): " <<
322 aTimer.ElapsedTime() << std::endl;
325 Standard_Integer aVerticesOffset = 0;
326 Standard_Integer aElementsOffset = 0;
327 Standard_Integer aBvhNodesOffset = QuadBVH()->Length();
329 for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
331 if (aBVH->IsOuter (aNodeIdx))
333 Standard_ASSERT_RETURN (aBVH->BegPrimitive (aNodeIdx) == aBVH->EndPrimitive (aNodeIdx),
334 "Error! Invalid leaf node in high-level BVH (contains several objects)", Standard_False);
336 const Standard_Integer anObjectIdx = aBVH->BegPrimitive (aNodeIdx);
338 Standard_ASSERT_RETURN (anObjectIdx < myObjects.Size(),
339 "Error! Invalid leaf node in high-level BVH (contains out-of-range object)", Standard_False);
341 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (myObjects (anObjectIdx).get());
343 // Note: We overwrite node info record to store parameters
344 // of bottom-level BVH and triangulation of OpenGL element
346 aBVH->NodeInfoBuffer()[aNodeIdx] = BVH_Vec4i (anObjectIdx + 1, // to keep leaf flag
351 aVerticesOffset += static_cast<Standard_Integer> (aTriangleSet->Vertices.size());
352 aElementsOffset += static_cast<Standard_Integer> (aTriangleSet->Elements.size());
354 aBvhNodesOffset += aTriangleSet->QuadBVH()->Length();
358 return Standard_True;
361 // =======================================================================
362 // function : QuadBVH
363 // purpose : Returns quad BVH (QBVH) tree produced from binary BVH
364 // =======================================================================
365 const QuadBvhHandle& OpenGl_RaytraceGeometry::QuadBVH()
369 Standard_ASSERT_RAISE (!myQuadBVH.IsNull(), "Error! BVH was not collapsed into QBVH");
373 myQuadBVH = BVH()->CollapseToQuadTree(); // build binary BVH and collapse it
375 myBVH->Clear(); // erase binary BVH
381 // =======================================================================
382 // function : AccelerationOffset
383 // purpose : Returns offset of bottom-level BVH for given leaf node
384 // =======================================================================
385 Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer theNodeIdx)
387 const QuadBvhHandle& aBVH = QuadBVH();
389 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
390 return INVALID_OFFSET;
392 return aBVH->NodeInfoBuffer().at (theNodeIdx).y();
395 // =======================================================================
396 // function : VerticesOffset
397 // purpose : Returns offset of triangulation vertices for given leaf node
398 // =======================================================================
399 Standard_Integer OpenGl_RaytraceGeometry::VerticesOffset (Standard_Integer theNodeIdx)
401 const QuadBvhHandle& aBVH = QuadBVH();
403 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
404 return INVALID_OFFSET;
406 return aBVH->NodeInfoBuffer().at (theNodeIdx).z();
409 // =======================================================================
410 // function : ElementsOffset
411 // purpose : Returns offset of triangulation elements for given leaf node
412 // =======================================================================
413 Standard_Integer OpenGl_RaytraceGeometry::ElementsOffset (Standard_Integer theNodeIdx)
415 const QuadBvhHandle& aBVH = QuadBVH();
417 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
418 return INVALID_OFFSET;
420 return aBVH->NodeInfoBuffer().at (theNodeIdx).w();
423 // =======================================================================
424 // function : TriangleSet
425 // purpose : Returns triangulation data for given leaf node
426 // =======================================================================
427 OpenGl_TriangleSet* OpenGl_RaytraceGeometry::TriangleSet (Standard_Integer theNodeIdx)
429 const QuadBvhHandle& aBVH = QuadBVH();
431 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
434 if (aBVH->NodeInfoBuffer().at (theNodeIdx).x() > myObjects.Size())
437 return dynamic_cast<OpenGl_TriangleSet*> (
438 myObjects (aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).get());
441 // =======================================================================
442 // function : AcquireTextures
443 // purpose : Makes the OpenGL texture handles resident
444 // =======================================================================
445 Standard_Boolean OpenGl_RaytraceGeometry::AcquireTextures (const Handle(OpenGl_Context)& theContext) const
447 if (theContext->arbTexBindless == NULL)
449 return Standard_True;
452 #if !defined(GL_ES_VERSION_2_0)
453 for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
455 theContext->arbTexBindless->glMakeTextureHandleResidentARB (myTextureHandles[anIdx]);
457 if (glGetError() != GL_NO_ERROR)
459 #ifdef RAY_TRACE_PRINT_INFO
460 std::cout << "Error: Failed to make OpenGL texture resident" << std::endl;
462 return Standard_False;
467 return Standard_True;
470 // =======================================================================
471 // function : ReleaseTextures
472 // purpose : Makes the OpenGL texture handles non-resident
473 // =======================================================================
474 Standard_Boolean OpenGl_RaytraceGeometry::ReleaseTextures (const Handle(OpenGl_Context)& theContext) const
476 if (theContext->arbTexBindless == NULL)
478 return Standard_True;
481 #if !defined(GL_ES_VERSION_2_0)
482 for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
484 theContext->arbTexBindless->glMakeTextureHandleNonResidentARB (myTextureHandles[anIdx]);
486 if (glGetError() != GL_NO_ERROR)
488 #ifdef RAY_TRACE_PRINT_INFO
489 std::cout << "Error: Failed to make OpenGL texture non-resident" << std::endl;
491 return Standard_False;
496 return Standard_True;
499 // =======================================================================
500 // function : AddTexture
501 // purpose : Adds new OpenGL texture to the scene and returns its index
502 // =======================================================================
503 Standard_Integer OpenGl_RaytraceGeometry::AddTexture (const Handle(OpenGl_Texture)& theTexture)
505 if (theTexture->TextureId() == OpenGl_Texture::NO_TEXTURE)
510 NCollection_Vector<Handle (OpenGl_Texture)>::iterator anIter =
511 std::find (myTextures.begin(), myTextures.end(), theTexture);
513 if (anIter == myTextures.end())
515 if (myTextures.Size() >= MAX_TEX_NUMBER)
520 myTextures.Append (theTexture);
523 return static_cast<Standard_Integer> (anIter - myTextures.begin());
526 // =======================================================================
527 // function : UpdateTextureHandles
528 // purpose : Updates unique 64-bit texture handles to use in shaders
529 // =======================================================================
530 Standard_Boolean OpenGl_RaytraceGeometry::UpdateTextureHandles (const Handle(OpenGl_Context)& theContext)
532 if (theContext->arbTexBindless == NULL)
534 return Standard_False;
537 if (myTextureSampler.IsNull())
539 myTextureSampler = new OpenGl_Sampler();
540 myTextureSampler->Init (*theContext.operator->());
541 myTextureSampler->SetParameter (*theContext.operator->(), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
542 myTextureSampler->SetParameter (*theContext.operator->(), GL_TEXTURE_MAG_FILTER, GL_LINEAR);
543 myTextureSampler->SetParameter (*theContext.operator->(), GL_TEXTURE_WRAP_S, GL_REPEAT);
544 myTextureSampler->SetParameter (*theContext.operator->(), GL_TEXTURE_WRAP_T, GL_REPEAT);
547 myTextureHandles.clear();
549 #if !defined(GL_ES_VERSION_2_0)
550 for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
552 const GLuint64 aHandle = theContext->arbTexBindless->glGetTextureSamplerHandleARB (
553 myTextures.Value (anIdx)->TextureId(), myTextureSampler->SamplerID());
555 if (glGetError() != GL_NO_ERROR)
557 #ifdef RAY_TRACE_PRINT_INFO
558 std::cout << "Error: Failed to get 64-bit handle of OpenGL texture" << std::endl;
560 return Standard_False;
563 myTextureHandles.push_back (aHandle);
567 return Standard_True;
570 namespace OpenGl_Raytrace
572 // =======================================================================
573 // function : IsRaytracedElement
574 // purpose : Checks to see if the element contains ray-trace geometry
575 // =======================================================================
576 Standard_Boolean IsRaytracedElement (const OpenGl_ElementNode* theNode)
578 OpenGl_PrimitiveArray* anArray = dynamic_cast<OpenGl_PrimitiveArray*> (theNode->elem);
579 return anArray != NULL
580 && anArray->DrawMode() >= GL_TRIANGLES;
583 // =======================================================================
584 // function : IsRaytracedElement
585 // purpose : Checks to see if the element contains ray-trace geometry
586 // =======================================================================
587 Standard_Boolean IsRaytracedElement (const OpenGl_Element* theElement)
589 const OpenGl_PrimitiveArray* anArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
590 return anArray != NULL
591 && anArray->DrawMode() >= GL_TRIANGLES;
594 // =======================================================================
595 // function : IsRaytracedGroup
596 // purpose : Checks to see if the group contains ray-trace geometry
597 // =======================================================================
598 Standard_Boolean IsRaytracedGroup (const OpenGl_Group* theGroup)
600 for (const OpenGl_ElementNode* aNode = theGroup->FirstNode(); aNode != NULL; aNode = aNode->next)
602 if (IsRaytracedElement (aNode))
604 return Standard_True;
607 return Standard_False;