0024739: TKOpenGl - port ray-tracing from OpenCL to GLSL for better integration and...
[occt.git] / src / OpenGl / OpenGl_SceneGeometry.cxx
... / ...
CommitLineData
1// Created on: 2013-08-27
2// Created by: Denis BOGOLEPOV
3// Copyright (c) 2013 OPEN CASCADE SAS
4//
5// This file is part of Open CASCADE Technology software library.
6//
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.
12//
13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
15
16#include <Standard_Assert.hxx>
17
18#ifdef HAVE_TBB
19 // On Windows, function TryEnterCriticalSection has appeared in Windows NT
20 // and is surrounded by #ifdef in MS VC++ 7.1 headers.
21 // Thus to use it we need to define appropriate macro saying that we wil
22 // run on Windows NT 4.0 at least
23 #if ((defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN32_WINNT))
24 #define _WIN32_WINNT 0x0501
25 #endif
26
27 #include <tbb/tbb.h>
28#endif
29
30#include <OpenGl_SceneGeometry.hxx>
31
32//! Use this macro to output BVH profiling info
33//#define BVH_PRINT_INFO
34
35#ifdef BVH_PRINT_INFO
36 #include <OSD_Timer.hxx>
37#endif
38
39namespace
40{
41 //! Useful constant for null floating-point 4D vector.
42 static const BVH_Vec4f ZERO_VEC_4F;
43};
44
45// =======================================================================
46// function : OpenGl_RaytraceMaterial
47// purpose : Creates new default material
48// =======================================================================
49OpenGl_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)
57{ }
58
59// =======================================================================
60// function : OpenGl_RaytraceMaterial
61// purpose : Creates new material with specified properties
62// =======================================================================
63OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
64 const BVH_Vec4f& theDiffuse,
65 const BVH_Vec4f& theSpecular)
66: Ambient (theAmbient),
67 Diffuse (theDiffuse),
68 Specular (theSpecular),
69 Emission (ZERO_VEC_4F),
70 Reflection (ZERO_VEC_4F),
71 Refraction (ZERO_VEC_4F),
72 Transparency (ZERO_VEC_4F)
73{
74 //
75}
76
77// =======================================================================
78// function : OpenGl_RaytraceMaterial
79// purpose : Creates new material with specified properties
80// =======================================================================
81OpenGl_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),
87 Diffuse (theDiffuse),
88 Specular (theSpecular),
89 Emission (theEmission),
90 Reflection (ZERO_VEC_4F),
91 Refraction (ZERO_VEC_4F),
92 Transparency (theTranspar)
93{
94 //
95}
96
97// =======================================================================
98// function : OpenGl_RaytraceMaterial
99// purpose : Creates new material with specified properties
100// =======================================================================
101OpenGl_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)
115{
116 //
117}
118
119// =======================================================================
120// function : OpenGl_LightSource
121// purpose : Creates new light source
122// =======================================================================
123OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theDiffuse,
124 const BVH_Vec4f& thePosition)
125: Diffuse (theDiffuse),
126 Position (thePosition)
127{
128 //
129}
130
131// =======================================================================
132// function : Clear
133// purpose : Clears ray-tracing geometry
134// =======================================================================
135void OpenGl_RaytraceGeometry::Clear()
136{
137 BVH_Geometry<Standard_ShortReal, 4>::BVH_Geometry::Clear();
138
139 std::vector<OpenGl_RaytraceLight,
140 NCollection_StdAllocator<OpenGl_RaytraceLight> > anEmptySources;
141
142 Sources.swap (anEmptySources);
143
144 std::vector<OpenGl_RaytraceMaterial,
145 NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
146
147 Materials.swap (anEmptyMaterials);
148}
149
150#ifdef HAVE_TBB
151
152struct OpenGL_BVHParallelBuilder
153{
154 BVH_ObjectSet<Standard_ShortReal, 4>* Set;
155
156 OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 4>* theSet)
157 : Set (theSet)
158 {
159 //
160 }
161
162 void operator() (const tbb::blocked_range<size_t>& theRange) const
163 {
164 for (size_t anObjectIdx = theRange.begin(); anObjectIdx != theRange.end(); ++anObjectIdx)
165 {
166 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
167 Set->Objects().ChangeValue (static_cast<Standard_Integer> (anObjectIdx)).operator->());
168
169 if (aTriangleSet != NULL)
170 {
171 aTriangleSet->BVH();
172 }
173 }
174 }
175};
176
177#endif
178
179// =======================================================================
180// function : ProcessAcceleration
181// purpose : Performs post-processing of high-level BVH
182// =======================================================================
183Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
184{
185#ifdef BVH_PRINT_INFO
186 OSD_Timer aTimer;
187#endif
188
189 MarkDirty(); // force BVH rebuilding
190
191#ifdef BVH_PRINT_INFO
192 aTimer.Reset();
193 aTimer.Start();
194#endif
195
196#ifdef HAVE_TBB
197 // If Intel TBB is available, perform the preliminary
198 // construction of bottom-level scene BVHs
199 tbb::parallel_for (tbb::blocked_range<size_t> (0, Size()),
200 OpenGL_BVHParallelBuilder (this));
201#endif
202
203 myBottomLevelTreeDepth = 0;
204
205 for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx)
206 {
207 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
208 myObjects.ChangeValue (anObjectIdx).operator->());
209
210 Standard_ASSERT_RETURN (aTriangleSet != NULL,
211 "Error! Failed to get triangulation of OpenGL element", Standard_False);
212
213 Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(),
214 "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
215
216 myBottomLevelTreeDepth = Max (myBottomLevelTreeDepth, aTriangleSet->BVH()->Depth());
217 }
218
219#ifdef BVH_PRINT_INFO
220 aTimer.Stop();
221
222 std::cout << "Updating bottom-level BVHs (sec): " <<
223 aTimer.ElapsedTime() << std::endl;
224#endif
225
226#ifdef BVH_PRINT_INFO
227 aTimer.Reset();
228 aTimer.Start();
229#endif
230
231 NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> > aBVH = BVH();
232
233#ifdef BVH_PRINT_INFO
234 aTimer.Stop();
235
236 std::cout << "Updating high-level BVH (sec): " <<
237 aTimer.ElapsedTime() << std::endl;
238#endif
239
240 Standard_ASSERT_RETURN (!aBVH.IsNull(),
241 "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False);
242
243 myHighLevelTreeDepth = aBVH->Depth();
244
245 Standard_Integer aVerticesOffset = 0;
246 Standard_Integer aElementsOffset = 0;
247 Standard_Integer aBVHNodesOffset = 0;
248
249 for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
250 {
251 if (!aBVH->IsOuter (aNodeIdx))
252 continue;
253
254 Standard_ASSERT_RETURN (aBVH->BegPrimitive (aNodeIdx) == aBVH->EndPrimitive (aNodeIdx),
255 "Error! Invalid leaf node in high-level BVH (contains several objects)", Standard_False);
256
257 Standard_Integer anObjectIdx = aBVH->BegPrimitive (aNodeIdx);
258
259 Standard_ASSERT_RETURN (anObjectIdx < myObjects.Size(),
260 "Error! Invalid leaf node in high-level BVH (contains out-of-range object)", Standard_False);
261
262 OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
263 myObjects.ChangeValue (anObjectIdx).operator->());
264
265 // Note: We overwrite node info record to store parameters
266 // of bottom-level BVH and triangulation of OpenGL element
267
268 aBVH->NodeInfoBuffer().at (aNodeIdx) = BVH_Vec4i (
269 anObjectIdx + 1 /* to keep leaf flag */, aBVHNodesOffset, aVerticesOffset, aElementsOffset);
270
271 aVerticesOffset += (int)aTriangleSet->Vertices.size();
272 aElementsOffset += (int)aTriangleSet->Elements.size();
273 aBVHNodesOffset += aTriangleSet->BVH()->Length();
274 }
275
276 return Standard_True;
277}
278
279// =======================================================================
280// function : AccelerationOffset
281// purpose : Returns offset of bottom-level BVH for given leaf node
282// =======================================================================
283Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer theNodeIdx)
284{
285 const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
286
287 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
288 return INVALID_OFFSET;
289
290 return aBVH->NodeInfoBuffer().at (theNodeIdx).y();
291}
292
293// =======================================================================
294// function : VerticesOffset
295// purpose : Returns offset of triangulation vertices for given leaf node
296// =======================================================================
297Standard_Integer OpenGl_RaytraceGeometry::VerticesOffset (Standard_Integer theNodeIdx)
298{
299 const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
300
301 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
302 return INVALID_OFFSET;
303
304 return aBVH->NodeInfoBuffer().at (theNodeIdx).z();
305}
306
307// =======================================================================
308// function : ElementsOffset
309// purpose : Returns offset of triangulation elements for given leaf node
310// =======================================================================
311Standard_Integer OpenGl_RaytraceGeometry::ElementsOffset (Standard_Integer theNodeIdx)
312{
313 const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
314
315 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
316 return INVALID_OFFSET;
317
318 return aBVH->NodeInfoBuffer().at (theNodeIdx).w();
319}
320
321// =======================================================================
322// function : TriangleSet
323// purpose : Returns triangulation data for given leaf node
324// =======================================================================
325OpenGl_TriangleSet* OpenGl_RaytraceGeometry::TriangleSet (Standard_Integer theNodeIdx)
326{
327 const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
328
329 if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
330 return NULL;
331
332 if (aBVH->NodeInfoBuffer().at (theNodeIdx).x() > myObjects.Size())
333 return NULL;
334
335 return dynamic_cast<OpenGl_TriangleSet*> (myObjects.ChangeValue (
336 aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).operator->());
337}
338
339namespace OpenGl_Raytrace
340{
341 // =======================================================================
342 // function : IsRaytracedElement
343 // purpose : Checks to see if the element contains ray-trace geometry
344 // =======================================================================
345 Standard_Boolean IsRaytracedElement (const OpenGl_ElementNode* theNode)
346 {
347 OpenGl_PrimitiveArray* anArray = dynamic_cast< OpenGl_PrimitiveArray* > (theNode->elem);
348 return anArray != NULL
349 && anArray->PArray()->type >= TelPolygonsArrayType;
350 }
351
352 // =======================================================================
353 // function : IsRaytracedGroup
354 // purpose : Checks to see if the group contains ray-trace geometry
355 // =======================================================================
356 Standard_Boolean IsRaytracedGroup (const OpenGl_Group *theGroup)
357 {
358 const OpenGl_ElementNode* aNode;
359 for (aNode = theGroup->FirstNode(); aNode != NULL; aNode = aNode->next)
360 {
361 if (IsRaytracedElement (aNode))
362 {
363 return Standard_True;
364 }
365 }
366 return Standard_False;
367 }
368
369 // =======================================================================
370 // function : IsRaytracedStructure
371 // purpose : Checks to see if the structure contains ray-trace geometry
372 // =======================================================================
373 Standard_Boolean IsRaytracedStructure (const OpenGl_Structure* theStructure)
374 {
375 for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups());
376 aGroupIter.More(); aGroupIter.Next())
377 {
378 if (aGroupIter.Value()->IsRaytracable())
379 return Standard_True;
380 }
381 for (OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures());
382 anIts.More(); anIts.Next())
383 {
384 if (IsRaytracedStructure (anIts.Value()))
385 return Standard_True;
386 }
387 return Standard_False;
388 }
389}