KiCad PCB EDA Suite
render_3d_raytrace.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2020 Mario Luzeiro <[email protected]>
5  * Copyright (C) 2015-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <gal/opengl/kiglew.h> // Must be included first
26 
27 #include <algorithm>
28 #include <atomic>
29 #include <chrono>
30 #include <climits>
31 #include <thread>
32 
33 #include "render_3d_raytrace.h"
34 #include "mortoncodes.h"
35 #include "../color_rgb.h"
36 #include "3d_fastmath.h"
37 #include "3d_math.h"
38 #include "../common_ogl/ogl_utils.h"
39 #include <profile.h> // To use GetRunningMicroSecs or another profiling utility
40 #include <wx/log.h>
41 
42 
44  RENDER_3D_BASE( aCanvas, aAdapter, aCamera ),
45  m_postShaderSsao( aCamera )
46 {
47  wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE::RENDER_3D_RAYTRACE" ) );
48 
50  m_pboId = GL_NONE;
51  m_pboDataSize = 0;
52  m_accelerator = nullptr;
55  m_oldWindowsSize.x = 0;
56  m_oldWindowsSize.y = 0;
57  m_outlineBoard2dObjects = nullptr;
59  m_firstHitinfo = nullptr;
60  m_shaderBuffer = nullptr;
61  m_cameraLight = nullptr;
62 
63  m_xoffset = 0;
64  m_yoffset = 0;
65 
66  m_isPreview = false;
67  m_renderState = RT_RENDER_STATE_MAX; // Set to an initial invalid state
70 }
71 
72 
74 {
75  wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE::~RENDER_3D_RAYTRACE" ) );
76 
77  delete m_accelerator;
78  m_accelerator = nullptr;
79 
81  m_outlineBoard2dObjects = nullptr;
82 
85 
86  delete[] m_shaderBuffer;
87  m_shaderBuffer = nullptr;
88 
89  deletePbo();
90 }
91 
92 
94 {
95  return 1000; // ms
96 }
97 
98 
100 {
101  // Delete PBO if it was created
103  {
104  if( glIsBufferARB( m_pboId ) )
105  glDeleteBuffers( 1, &m_pboId );
106 
107  m_pboId = GL_NONE;
108  }
109 }
110 
111 
112 void RENDER_3D_RAYTRACE::SetCurWindowSize( const wxSize& aSize )
113 {
114  if( m_windowSize != aSize )
115  {
116  m_windowSize = aSize;
117  glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
118 
120  }
121 }
122 
123 
125 {
127 
130 
132 
134 
135  // Mark the blocks not processed yet
136  std::fill( m_blockPositionsWasProcessed.begin(), m_blockPositionsWasProcessed.end(), 0 );
137 }
138 
139 
140 static inline void SetPixel( GLubyte* p, const COLOR_RGB& v )
141 {
142  p[0] = v.c[0];
143  p[1] = v.c[1];
144  p[2] = v.c[2];
145  p[3] = 255;
146 }
147 
148 
149 bool RENDER_3D_RAYTRACE::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
150  REPORTER* aWarningReporter )
151 {
152  bool requestRedraw = false;
153 
154  // Initialize openGL if need
156  {
157  if( !initializeOpenGL() )
158  return false;
159 
160  //aIsMoving = true;
161  requestRedraw = true;
162 
163  // It will assign the first time the windows size, so it will now
164  // revert to preview mode the first time the Redraw is called
167  }
168 
169  std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
170 
171  // Reload board if it was requested
172  if( m_reloadRequested )
173  {
174  if( aStatusReporter )
175  aStatusReporter->Report( _( "Loading..." ) );
176 
177  //aIsMoving = true;
178  requestRedraw = true;
179  Reload( aStatusReporter, aWarningReporter, false );
180  }
181 
182 
183  // Recalculate constants if windows size was changed
185  {
187  aIsMoving = true;
188  requestRedraw = true;
189 
191  }
192 
193 
194  // Clear buffers
195  glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
196  glClearDepth( 1.0f );
197  glClearStencil( 0x00 );
198  glClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
199 
200  // 4-byte pixel alignment
201  glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
202 
203  glDisable( GL_STENCIL_TEST );
204  glDisable( GL_LIGHTING );
205  glDisable( GL_COLOR_MATERIAL );
206  glDisable( GL_DEPTH_TEST );
207  glDisable( GL_TEXTURE_2D );
208  glDisable( GL_BLEND );
209  glDisable( GL_MULTISAMPLE );
210 
211  const bool was_camera_changed = m_camera.ParametersChanged();
212 
213  if( requestRedraw || aIsMoving || was_camera_changed )
214  m_renderState = RT_RENDER_STATE_MAX; // Set to an invalid state,
215  // so it will restart again latter
216 
217  // This will only render if need, otherwise it will redraw the PBO on the screen again
218  if( aIsMoving || was_camera_changed )
219  {
220  // Set head light (camera view light) with the opposite direction of the camera
221  if( m_cameraLight )
223 
226 
227  // Bind PBO
228  glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
229 
230  // Get the PBO pixel pointer to write the data
231  GLubyte* ptrPBO = (GLubyte *)glMapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB,
232  GL_WRITE_ONLY_ARB );
233 
234  if( ptrPBO )
235  {
236  renderPreview( ptrPBO );
237 
238  // release pointer to mapping buffer, this initialize the coping to PBO
239  glUnmapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB );
240  }
241 
242  glWindowPos2i( m_xoffset, m_yoffset );
243  }
244  else
245  {
246  // Bind PBO
247  glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
248 
250  {
251  // Get the PBO pixel pointer to write the data
252  GLubyte* ptrPBO = (GLubyte *)glMapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB,
253  GL_WRITE_ONLY_ARB );
254 
255  if( ptrPBO )
256  {
257  render( ptrPBO, aStatusReporter );
258 
260  requestRedraw = true;
261 
262  // release pointer to mapping buffer, this initialize the coping to PBO
263  glUnmapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB );
264  }
265  }
266 
268  {
269  glClear( GL_COLOR_BUFFER_BIT );
270  }
271 
272  glWindowPos2i( m_xoffset, m_yoffset );
273  }
274 
275  // This way it will blend the progress rendering with the last buffer. eg:
276  // if it was called after a openGL.
277  glEnable( GL_BLEND );
278  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
279  glEnable( GL_ALPHA_TEST );
280  glDrawPixels( m_realBufferSize.x, m_realBufferSize.y, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
281  glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
282 
283  return requestRedraw;
284 }
285 
286 
287 void RENDER_3D_RAYTRACE::render( GLubyte* ptrPBO, REPORTER* aStatusReporter )
288 {
290  {
292 
293  if( m_cameraLight )
295 
297  {
298  // Set all pixels of PBO transparent (Alpha to 0)
299  // This way it will draw the full buffer but only shows the updated (
300  // already calculated) squares
301  unsigned int nPixels = m_realBufferSize.x * m_realBufferSize.y;
302  GLubyte* tmp_ptrPBO = ptrPBO + 3; // PBO is RGBA
303 
304  for( unsigned int i = 0; i < nPixels; ++i )
305  {
306  *tmp_ptrPBO = 0;
307  tmp_ptrPBO += 4; // PBO is RGBA
308  }
309  }
310 
313  }
314 
315  switch( m_renderState )
316  {
318  renderTracing( ptrPBO, aStatusReporter );
319  break;
320 
322  postProcessShading( ptrPBO, aStatusReporter );
323  break;
324 
326  postProcessBlurFinish( ptrPBO, aStatusReporter );
327  break;
328 
329  default:
330  wxASSERT_MSG( false, wxT( "Invalid state on m_renderState" ) );
332  break;
333  }
334 
335  if( aStatusReporter && ( m_renderState == RT_RENDER_STATE_FINISH ) )
336  {
337  // Calculation time in seconds
338  const double elapsed_time = (double)( GetRunningMicroSecs() - m_renderStartTime ) / 1e6;
339 
340  aStatusReporter->Report( wxString::Format( _( "Rendering time %.3f s" ), elapsed_time ) );
341  }
342 }
343 
344 
345 void RENDER_3D_RAYTRACE::renderTracing( GLubyte* ptrPBO, REPORTER* aStatusReporter )
346 {
347  m_isPreview = false;
348 
349  auto startTime = std::chrono::steady_clock::now();
350  bool breakLoop = false;
351 
352  std::atomic<size_t> numBlocksRendered( 0 );
353  std::atomic<size_t> currentBlock( 0 );
354  std::atomic<size_t> threadsFinished( 0 );
355 
356  size_t parallelThreadCount = std::min<size_t>(
357  std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
358  m_blockPositions.size() );
359 
360  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
361  {
362  std::thread t = std::thread( [&]()
363  {
364  for( size_t iBlock = currentBlock.fetch_add( 1 );
365  iBlock < m_blockPositions.size() && !breakLoop;
366  iBlock = currentBlock.fetch_add( 1 ) )
367  {
368  if( !m_blockPositionsWasProcessed[iBlock] )
369  {
370  renderBlockTracing( ptrPBO, iBlock );
371  numBlocksRendered++;
372  m_blockPositionsWasProcessed[iBlock] = 1;
373 
374  // Check if it spend already some time render and request to exit
375  // to display the progress
376  if( std::chrono::duration_cast<std::chrono::milliseconds>(
377  std::chrono::steady_clock::now() - startTime ).count() > 150 )
378  breakLoop = true;
379  }
380  }
381 
382  threadsFinished++;
383  } );
384 
385  t.detach();
386  }
387 
388  while( threadsFinished < parallelThreadCount )
389  std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
390 
391  m_blockRenderProgressCount += numBlocksRendered;
392 
393  if( aStatusReporter )
394  aStatusReporter->Report( wxString::Format( _( "Rendering: %.0f %%" ),
395  (float) ( m_blockRenderProgressCount * 100 )
396  / (float) m_blockPositions.size() ) );
397 
398  // Check if it finish the rendering and if should continue to a post processing
399  // or mark it as finished
401  {
404  else
406  }
407 }
408 
409 
410 #ifdef USE_SRGB_SPACE
411 
413 #define SRGB_GAMA 2.4f
414 
415 
416 // This function implements the conversion from linear RGB to sRGB
417 // https://github.com/g-truc/glm/blob/master/glm/gtc/color_space.inl#L12
418 static SFVEC3F convertLinearToSRGB( const SFVEC3F& aRGBcolor )
419 {
420  const float gammaCorrection = 1.0f / SRGB_GAMA;
421  const SFVEC3F clampedColor = glm::clamp( aRGBcolor, SFVEC3F( 0.0f ), SFVEC3F( 1.0f ) );
422 
423  return glm::mix( glm::pow( clampedColor, SFVEC3F(gammaCorrection) ) * 1.055f - 0.055f,
424  clampedColor * 12.92f,
425  glm::lessThan( clampedColor, SFVEC3F(0.0031308f) ) );
426 }
427 
428 
429 // This function implements the conversion from sRGB to linear RGB
430 // https://github.com/g-truc/glm/blob/master/glm/gtc/color_space.inl#L35
431 SFVEC3F ConvertSRGBToLinear( const SFVEC3F& aSRGBcolor )
432 {
433  const float gammaCorrection = SRGB_GAMA;
434 
435  return glm::mix( glm::pow( ( aSRGBcolor + SFVEC3F( 0.055f ) )
436  * SFVEC3F( 0.94786729857819905213270142180095f ),
437  SFVEC3F( gammaCorrection ) ),
438  aSRGBcolor * SFVEC3F( 0.07739938080495356037151702786378f ),
439  glm::lessThanEqual( aSRGBcolor, SFVEC3F( 0.04045f ) ) );
440 }
441 
442 #endif
443 
444 
445 void RENDER_3D_RAYTRACE::renderFinalColor( GLubyte* ptrPBO, const SFVEC3F& rgbColor,
446  bool applyColorSpaceConversion )
447 {
448  SFVEC3F color = rgbColor;
449 
450 #ifdef USE_SRGB_SPACE
451  // if( applyColorSpaceConversion )
453  // rgbColor = glm::convertLinearToSRGB( rgbColor );
454 
455  if( applyColorSpaceConversion )
456  color = convertLinearToSRGB( rgbColor );
457 #endif
458 
459  ptrPBO[0] = (unsigned int) glm::clamp( (int) ( color.r * 255 ), 0, 255 );
460  ptrPBO[1] = (unsigned int) glm::clamp( (int) ( color.g * 255 ), 0, 255 );
461  ptrPBO[2] = (unsigned int) glm::clamp( (int) ( color.b * 255 ), 0, 255 );
462  ptrPBO[3] = 255;
463 }
464 
465 
466 static void HITINFO_PACKET_init( HITINFO_PACKET* aHitPacket )
467 {
468  // Initialize hitPacket with a "not hit" information
469  for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
470  {
471  aHitPacket[i].m_HitInfo.m_tHit = std::numeric_limits<float>::infinity();
472  aHitPacket[i].m_HitInfo.m_acc_node_info = 0;
473  aHitPacket[i].m_hitresult = false;
474  aHitPacket[i].m_HitInfo.m_HitNormal = SFVEC3F( 0.0f );
475  aHitPacket[i].m_HitInfo.m_ShadowFactor = 1.0f;
476  }
477 }
478 
479 
480 void RENDER_3D_RAYTRACE::renderRayPackets( const SFVEC3F* bgColorY, const RAY* aRayPkt,
481  HITINFO_PACKET* aHitPacket, bool is_testShadow,
482  SFVEC3F* aOutHitColor )
483 {
484  for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
485  {
486  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
487  {
488  if( aHitPacket[i].m_hitresult == true )
489  {
490  aOutHitColor[i] = shadeHit( bgColorY[y], aRayPkt[i], aHitPacket[i].m_HitInfo,
491  false, 0, is_testShadow );
492  }
493  else
494  {
495  aOutHitColor[i] = bgColorY[y];
496  }
497  }
498  }
499 }
500 
501 
503  const HITINFO_PACKET* aHitPck_X0Y0,
504  const HITINFO_PACKET* aHitPck_AA_X1Y1,
505  const RAY* aRayPck, SFVEC3F* aOutHitColor )
506 {
507  const bool is_testShadow = m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_SHADOWS );
508 
509  for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
510  {
511  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
512  {
513  const RAY& rayAA = aRayPck[i];
514 
515  HITINFO hitAA;
516  hitAA.m_tHit = std::numeric_limits<float>::infinity();
517  hitAA.m_acc_node_info = 0;
518 
519  bool hitted = false;
520 
521  const unsigned int idx0y1 = ( x + 0 ) + RAYPACKET_DIM * ( y + 1 );
522  const unsigned int idx1y1 = ( x + 1 ) + RAYPACKET_DIM * ( y + 1 );
523 
524  // Gets the node info from the hit.
525  const unsigned int nodex0y0 = aHitPck_X0Y0[ i ].m_HitInfo.m_acc_node_info;
526  const unsigned int node_AA_x0y0 = aHitPck_AA_X1Y1[ i ].m_HitInfo.m_acc_node_info;
527 
528  unsigned int nodex1y0 = 0;
529 
530  if( x < (RAYPACKET_DIM - 1) )
531  nodex1y0 = aHitPck_X0Y0[ i + 1 ].m_HitInfo.m_acc_node_info;
532 
533  unsigned int nodex0y1 = 0;
534 
535  if( y < ( RAYPACKET_DIM - 1 ) && idx0y1 < RAYPACKET_RAYS_PER_PACKET )
536  nodex0y1 = aHitPck_X0Y0[idx0y1].m_HitInfo.m_acc_node_info;
537 
538  unsigned int nodex1y1 = 0;
539 
540  if( ( x < ( RAYPACKET_DIM - 1 ) ) && ( y < ( RAYPACKET_DIM - 1 ) )
541  && idx1y1 < RAYPACKET_RAYS_PER_PACKET )
542  nodex1y1 = aHitPck_X0Y0[idx1y1].m_HitInfo.m_acc_node_info;
543 
544  // If all notes are equal we assume there was no change on the object hits.
545  if( ( ( nodex0y0 == nodex1y0 ) || ( nodex1y0 == 0 ) )
546  && ( ( nodex0y0 == nodex0y1 ) || ( nodex0y1 == 0 ) )
547  && ( ( nodex0y0 == nodex1y1 ) || ( nodex1y1 == 0 ) )
548  && ( nodex0y0 == node_AA_x0y0 ) )
549  {
552  // Option 1
553  // This option will give a very good quality on reflections (slow)
554  /*
555  if( m_accelerator->Intersect( rayAA, hitAA, nodex0y0 ) )
556  {
557  aOutHitColor[i] += shadeHit( aBgColorY[y], rayAA, hitAA, false, 0 );
558  }
559  else
560  {
561  if( m_accelerator->Intersect( rayAA, hitAA ) )
562  aOutHitColor[i] += shadeHit( aBgColorY[y], rayAA, hitAA, false, 0 );
563  else
564  aOutHitColor[i] += hitColor[i];
565  }
566  */
567 
568  // Option 2
569  // Trace again with the same node,
570  // then if miss just give the same color as before
571  //if( m_accelerator->Intersect( rayAA, hitAA, nodex0y0 ) )
572  // aOutHitColor[i] += shadeHit( aBgColorY[y], rayAA, hitAA, false, 0 );
573 
574  // Option 3
575  // Use same color
576  }
577  else
578  {
579  // Try to intersect the different nodes
580  // It tests the possible combination of hitted or not hitted points
581  // This will try to get the best hit for this ray
582 
583  if( nodex0y0 != 0 )
584  hitted |= m_accelerator->Intersect( rayAA, hitAA, nodex0y0 );
585 
586  if( ( nodex1y0 != 0 ) && ( nodex0y0 != nodex1y0 ) )
587  hitted |= m_accelerator->Intersect( rayAA, hitAA, nodex1y0 );
588 
589  if( ( nodex0y1 != 0 ) && ( nodex0y0 != nodex0y1 ) && ( nodex1y0 != nodex0y1 ) )
590  hitted |= m_accelerator->Intersect( rayAA, hitAA, nodex0y1 );
591 
592  if( ( nodex1y1 != 0 ) && ( nodex0y0 != nodex1y1 ) && ( nodex0y1 != nodex1y1 ) &&
593  ( nodex1y0 != nodex1y1 ) )
594  hitted |= m_accelerator->Intersect( rayAA, hitAA, nodex1y1 );
595 
596  if( (node_AA_x0y0 != 0 ) && ( nodex0y0 != node_AA_x0y0 ) &&
597  ( nodex0y1 != node_AA_x0y0 ) && ( nodex1y0 != node_AA_x0y0 ) &&
598  ( nodex1y1 != node_AA_x0y0 ) )
599  hitted |= m_accelerator->Intersect( rayAA, hitAA, node_AA_x0y0 );
600 
601  if( hitted )
602  {
603  // If we got any result, shade it
604  aOutHitColor[i] = shadeHit( aBgColorY[y], rayAA, hitAA, false, 0,
605  is_testShadow );
606  }
607  else
608  {
609  // Note: There are very few cases that will end on this situation
610  // so it is not so expensive to trace a single ray from the beginning
611 
612  // It was missed the 'last nodes' so, trace a ray from the beginning
613  if( m_accelerator->Intersect( rayAA, hitAA ) )
614  aOutHitColor[i] = shadeHit( aBgColorY[y], rayAA, hitAA, false, 0,
615  is_testShadow );
616  }
617  }
618  }
619  }
620 }
621 
622 
623 #define DISP_FACTOR 0.075f
624 
625 
626 void RENDER_3D_RAYTRACE::renderBlockTracing( GLubyte* ptrPBO, signed int iBlock )
627 {
628  // Initialize ray packets
629  const SFVEC2UI& blockPos = m_blockPositions[iBlock];
630  const SFVEC2I blockPosI = SFVEC2I( blockPos.x + m_xoffset, blockPos.y + m_yoffset );
631 
632  RAYPACKET blockPacket( m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, DISP_FACTOR ),
633  SFVEC2F( DISP_FACTOR, DISP_FACTOR ) /* Displacement random factor */ );
634 
635 
637 
638  HITINFO_PACKET_init( hitPacket_X0Y0 );
639 
640  // Calculate background gradient color
641  SFVEC3F bgColor[RAYPACKET_DIM];// Store a vertical gradient color
642 
643  for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
644  {
645  const float posYfactor = (float) ( blockPosI.y + y ) / (float) m_windowSize.y;
646 
647  bgColor[y] = m_backgroundColorTop * SFVEC3F(posYfactor) +
648  m_backgroundColorBottom * ( SFVEC3F(1.0f) - SFVEC3F(posYfactor) );
649  }
650 
651  // Intersect ray packets (calculate the intersection with rays and objects)
652  if( !m_accelerator->Intersect( blockPacket, hitPacket_X0Y0 ) )
653  {
654  // If block is empty then set shades and continue
656  {
657  for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
658  {
659  const SFVEC3F& outColor = bgColor[y];
660 
661  const unsigned int yBlockPos = blockPos.y + y;
662 
663  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x )
664  {
665  m_postShaderSsao.SetPixelData( blockPos.x + x, yBlockPos,
666  SFVEC3F( 0.0f ), outColor,
667  SFVEC3F( 0.0f ), 0, 1.0f );
668  }
669  }
670  }
671 
672  // This will set the output color to be displayed
673  // If post processing is enabled, it will not reflect the final result
674  // (as the final color will be computed on post processing)
675  // but it is used for report progress
676  const bool isFinalColor = !m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_POST_PROCESSING );
677 
678  for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
679  {
680  const SFVEC3F& outColor = bgColor[y];
681 
682  const unsigned int yConst = blockPos.x + ( ( y + blockPos.y ) * m_realBufferSize.x );
683 
684  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x )
685  {
686  GLubyte* ptr = &ptrPBO[( yConst + x ) * 4];
687 
688  renderFinalColor( ptr, outColor, isFinalColor );
689  }
690  }
691 
692  // There is nothing more here to do.. there are no hits ..
693  // just background so continue
694  return;
695  }
696 
697  SFVEC3F hitColor_X0Y0[RAYPACKET_RAYS_PER_PACKET];
698 
699  // Shade original (0, 0) hits ("paint" the intersected objects)
700  renderRayPackets( bgColor, blockPacket.m_ray, hitPacket_X0Y0,
702 
704  {
705  SFVEC3F hitColor_AA_X1Y1[RAYPACKET_RAYS_PER_PACKET];
706 
707  // Intersect one blockPosI + (0.5, 0.5) used for anti aliasing calculation
708  HITINFO_PACKET hitPacket_AA_X1Y1[RAYPACKET_RAYS_PER_PACKET];
709  HITINFO_PACKET_init( hitPacket_AA_X1Y1 );
710 
711  RAYPACKET blockPacket_AA_X1Y1( m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f, 0.5f ),
713 
714  if( !m_accelerator->Intersect( blockPacket_AA_X1Y1, hitPacket_AA_X1Y1 ) )
715  {
716  // Missed all the package
717  for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
718  {
719  const SFVEC3F& outColor = bgColor[y];
720 
721  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
722  {
723  hitColor_AA_X1Y1[i] = outColor;
724  }
725  }
726  }
727  else
728  {
729  renderRayPackets( bgColor, blockPacket_AA_X1Y1.m_ray, hitPacket_AA_X1Y1,
731  hitColor_AA_X1Y1 );
732  }
733 
734  SFVEC3F hitColor_AA_X1Y0[RAYPACKET_RAYS_PER_PACKET];
735  SFVEC3F hitColor_AA_X0Y1[RAYPACKET_RAYS_PER_PACKET];
736  SFVEC3F hitColor_AA_X0Y1_half[RAYPACKET_RAYS_PER_PACKET];
737 
738  for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
739  {
740  const SFVEC3F color_average = ( hitColor_X0Y0[i] +
741  hitColor_AA_X1Y1[i] ) * SFVEC3F( 0.5f );
742 
743  hitColor_AA_X1Y0[i] = color_average;
744  hitColor_AA_X0Y1[i] = color_average;
745  hitColor_AA_X0Y1_half[i] = color_average;
746  }
747 
748  RAY blockRayPck_AA_X1Y0[RAYPACKET_RAYS_PER_PACKET];
749  RAY blockRayPck_AA_X0Y1[RAYPACKET_RAYS_PER_PACKET];
750  RAY blockRayPck_AA_X1Y1_half[RAYPACKET_RAYS_PER_PACKET];
751 
753  m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f - DISP_FACTOR, DISP_FACTOR ),
754  SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y0 );
755 
757  m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, 0.5f - DISP_FACTOR ),
758  SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X0Y1 );
759 
761  m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.25f - DISP_FACTOR, 0.25f - DISP_FACTOR ),
762  SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y1_half );
763 
764  renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1, blockRayPck_AA_X1Y0,
765  hitColor_AA_X1Y0 );
766 
767  renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1, blockRayPck_AA_X0Y1,
768  hitColor_AA_X0Y1 );
769 
770  renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1,
771  blockRayPck_AA_X1Y1_half, hitColor_AA_X0Y1_half );
772 
773  // Average the result
774  for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
775  {
776  hitColor_X0Y0[i] = ( hitColor_X0Y0[i] + hitColor_AA_X1Y1[i] + hitColor_AA_X1Y0[i] +
777  hitColor_AA_X0Y1[i] + hitColor_AA_X0Y1_half[i] ) *
778  SFVEC3F( 1.0f / 5.0f );
779  }
780  }
781 
782  // Copy results to the next stage
783  GLubyte* ptr = &ptrPBO[( blockPos.x + ( blockPos.y * m_realBufferSize.x ) ) * 4];
784 
785  const uint32_t ptrInc = ( m_realBufferSize.x - RAYPACKET_DIM ) * 4;
786 
788  {
789  SFVEC2I bPos;
790  bPos.y = blockPos.y;
791 
792  for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
793  {
794  bPos.x = blockPos.x;
795 
796  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
797  {
798  const SFVEC3F& hColor = hitColor_X0Y0[i];
799 
800  if( hitPacket_X0Y0[i].m_hitresult == true )
801  m_postShaderSsao.SetPixelData( bPos.x, bPos.y,
802  hitPacket_X0Y0[i].m_HitInfo.m_HitNormal,
803  hColor,
804  blockPacket.m_ray[i].at(
805  hitPacket_X0Y0[i].m_HitInfo.m_tHit ),
806  hitPacket_X0Y0[i].m_HitInfo.m_tHit,
807  hitPacket_X0Y0[i].m_HitInfo.m_ShadowFactor );
808  else
809  m_postShaderSsao.SetPixelData( bPos.x, bPos.y, SFVEC3F( 0.0f ), hColor,
810  SFVEC3F( 0.0f ), 0, 1.0f );
811 
812  renderFinalColor( ptr, hColor, false );
813 
814  bPos.x++;
815  ptr += 4;
816  }
817 
818  ptr += ptrInc;
819  bPos.y++;
820  }
821  }
822  else
823  {
824  for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
825  {
826  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
827  {
828  renderFinalColor( ptr, hitColor_X0Y0[i], true );
829  ptr += 4;
830  }
831 
832  ptr += ptrInc;
833  }
834  }
835 }
836 
837 
838 void RENDER_3D_RAYTRACE::postProcessShading( GLubyte* /* ptrPBO */, REPORTER* aStatusReporter )
839 {
841  {
842  if( aStatusReporter )
843  aStatusReporter->Report( _( "Rendering: Post processing shader" ) );
844 
847 
848  std::atomic<size_t> nextBlock( 0 );
849  std::atomic<size_t> threadsFinished( 0 );
850 
851  size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
852 
853  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
854  {
855  std::thread t = std::thread( [&]()
856  {
857  for( size_t y = nextBlock.fetch_add( 1 ); y < m_realBufferSize.y;
858  y = nextBlock.fetch_add( 1 ) )
859  {
860  SFVEC3F* ptr = &m_shaderBuffer[ y * m_realBufferSize.x ];
861 
862  for( signed int x = 0; x < (int)m_realBufferSize.x; ++x )
863  {
864  *ptr = m_postShaderSsao.Shade( SFVEC2I( x, y ) );
865  ptr++;
866  }
867  }
868 
869  threadsFinished++;
870  } );
871 
872  t.detach();
873  }
874 
875  while( threadsFinished < parallelThreadCount )
876  std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
877 
879 
880  // Set next state
882  }
883  else
884  {
885  // As this was an invalid state, set to finish
887  }
888 }
889 
890 
891 void RENDER_3D_RAYTRACE::postProcessBlurFinish( GLubyte* ptrPBO, REPORTER* /* aStatusReporter */ )
892 {
894  {
895  // Now blurs the shader result and compute the final color
896  std::atomic<size_t> nextBlock( 0 );
897  std::atomic<size_t> threadsFinished( 0 );
898 
899  size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
900 
901  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
902  {
903  std::thread t = std::thread( [&]()
904  {
905  for( size_t y = nextBlock.fetch_add( 1 ); y < m_realBufferSize.y;
906  y = nextBlock.fetch_add( 1 ) )
907  {
908  GLubyte* ptr = &ptrPBO[ y * m_realBufferSize.x * 4 ];
909 
910  for( signed int x = 0; x < (int)m_realBufferSize.x; ++x )
911  {
912  const SFVEC3F bluredShadeColor = m_postShaderSsao.Blur( SFVEC2I( x, y ) );
913 
914 #ifdef USE_SRGB_SPACE
915  const SFVEC3F originColor = convertLinearToSRGB(
917 #else
918  const SFVEC3F originColor =
920 #endif
921  const SFVEC3F shadedColor = m_postShaderSsao.ApplyShadeColor(
922  SFVEC2I( x, y ), originColor, bluredShadeColor );
923 
924  renderFinalColor( ptr, shadedColor, false );
925 
926  ptr += 4;
927  }
928  }
929 
930  threadsFinished++;
931  } );
932 
933  t.detach();
934  }
935 
936  while( threadsFinished < parallelThreadCount )
937  std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
938 
939  // Debug code
940  //m_postShaderSsao.DebugBuffersOutputAsImages();
941  }
942 
943  // End rendering
945 }
946 
947 
948 void RENDER_3D_RAYTRACE::renderPreview( GLubyte* ptrPBO )
949 {
950  m_isPreview = true;
951 
952  std::atomic<size_t> nextBlock( 0 );
953  std::atomic<size_t> threadsFinished( 0 );
954 
955  size_t parallelThreadCount = std::min<size_t>(
956  std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
957  m_blockPositions.size() );
958 
959  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
960  {
961  std::thread t = std::thread( [&]()
962  {
963  for( size_t iBlock = nextBlock.fetch_add( 1 ); iBlock < m_blockPositionsFast.size();
964  iBlock = nextBlock.fetch_add( 1 ) )
965  {
966  const SFVEC2UI& windowPosUI = m_blockPositionsFast[ iBlock ];
967  const SFVEC2I windowsPos = SFVEC2I( windowPosUI.x + m_xoffset,
968  windowPosUI.y + m_yoffset );
969 
970  RAYPACKET blockPacket( m_camera, windowsPos, 4 );
971 
973 
974  // Initialize hitPacket with a "not hit" information
975  for( HITINFO_PACKET& packet : hitPacket )
976  {
977  packet.m_HitInfo.m_tHit = std::numeric_limits<float>::infinity();
978  packet.m_HitInfo.m_acc_node_info = 0;
979  packet.m_hitresult = false;
980  }
981 
982  // Intersect packet block
983  m_accelerator->Intersect( blockPacket, hitPacket );
984 
985  // Calculate background gradient color
986  SFVEC3F bgColor[RAYPACKET_DIM];
987 
988  for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
989  {
990  const float posYfactor =
991  (float) ( windowsPos.y + y * 4.0f ) / (float) m_windowSize.y;
992 
993  bgColor[y] = (SFVEC3F) m_boardAdapter.m_BgColorTop * SFVEC3F( posYfactor )
995  * ( SFVEC3F( 1.0f ) - SFVEC3F( posYfactor ) );
996  }
997 
998  COLOR_RGB hitColorShading[RAYPACKET_RAYS_PER_PACKET];
999 
1000  for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
1001  {
1002  const SFVEC3F bhColorY = bgColor[i / RAYPACKET_DIM];
1003 
1004  if( hitPacket[i].m_hitresult == true )
1005  {
1006  const SFVEC3F hitColor = shadeHit( bhColorY, blockPacket.m_ray[i],
1007  hitPacket[i].m_HitInfo, false,
1008  0, false );
1009 
1010  hitColorShading[i] = COLOR_RGB( hitColor );
1011  }
1012  else
1013  hitColorShading[i] = bhColorY;
1014  }
1015 
1016  COLOR_RGB cLRB_old[(RAYPACKET_DIM - 1)];
1017 
1018  for( unsigned int y = 0; y < (RAYPACKET_DIM - 1); ++y )
1019  {
1020  const SFVEC3F bgColorY = bgColor[y];
1021  const COLOR_RGB bgColorYRGB = COLOR_RGB( bgColorY );
1022 
1023  // This stores cRTB from the last block to be reused next time in a cLTB pixel
1024  COLOR_RGB cRTB_old;
1025 
1026  //RAY cRTB_ray;
1027  //HITINFO cRTB_hitInfo;
1028 
1029  for( unsigned int x = 0; x < ( RAYPACKET_DIM - 1 ); ++x )
1030  {
1031  // pxl 0 pxl 1 pxl 2 pxl 3 pxl 4
1032  // x0 x1 ...
1033  // .---------------------------.
1034  // y0 | cLT | cxxx | cLRT | cxxx | cRT |
1035  // | cxxx | cLTC | cxxx | cRTC | cxxx |
1036  // | cLTB | cxxx | cC | cxxx | cRTB |
1037  // | cxxx | cLBC | cxxx | cRBC | cxxx |
1038  // '---------------------------'
1039  // y1 | cLB | cxxx | cLRB | cxxx | cRB |
1040 
1041  const unsigned int iLT = ( ( x + 0 ) + RAYPACKET_DIM * ( y + 0 ) );
1042  const unsigned int iRT = ( ( x + 1 ) + RAYPACKET_DIM * ( y + 0 ) );
1043  const unsigned int iLB = ( ( x + 0 ) + RAYPACKET_DIM * ( y + 1 ) );
1044  const unsigned int iRB = ( ( x + 1 ) + RAYPACKET_DIM * ( y + 1 ) );
1045 
1046  // !TODO: skip when there are no hits
1047  const COLOR_RGB& cLT = hitColorShading[ iLT ];
1048  const COLOR_RGB& cRT = hitColorShading[ iRT ];
1049  const COLOR_RGB& cLB = hitColorShading[ iLB ];
1050  const COLOR_RGB& cRB = hitColorShading[ iRB ];
1051 
1052  // Trace and shade cC
1053  COLOR_RGB cC = bgColorYRGB;
1054 
1055  const SFVEC3F& oriLT = blockPacket.m_ray[ iLT ].m_Origin;
1056  const SFVEC3F& oriRB = blockPacket.m_ray[ iRB ].m_Origin;
1057 
1058  const SFVEC3F& dirLT = blockPacket.m_ray[ iLT ].m_Dir;
1059  const SFVEC3F& dirRB = blockPacket.m_ray[ iRB ].m_Dir;
1060 
1061  SFVEC3F oriC;
1062  SFVEC3F dirC;
1063 
1064  HITINFO centerHitInfo;
1065  centerHitInfo.m_tHit = std::numeric_limits<float>::infinity();
1066 
1067  bool hittedC = false;
1068 
1069  if( ( hitPacket[iLT].m_hitresult == true )
1070  || ( hitPacket[iRT].m_hitresult == true )
1071  || ( hitPacket[iLB].m_hitresult == true )
1072  || ( hitPacket[iRB].m_hitresult == true ) )
1073  {
1074  oriC = ( oriLT + oriRB ) * 0.5f;
1075  dirC = glm::normalize( ( dirLT + dirRB ) * 0.5f );
1076 
1077  // Trace the center ray
1078  RAY centerRay;
1079  centerRay.Init( oriC, dirC );
1080 
1081  const unsigned int nodeLT = hitPacket[ iLT ].m_HitInfo.m_acc_node_info;
1082  const unsigned int nodeRT = hitPacket[ iRT ].m_HitInfo.m_acc_node_info;
1083  const unsigned int nodeLB = hitPacket[ iLB ].m_HitInfo.m_acc_node_info;
1084  const unsigned int nodeRB = hitPacket[ iRB ].m_HitInfo.m_acc_node_info;
1085 
1086  if( nodeLT != 0 )
1087  hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1088  nodeLT );
1089 
1090  if( ( nodeRT != 0 ) && ( nodeRT != nodeLT ) )
1091  hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1092  nodeRT );
1093 
1094  if( ( nodeLB != 0 ) && ( nodeLB != nodeLT ) && ( nodeLB != nodeRT ) )
1095  hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1096  nodeLB );
1097 
1098  if( ( nodeRB != 0 ) && ( nodeRB != nodeLB ) && ( nodeRB != nodeLT )
1099  && ( nodeRB != nodeRT ) )
1100  hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1101  nodeRB );
1102 
1103  if( hittedC )
1104  {
1105  cC = COLOR_RGB( shadeHit( bgColorY, centerRay, centerHitInfo,
1106  false, 0, false ) );
1107  }
1108  else
1109  {
1110  centerHitInfo.m_tHit = std::numeric_limits<float>::infinity();
1111  hittedC = m_accelerator->Intersect( centerRay, centerHitInfo );
1112 
1113  if( hittedC )
1114  cC = COLOR_RGB( shadeHit( bgColorY, centerRay, centerHitInfo,
1115  false, 0, false ) );
1116  }
1117  }
1118 
1119  // Trace and shade cLRT
1120  COLOR_RGB cLRT = bgColorYRGB;
1121 
1122  const SFVEC3F& oriRT = blockPacket.m_ray[ iRT ].m_Origin;
1123  const SFVEC3F& dirRT = blockPacket.m_ray[ iRT ].m_Dir;
1124 
1125  if( y == 0 )
1126  {
1127  // Trace the center ray
1128  RAY rayLRT;
1129  rayLRT.Init( ( oriLT + oriRT ) * 0.5f,
1130  glm::normalize( ( dirLT + dirRT ) * 0.5f ) );
1131 
1132  HITINFO hitInfoLRT;
1133  hitInfoLRT.m_tHit = std::numeric_limits<float>::infinity();
1134 
1135  if( hitPacket[iLT].m_hitresult && hitPacket[iRT].m_hitresult
1136  && ( hitPacket[iLT].m_HitInfo.pHitObject
1137  == hitPacket[iRT].m_HitInfo.pHitObject ) )
1138  {
1139  hitInfoLRT.pHitObject = hitPacket[ iLT ].m_HitInfo.pHitObject;
1140  hitInfoLRT.m_tHit = ( hitPacket[ iLT ].m_HitInfo.m_tHit +
1141  hitPacket[ iRT ].m_HitInfo.m_tHit ) * 0.5f;
1142  hitInfoLRT.m_HitNormal =
1143  glm::normalize( ( hitPacket[ iLT ].m_HitInfo.m_HitNormal +
1144  hitPacket[ iRT ].m_HitInfo.m_HitNormal ) * 0.5f );
1145 
1146  cLRT = COLOR_RGB( shadeHit( bgColorY, rayLRT, hitInfoLRT, false,
1147  0, false ) );
1148  cLRT = BlendColor( cLRT, BlendColor( cLT, cRT ) );
1149  }
1150  else
1151  {
1152  // If any hits
1153  if( hitPacket[ iLT ].m_hitresult || hitPacket[ iRT ].m_hitresult )
1154  {
1155  const unsigned int nodeLT =
1156  hitPacket[ iLT ].m_HitInfo.m_acc_node_info;
1157  const unsigned int nodeRT =
1158  hitPacket[ iRT ].m_HitInfo.m_acc_node_info;
1159 
1160  bool hittedLRT = false;
1161 
1162  if( nodeLT != 0 )
1163  hittedLRT |= m_accelerator->Intersect( rayLRT, hitInfoLRT,
1164  nodeLT );
1165 
1166  if( ( nodeRT != 0 ) && ( nodeRT != nodeLT ) )
1167  hittedLRT |= m_accelerator->Intersect( rayLRT, hitInfoLRT,
1168  nodeRT );
1169 
1170  if( hittedLRT )
1171  cLRT = COLOR_RGB( shadeHit( bgColorY, rayLRT, hitInfoLRT,
1172  false, 0, false ) );
1173  else
1174  {
1175  hitInfoLRT.m_tHit = std::numeric_limits<float>::infinity();
1176 
1177  if( m_accelerator->Intersect( rayLRT,hitInfoLRT ) )
1178  cLRT = COLOR_RGB( shadeHit( bgColorY, rayLRT,
1179  hitInfoLRT, false,
1180  0, false ) );
1181  }
1182  }
1183  }
1184  }
1185  else
1186  {
1187  cLRT = cLRB_old[x];
1188  }
1189 
1190  // Trace and shade cLTB
1191  COLOR_RGB cLTB = bgColorYRGB;
1192 
1193  if( x == 0 )
1194  {
1195  const SFVEC3F &oriLB = blockPacket.m_ray[ iLB ].m_Origin;
1196  const SFVEC3F& dirLB = blockPacket.m_ray[ iLB ].m_Dir;
1197 
1198  // Trace the center ray
1199  RAY rayLTB;
1200  rayLTB.Init( ( oriLT + oriLB ) * 0.5f,
1201  glm::normalize( ( dirLT + dirLB ) * 0.5f ) );
1202 
1203  HITINFO hitInfoLTB;
1204  hitInfoLTB.m_tHit = std::numeric_limits<float>::infinity();
1205 
1206  if( hitPacket[ iLT ].m_hitresult && hitPacket[ iLB ].m_hitresult
1207  && ( hitPacket[ iLT ].m_HitInfo.pHitObject ==
1208  hitPacket[ iLB ].m_HitInfo.pHitObject ) )
1209  {
1210  hitInfoLTB.pHitObject = hitPacket[ iLT ].m_HitInfo.pHitObject;
1211  hitInfoLTB.m_tHit = ( hitPacket[ iLT ].m_HitInfo.m_tHit +
1212  hitPacket[ iLB ].m_HitInfo.m_tHit ) * 0.5f;
1213  hitInfoLTB.m_HitNormal =
1214  glm::normalize( ( hitPacket[ iLT ].m_HitInfo.m_HitNormal +
1215  hitPacket[ iLB ].m_HitInfo.m_HitNormal ) * 0.5f );
1216  cLTB = COLOR_RGB( shadeHit( bgColorY, rayLTB, hitInfoLTB, false,
1217  0, false ) );
1218  cLTB = BlendColor( cLTB, BlendColor( cLT, cLB) );
1219  }
1220  else
1221  {
1222  // If any hits
1223  if( hitPacket[ iLT ].m_hitresult || hitPacket[ iLB ].m_hitresult )
1224  {
1225  const unsigned int nodeLT =
1226  hitPacket[ iLT ].m_HitInfo.m_acc_node_info;
1227  const unsigned int nodeLB =
1228  hitPacket[ iLB ].m_HitInfo.m_acc_node_info;
1229 
1230  bool hittedLTB = false;
1231 
1232  if( nodeLT != 0 )
1233  hittedLTB |= m_accelerator->Intersect( rayLTB, hitInfoLTB,
1234  nodeLT );
1235 
1236  if( ( nodeLB != 0 ) && ( nodeLB != nodeLT ) )
1237  hittedLTB |= m_accelerator->Intersect( rayLTB, hitInfoLTB,
1238  nodeLB );
1239 
1240  if( hittedLTB )
1241  cLTB = COLOR_RGB( shadeHit( bgColorY, rayLTB, hitInfoLTB,
1242  false, 0, false ) );
1243  else
1244  {
1245  hitInfoLTB.m_tHit = std::numeric_limits<float>::infinity();
1246 
1247  if( m_accelerator->Intersect( rayLTB, hitInfoLTB ) )
1248  cLTB = COLOR_RGB( shadeHit( bgColorY, rayLTB,
1249  hitInfoLTB, false,
1250  0, false ) );
1251  }
1252  }
1253  }
1254  }
1255  else
1256  {
1257  cLTB = cRTB_old;
1258  }
1259 
1260  // Trace and shade cRTB
1261  COLOR_RGB cRTB = bgColorYRGB;
1262 
1263  // Trace the center ray
1264  RAY rayRTB;
1265  rayRTB.Init( ( oriRT + oriRB ) * 0.5f,
1266  glm::normalize( ( dirRT + dirRB ) * 0.5f ) );
1267 
1268  HITINFO hitInfoRTB;
1269  hitInfoRTB.m_tHit = std::numeric_limits<float>::infinity();
1270 
1271  if( hitPacket[ iRT ].m_hitresult && hitPacket[ iRB ].m_hitresult
1272  && ( hitPacket[ iRT ].m_HitInfo.pHitObject ==
1273  hitPacket[ iRB ].m_HitInfo.pHitObject ) )
1274  {
1275  hitInfoRTB.pHitObject = hitPacket[ iRT ].m_HitInfo.pHitObject;
1276 
1277  hitInfoRTB.m_tHit = ( hitPacket[ iRT ].m_HitInfo.m_tHit +
1278  hitPacket[ iRB ].m_HitInfo.m_tHit ) * 0.5f;
1279 
1280  hitInfoRTB.m_HitNormal =
1281  glm::normalize( ( hitPacket[ iRT ].m_HitInfo.m_HitNormal +
1282  hitPacket[ iRB ].m_HitInfo.m_HitNormal ) * 0.5f );
1283 
1284  cRTB = COLOR_RGB( shadeHit( bgColorY, rayRTB, hitInfoRTB, false, 0,
1285  false ) );
1286  cRTB = BlendColor( cRTB, BlendColor( cRT, cRB ) );
1287  }
1288  else
1289  {
1290  // If any hits
1291  if( hitPacket[ iRT ].m_hitresult || hitPacket[ iRB ].m_hitresult )
1292  {
1293  const unsigned int nodeRT =
1294  hitPacket[ iRT ].m_HitInfo.m_acc_node_info;
1295  const unsigned int nodeRB =
1296  hitPacket[ iRB ].m_HitInfo.m_acc_node_info;
1297 
1298  bool hittedRTB = false;
1299 
1300  if( nodeRT != 0 )
1301  hittedRTB |= m_accelerator->Intersect( rayRTB, hitInfoRTB,
1302  nodeRT );
1303 
1304  if( ( nodeRB != 0 ) && ( nodeRB != nodeRT ) )
1305  hittedRTB |= m_accelerator->Intersect( rayRTB, hitInfoRTB,
1306  nodeRB );
1307 
1308  if( hittedRTB )
1309  {
1310  cRTB = COLOR_RGB( shadeHit( bgColorY, rayRTB, hitInfoRTB,
1311  false, 0, false) );
1312  }
1313  else
1314  {
1315  hitInfoRTB.m_tHit = std::numeric_limits<float>::infinity();
1316 
1317  if( m_accelerator->Intersect( rayRTB, hitInfoRTB ) )
1318  cRTB = COLOR_RGB( shadeHit( bgColorY, rayRTB, hitInfoRTB,
1319  false, 0, false ) );
1320  }
1321  }
1322  }
1323 
1324  cRTB_old = cRTB;
1325 
1326  // Trace and shade cLRB
1327  COLOR_RGB cLRB = bgColorYRGB;
1328 
1329  const SFVEC3F& oriLB = blockPacket.m_ray[ iLB ].m_Origin;
1330  const SFVEC3F& dirLB = blockPacket.m_ray[ iLB ].m_Dir;
1331 
1332  // Trace the center ray
1333  RAY rayLRB;
1334  rayLRB.Init( ( oriLB + oriRB ) * 0.5f,
1335  glm::normalize( ( dirLB + dirRB ) * 0.5f ) );
1336 
1337  HITINFO hitInfoLRB;
1338  hitInfoLRB.m_tHit = std::numeric_limits<float>::infinity();
1339 
1340  if( hitPacket[iLB].m_hitresult && hitPacket[iRB].m_hitresult
1341  && ( hitPacket[iLB].m_HitInfo.pHitObject ==
1342  hitPacket[iRB].m_HitInfo.pHitObject ) )
1343  {
1344  hitInfoLRB.pHitObject = hitPacket[ iLB ].m_HitInfo.pHitObject;
1345 
1346  hitInfoLRB.m_tHit = ( hitPacket[ iLB ].m_HitInfo.m_tHit +
1347  hitPacket[ iRB ].m_HitInfo.m_tHit ) * 0.5f;
1348 
1349  hitInfoLRB.m_HitNormal =
1350  glm::normalize( ( hitPacket[ iLB ].m_HitInfo.m_HitNormal +
1351  hitPacket[ iRB ].m_HitInfo.m_HitNormal ) * 0.5f );
1352 
1353  cLRB = COLOR_RGB( shadeHit( bgColorY, rayLRB, hitInfoLRB, false, 0,
1354  false ) );
1355  cLRB = BlendColor( cLRB, BlendColor( cLB, cRB ) );
1356  }
1357  else
1358  {
1359  // If any hits
1360  if( hitPacket[ iLB ].m_hitresult || hitPacket[ iRB ].m_hitresult )
1361  {
1362  const unsigned int nodeLB =
1363  hitPacket[ iLB ].m_HitInfo.m_acc_node_info;
1364  const unsigned int nodeRB =
1365  hitPacket[ iRB ].m_HitInfo.m_acc_node_info;
1366 
1367  bool hittedLRB = false;
1368 
1369  if( nodeLB != 0 )
1370  hittedLRB |= m_accelerator->Intersect( rayLRB, hitInfoLRB,
1371  nodeLB );
1372 
1373  if( ( nodeRB != 0 ) && ( nodeRB != nodeLB ) )
1374  hittedLRB |= m_accelerator->Intersect( rayLRB, hitInfoLRB,
1375  nodeRB );
1376 
1377  if( hittedLRB )
1378  {
1379  cLRB = COLOR_RGB( shadeHit( bgColorY, rayLRB, hitInfoLRB,
1380  false, 0, false ) );
1381  }
1382  else
1383  {
1384  hitInfoLRB.m_tHit = std::numeric_limits<float>::infinity();
1385 
1386  if( m_accelerator->Intersect( rayLRB, hitInfoLRB ) )
1387  cLRB = COLOR_RGB( shadeHit( bgColorY, rayLRB, hitInfoLRB,
1388  false, 0, false ) );
1389  }
1390  }
1391  }
1392 
1393  cLRB_old[x] = cLRB;
1394 
1395  // Trace and shade cLTC
1396  COLOR_RGB cLTC = BlendColor( cLT , cC );
1397 
1398  if( hitPacket[ iLT ].m_hitresult || hittedC )
1399  {
1400  // Trace the center ray
1401  RAY rayLTC;
1402  rayLTC.Init( ( oriLT + oriC ) * 0.5f,
1403  glm::normalize( ( dirLT + dirC ) * 0.5f ) );
1404 
1405  HITINFO hitInfoLTC;
1406  hitInfoLTC.m_tHit = std::numeric_limits<float>::infinity();
1407 
1408  bool hitted = false;
1409 
1410  if( hittedC )
1411  hitted = centerHitInfo.pHitObject->Intersect( rayLTC, hitInfoLTC );
1412  else if( hitPacket[ iLT ].m_hitresult )
1413  hitted = hitPacket[ iLT ].m_HitInfo.pHitObject->Intersect(
1414  rayLTC,
1415  hitInfoLTC );
1416 
1417  if( hitted )
1418  cLTC = COLOR_RGB( shadeHit( bgColorY, rayLTC, hitInfoLTC, false,
1419  0, false ) );
1420  }
1421 
1422  // Trace and shade cRTC
1423  COLOR_RGB cRTC = BlendColor( cRT , cC );
1424 
1425  if( hitPacket[ iRT ].m_hitresult || hittedC )
1426  {
1427  // Trace the center ray
1428  RAY rayRTC;
1429  rayRTC.Init( ( oriRT + oriC ) * 0.5f,
1430  glm::normalize( ( dirRT + dirC ) * 0.5f ) );
1431 
1432  HITINFO hitInfoRTC;
1433  hitInfoRTC.m_tHit = std::numeric_limits<float>::infinity();
1434 
1435  bool hitted = false;
1436 
1437  if( hittedC )
1438  hitted = centerHitInfo.pHitObject->Intersect( rayRTC, hitInfoRTC );
1439  else if( hitPacket[ iRT ].m_hitresult )
1440  hitted = hitPacket[ iRT ].m_HitInfo.pHitObject->Intersect( rayRTC,
1441  hitInfoRTC );
1442 
1443  if( hitted )
1444  cRTC = COLOR_RGB( shadeHit( bgColorY, rayRTC, hitInfoRTC, false,
1445  0, false ) );
1446  }
1447 
1448  // Trace and shade cLBC
1449  COLOR_RGB cLBC = BlendColor( cLB , cC );
1450 
1451  if( hitPacket[ iLB ].m_hitresult || hittedC )
1452  {
1453  // Trace the center ray
1454  RAY rayLBC;
1455  rayLBC.Init( ( oriLB + oriC ) * 0.5f,
1456  glm::normalize( ( dirLB + dirC ) * 0.5f ) );
1457 
1458  HITINFO hitInfoLBC;
1459  hitInfoLBC.m_tHit = std::numeric_limits<float>::infinity();
1460 
1461  bool hitted = false;
1462 
1463  if( hittedC )
1464  hitted = centerHitInfo.pHitObject->Intersect( rayLBC, hitInfoLBC );
1465  else if( hitPacket[ iLB ].m_hitresult )
1466  hitted = hitPacket[ iLB ].m_HitInfo.pHitObject->Intersect( rayLBC,
1467  hitInfoLBC );
1468 
1469  if( hitted )
1470  cLBC = COLOR_RGB( shadeHit( bgColorY, rayLBC, hitInfoLBC, false,
1471  0, false ) );
1472  }
1473 
1474  // Trace and shade cRBC
1475  COLOR_RGB cRBC = BlendColor( cRB , cC );
1476 
1477  if( hitPacket[ iRB ].m_hitresult || hittedC )
1478  {
1479  // Trace the center ray
1480  RAY rayRBC;
1481  rayRBC.Init( ( oriRB + oriC ) * 0.5f,
1482  glm::normalize( ( dirRB + dirC ) * 0.5f ) );
1483 
1484  HITINFO hitInfoRBC;
1485  hitInfoRBC.m_tHit = std::numeric_limits<float>::infinity();
1486 
1487  bool hitted = false;
1488 
1489  if( hittedC )
1490  hitted = centerHitInfo.pHitObject->Intersect( rayRBC, hitInfoRBC );
1491  else if( hitPacket[ iRB ].m_hitresult )
1492  hitted = hitPacket[ iRB ].m_HitInfo.pHitObject->Intersect( rayRBC,
1493  hitInfoRBC );
1494 
1495  if( hitted )
1496  cRBC = COLOR_RGB( shadeHit( bgColorY, rayRBC, hitInfoRBC, false,
1497  0, false ) );
1498  }
1499 
1500  // Set pixel colors
1501  GLubyte* ptr =
1502  &ptrPBO[( 4 * x + m_blockPositionsFast[iBlock].x
1503  + m_realBufferSize.x
1504  * ( m_blockPositionsFast[iBlock].y + 4 * y ) ) * 4];
1505  SetPixel( ptr + 0, cLT );
1506  SetPixel( ptr + 4, BlendColor( cLT, cLRT, cLTC ) );
1507  SetPixel( ptr + 8, cLRT );
1508  SetPixel( ptr + 12, BlendColor( cLRT, cRT, cRTC ) );
1509 
1510  ptr += m_realBufferSize.x * 4;
1511  SetPixel( ptr + 0, BlendColor( cLT , cLTB, cLTC ) );
1512  SetPixel( ptr + 4, BlendColor( cLTC, BlendColor( cLT , cC ) ) );
1513  SetPixel( ptr + 8, BlendColor( cC, BlendColor( cLRT, cLTC, cRTC ) ) );
1514  SetPixel( ptr + 12, BlendColor( cRTC, BlendColor( cRT , cC ) ) );
1515 
1516  ptr += m_realBufferSize.x * 4;
1517  SetPixel( ptr + 0, cLTB );
1518  SetPixel( ptr + 4, BlendColor( cC, BlendColor( cLTB, cLTC, cLBC ) ) );
1519  SetPixel( ptr + 8, cC );
1520  SetPixel( ptr + 12, BlendColor( cC, BlendColor( cRTB, cRTC, cRBC ) ) );
1521 
1522  ptr += m_realBufferSize.x * 4;
1523  SetPixel( ptr + 0, BlendColor( cLB , cLTB, cLBC ) );
1524  SetPixel( ptr + 4, BlendColor( cLBC, BlendColor( cLB , cC ) ) );
1525  SetPixel( ptr + 8, BlendColor( cC, BlendColor( cLRB, cLBC, cRBC ) ) );
1526  SetPixel( ptr + 12, BlendColor( cRBC, BlendColor( cRB , cC ) ) );
1527  }
1528  }
1529  }
1530 
1531  threadsFinished++;
1532  } );
1533 
1534  t.detach();
1535  }
1536 
1537  while( threadsFinished < parallelThreadCount )
1538  std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1539 }
1540 
1541 
1542 #define USE_EXPERIMENTAL_SOFT_SHADOWS 1
1543 
1544 SFVEC3F RENDER_3D_RAYTRACE::shadeHit( const SFVEC3F& aBgColor, const RAY& aRay, HITINFO& aHitInfo,
1545  bool aIsInsideObject, unsigned int aRecursiveLevel,
1546  bool is_testShadow ) const
1547 {
1548  const MATERIAL* objMaterial = aHitInfo.pHitObject->GetMaterial();
1549  wxASSERT( objMaterial != nullptr );
1550 
1551  SFVEC3F outColor = objMaterial->GetEmissiveColor() + objMaterial->GetAmbientColor();
1552 
1553  if( aRecursiveLevel > 7 )
1554  return outColor;
1555 
1556  SFVEC3F hitPoint = aHitInfo.m_HitPoint;
1557 
1558  hitPoint += aHitInfo.m_HitNormal * m_boardAdapter.GetNonCopperLayerThickness() * 0.6f;
1559 
1560  const SFVEC3F diffuseColorObj = aHitInfo.pHitObject->GetDiffuseColor( aHitInfo );
1561 
1562 #if USE_EXPERIMENTAL_SOFT_SHADOWS
1563  const bool is_aa_enabled = m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_ANTI_ALIASING ) &&
1564  (!m_isPreview);
1565 #endif
1566 
1567  float shadow_att_factor_sum = 0.0f;
1568 
1569  unsigned int nr_lights_that_can_cast_shadows = 0;
1570 
1571  for( const LIGHT* light : m_lights )
1572  {
1573  SFVEC3F vectorToLight;
1574  SFVEC3F colorOfLight;
1575  float distToLight;
1576 
1577  light->GetLightParameters( hitPoint, vectorToLight, colorOfLight, distToLight );
1578 
1579  if( m_isPreview )
1580  colorOfLight = SFVEC3F( 1.0f );
1581 
1582  const float NdotL = glm::dot( aHitInfo.m_HitNormal, vectorToLight );
1583 
1584  // Only calc shade if the normal is facing the direction of light,
1585  // otherwise it is in the shadow
1586  if( NdotL >= FLT_EPSILON )
1587  {
1588  float shadow_att_factor_light = 1.0f;
1589 
1590  if( is_testShadow && light->GetCastShadows() )
1591  {
1592  nr_lights_that_can_cast_shadows++;
1593 #if USE_EXPERIMENTAL_SOFT_SHADOWS
1594  // For rays that are recursive, just calculate one hit shadow
1595  if( aRecursiveLevel > 0 )
1596  {
1597 #endif
1598  RAY rayToLight;
1599  rayToLight.Init( hitPoint, vectorToLight );
1600 
1601  // Test if point is not in the shadow.
1602  // Test for any hit from the point in the direction of light
1603  if( m_accelerator->IntersectP( rayToLight, distToLight ) )
1604  shadow_att_factor_light = 0.0f;
1605 
1606 #if USE_EXPERIMENTAL_SOFT_SHADOWS
1607  }
1608  else // Experimental softshadow calculation
1609  {
1610 
1611  const unsigned int shadow_number_of_samples =
1613  const float shadow_inc_factor = 1.0f / (float) ( shadow_number_of_samples );
1614 
1615  for( unsigned int i = 0; i < shadow_number_of_samples; ++i )
1616  {
1617  RAY rayToLight;
1618 
1619  if( i == 0 )
1620  {
1621  rayToLight.Init( hitPoint, vectorToLight );
1622  }
1623  else
1624  {
1625  const SFVEC3F unifVector = UniformRandomHemisphereDirection();
1626  const SFVEC3F disturbed_vector_to_light =
1627  glm::normalize( vectorToLight + unifVector *
1629 
1630  rayToLight.Init( hitPoint, disturbed_vector_to_light );
1631  }
1632 
1633  // !TODO: there are multiple ways that this tests can be
1634  // optimized. Eg: by packing rays or to test against the
1635  // latest hit object.
1636  if( m_accelerator->IntersectP( rayToLight, distToLight ) )
1637  {
1638  shadow_att_factor_light -= shadow_inc_factor;
1639  }
1640  }
1641  }
1642 #endif
1643  shadow_att_factor_sum += shadow_att_factor_light;
1644  }
1645 
1646  outColor += objMaterial->Shade( aRay, aHitInfo, NdotL, diffuseColorObj, vectorToLight,
1647  colorOfLight, shadow_att_factor_light );
1648  }
1649 
1650  // Only use the headlight for preview
1651  if( m_isPreview )
1652  break;
1653  }
1654 
1655  // Improvement: this is not taking in account the lightcolor
1656  if( nr_lights_that_can_cast_shadows > 0 )
1657  {
1658  aHitInfo.m_ShadowFactor = glm::max(
1659  shadow_att_factor_sum / (float) ( nr_lights_that_can_cast_shadows * 1.0f ), 0.0f );
1660  }
1661  else
1662  {
1663  aHitInfo.m_ShadowFactor = 1.0f;
1664  }
1665 
1666  // Clamp color to not be brighter than 1.0f
1667  outColor = glm::min( outColor, SFVEC3F( 1.0f ) );
1668 
1669  if( !m_isPreview )
1670  {
1671  // Reflections
1672  if( ( objMaterial->GetReflection() > 0.0f )
1674  && ( aRecursiveLevel < objMaterial->GetReflectionRecursionCount() ) )
1675  {
1676  const unsigned int reflection_number_of_samples =
1677  objMaterial->GetReflectionRayCount();
1678 
1679  SFVEC3F sum_color = SFVEC3F( 0.0f );
1680 
1681  const SFVEC3F reflectVector = aRay.m_Dir - 2.0f *
1682  glm::dot( aRay.m_Dir, aHitInfo.m_HitNormal ) * aHitInfo.m_HitNormal;
1683 
1684  for( unsigned int i = 0; i < reflection_number_of_samples; ++i )
1685  {
1686  RAY reflectedRay;
1687 
1688  if( i == 0 )
1689  {
1690  reflectedRay.Init( hitPoint, reflectVector );
1691  }
1692  else
1693  {
1694  // Apply some randomize to the reflected vector
1695  const SFVEC3F random_reflectVector =
1696  glm::normalize( reflectVector +
1699 
1700  reflectedRay.Init( hitPoint, random_reflectVector );
1701  }
1702 
1703  HITINFO reflectedHit;
1704  reflectedHit.m_tHit = std::numeric_limits<float>::infinity();
1705 
1706  if( m_accelerator->Intersect( reflectedRay, reflectedHit ) )
1707  {
1708  sum_color += ( diffuseColorObj + objMaterial->GetSpecularColor() ) *
1709  shadeHit( aBgColor, reflectedRay, reflectedHit, false,
1710  aRecursiveLevel + 1, is_testShadow ) *
1711  SFVEC3F( objMaterial->GetReflection() *
1712  // Falloff factor
1713  (1.0f / ( 1.0f + 0.75f * reflectedHit.m_tHit *
1714  reflectedHit.m_tHit) ) );
1715  }
1716  }
1717 
1718  outColor += (sum_color / SFVEC3F( (float)reflection_number_of_samples) );
1719  }
1720 
1721  // Refraction
1722  const float objTransparency = aHitInfo.pHitObject->GetModelTransparency();
1723 
1724  if( ( objTransparency > 0.0f ) && m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_REFRACTIONS )
1725  && ( aRecursiveLevel < objMaterial->GetRefractionRecursionCount() ) )
1726  {
1727  const float airIndex = 1.000293f;
1728  const float glassIndex = 1.49f;
1729  const float air_over_glass = airIndex / glassIndex;
1730  const float glass_over_air = glassIndex / airIndex;
1731 
1732  const float refractionRatio = aIsInsideObject?glass_over_air:air_over_glass;
1733 
1734  SFVEC3F refractedVector;
1735 
1736  if( Refract( aRay.m_Dir, aHitInfo.m_HitNormal, refractionRatio, refractedVector ) )
1737  {
1738  // This increase the start point by a "fixed" factor so it will work the
1739  // same for all distances
1740  const SFVEC3F startPoint =
1741  aRay.at( aHitInfo.m_tHit + m_boardAdapter.GetNonCopperLayerThickness() *
1742  0.25f );
1743 
1744  const unsigned int refractions_number_of_samples =
1745  objMaterial->GetRefractionRayCount();
1746 
1747  SFVEC3F sum_color = SFVEC3F(0.0f);
1748 
1749  for( unsigned int i = 0; i < refractions_number_of_samples; ++i )
1750  {
1751  RAY refractedRay;
1752 
1753  if( i == 0 )
1754  {
1755  refractedRay.Init( startPoint, refractedVector );
1756  }
1757  else
1758  {
1759  // apply some randomize to the refracted vector
1760  const SFVEC3F randomizeRefractedVector =
1761  glm::normalize( refractedVector +
1764 
1765  refractedRay.Init( startPoint, randomizeRefractedVector );
1766  }
1767 
1768  HITINFO refractedHit;
1769  refractedHit.m_tHit = std::numeric_limits<float>::infinity();
1770 
1771  SFVEC3F refractedColor = aBgColor;
1772 
1773  if( m_accelerator->Intersect( refractedRay, refractedHit ) )
1774  {
1775  refractedColor = shadeHit( aBgColor, refractedRay, refractedHit,
1776  !aIsInsideObject, aRecursiveLevel + 1, false );
1777 
1778  const SFVEC3F absorbance = ( SFVEC3F(1.0f) - diffuseColorObj ) *
1779  (1.0f - objTransparency ) *
1780  objMaterial->GetAbsorvance() *
1781  refractedHit.m_tHit;
1782 
1783  const SFVEC3F transparency = 1.0f / ( absorbance + 1.0f );
1784 
1785  sum_color += refractedColor * transparency;
1786  }
1787  else
1788  {
1789  sum_color += refractedColor;
1790  }
1791  }
1792 
1793  outColor = outColor * ( 1.0f - objTransparency ) + objTransparency * sum_color
1794  / SFVEC3F( (float) refractions_number_of_samples );
1795  }
1796  else
1797  {
1798  outColor = outColor * ( 1.0f - objTransparency ) + objTransparency * aBgColor;
1799  }
1800  }
1801  }
1802 
1803  return outColor;
1804 }
1805 
1806 
1808 {
1809  initPbo();
1810 }
1811 
1812 
1814 {
1815  if( GLEW_ARB_pixel_buffer_object )
1816  {
1818 
1819  // Try to delete vbo if it was already initialized
1820  deletePbo();
1821 
1822  // Learn about Pixel buffer objects at:
1823  // http://www.songho.ca/opengl/gl_pbo.html
1824  // http://web.eecs.umich.edu/~sugih/courses/eecs487/lectures/25-PBO+Mipmapping.pdf
1825  // "create 2 pixel buffer objects, you need to delete them when program exits.
1826  // glBufferDataARB with NULL pointer reserves only memory space."
1827 
1828  // This sets the number of RGBA pixels
1830 
1831  glGenBuffersARB( 1, &m_pboId );
1832  glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
1833  glBufferDataARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboDataSize, 0, GL_STREAM_DRAW_ARB );
1834  glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
1835 
1836  wxLogTrace( m_logTrace,
1837  wxT( "RENDER_3D_RAYTRACE:: GLEW_ARB_pixel_buffer_object is supported" ) );
1838  }
1839 }
1840 
1841 
1843 {
1844  m_is_opengl_initialized = true;
1845 
1846  return true;
1847 }
1848 
1849 
1850 static float distance( const SFVEC2UI& a, const SFVEC2UI& b )
1851 {
1852  const float dx = (float) a.x - (float) b.x;
1853  const float dy = (float) a.y - (float) b.y;
1854  return hypotf( dx, dy );
1855 }
1856 
1857 
1859 {
1860  m_realBufferSize = SFVEC2UI( 0 );
1861 
1862  // Calc block positions for fast preview mode
1863  m_blockPositionsFast.clear();
1864 
1865  unsigned int i = 0;
1866 
1867  while(1)
1868  {
1869  const unsigned int mX = DecodeMorton2X(i);
1870  const unsigned int mY = DecodeMorton2Y(i);
1871 
1872  i++;
1873 
1874  const SFVEC2UI blockPos( mX * 4 * RAYPACKET_DIM - mX * 4,
1875  mY * 4 * RAYPACKET_DIM - mY * 4 );
1876 
1877  if( ( blockPos.x >= ( (unsigned int)m_windowSize.x - ( 4 * RAYPACKET_DIM + 4 ) ) ) &&
1878  ( blockPos.y >= ( (unsigned int)m_windowSize.y - ( 4 * RAYPACKET_DIM + 4 ) ) ) )
1879  break;
1880 
1881  if( ( blockPos.x < ( (unsigned int)m_windowSize.x - ( 4 * RAYPACKET_DIM + 4 ) ) ) &&
1882  ( blockPos.y < ( (unsigned int)m_windowSize.y - ( 4 * RAYPACKET_DIM + 4 ) ) ) )
1883  {
1884  m_blockPositionsFast.push_back( blockPos );
1885 
1886  if( blockPos.x > m_realBufferSize.x )
1887  m_realBufferSize.x = blockPos.x;
1888 
1889  if( blockPos.y > m_realBufferSize.y )
1890  m_realBufferSize.y = blockPos.y;
1891  }
1892  }
1893 
1895 
1898 
1899  m_xoffset = ( m_windowSize.x - m_realBufferSize.x ) / 2;
1900  m_yoffset = ( m_windowSize.y - m_realBufferSize.y ) / 2;
1901 
1903 
1904  // Calc block positions for regular rendering. Choose an 'inside out' style of rendering.
1905  m_blockPositions.clear();
1906  const int blocks_x = m_realBufferSize.x / RAYPACKET_DIM;
1907  const int blocks_y = m_realBufferSize.y / RAYPACKET_DIM;
1908  m_blockPositions.reserve( blocks_x * blocks_y );
1909 
1910  for( int x = 0; x < blocks_x; ++x )
1911  {
1912  for( int y = 0; y < blocks_y; ++y )
1913  m_blockPositions.emplace_back( x * RAYPACKET_DIM, y * RAYPACKET_DIM );
1914  }
1915 
1916  const SFVEC2UI center( m_realBufferSize.x / 2, m_realBufferSize.y / 2 );
1917  std::sort( m_blockPositions.begin(), m_blockPositions.end(),
1918  [&]( const SFVEC2UI& a, const SFVEC2UI& b ) {
1919  // Sort order: inside out.
1920  return distance( a, center ) < distance( b, center );
1921  } );
1922 
1923  // Create m_shader buffer
1924  delete[] m_shaderBuffer;
1926 
1927  initPbo();
1928 }
1929 
1930 
1932 {
1933  HITINFO hitInfo;
1934  hitInfo.m_tHit = std::numeric_limits<float>::infinity();
1935 
1936  if( m_accelerator )
1937  {
1938  if( m_accelerator->Intersect( aRay, hitInfo ) )
1939  {
1940  if( hitInfo.pHitObject )
1941  return hitInfo.pHitObject->GetBoardItem();
1942  }
1943  }
1944 
1945  return nullptr;
1946 }
unsigned char c[3]
Definition: color_rgb.h:36
#define RAYPACKET_DIM
Definition: raypacket.h:32
float m_ShadowFactor
( 4) Shadow attenuation (1.0 no shadow, 0.0f darkness)
Definition: hitinfo.h:45
bool GetFlag(DISPLAY3D_FLG aFlag) const
Get a configuration status of a flag.
BOARD_ADAPTER & m_boardAdapter
std::vector< int > m_blockPositionsWasProcessed
Encode the Morton code positions (on fast preview mode).
void SetShadowsEnabled(bool aIsShadowsEnabled)
int m_RtShadowSampleCount
Defines math related functions.
A base light class to derive to implement other light classes.
Definition: light.h:40
RAY m_ray[RAYPACKET_RAYS_PER_PACKET]
Definition: raypacket.h:54
void SetShadedBuffer(SFVEC3F *aShadedBuffer)
SFVEC3F shadeHit(const SFVEC3F &aBgColor, const RAY &aRay, HITINFO &aHitInfo, bool aIsInsideObject, unsigned int aRecursiveLevel, bool is_testShadow) const
const SFVEC3F & GetEmissiveColor() const
Definition: material.h:269
virtual bool IntersectP(const RAY &aRay, float aMaxDistance) const =0
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
unsigned int m_convertedDummyBlockCount
uint32_t DecodeMorton2X(uint32_t code)
Definition: mortoncodes.cpp:98
virtual bool Intersect(const RAY &aRay, HITINFO &aHitInfo) const =0
void Init(const SFVEC3F &o, const SFVEC3F &d)
Definition: ray.cpp:35
BOARD_ITEM * GetBoardItem() const
Definition: object_3d.h:56
#define RAYPACKET_INVMASK
Definition: raypacket.h:34
int color
Definition: DXF_plotter.cpp:57
unsigned long int m_renderStartTime
Time that the render starts.
void renderRayPackets(const SFVEC3F *bgColorY, const RAY *aRayPkt, HITINFO_PACKET *aHitPacket, bool is_testShadow, SFVEC3F *aOutHitColor)
float GetNonCopperLayerThickness() const noexcept
Get the current non copper layers thickness.
Implement a canvas based on a wxGLCanvas.
Definition: eda_3d_canvas.h:48
static void HITINFO_PACKET_init(HITINFO_PACKET *aHitPacket)
SFVEC3F ApplyShadeColor(const SFVEC2I &aShaderPos, const SFVEC3F &aInputColor, const SFVEC3F &aShadeColor) const override
Apply the final color process using a previous stage color.
RT_RENDER_STATE m_renderState
State used on quality render.
Definition: ray.h:62
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:70
glm::ivec2 SFVEC2I
Definition: xv3d_types.h:39
float GetModelTransparency() const
Definition: object_3d.h:65
std::list< LIGHT * > m_lights
const SFVEC3F & GetSpecularColor() const
Definition: material.h:270
float m_RtSpreadRefractions
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
void RAYPACKET_InitRays_with2DDisplacement(const CAMERA &aCamera, const SFVEC2F &aWindowsPosition, const SFVEC2F &a2DWindowsPosDisplacementFactor, RAY *aRayPck)
Definition: raypacket.cpp:162
float m_tHit
( 4) distance
Definition: hitinfo.h:38
void renderPreview(GLubyte *ptrPBO)
std::vector< SFVEC2UI > m_blockPositions
Flag if a position was already processed (cleared each new render).
virtual SFVEC3F Shade(const RAY &aRay, const HITINFO &aHitInfo, float NdotL, const SFVEC3F &aDiffuseObjColor, const SFVEC3F &aDirToLight, const SFVEC3F &aLightColor, float aShadowAttenuationFactor) const =0
Shade an intersection point.
SFVEC3F at(float t) const
Definition: ray.h:84
uint32_t DecodeMorton2Y(uint32_t code)
void renderBlockTracing(GLubyte *ptrPBO, signed int iBlock)
void SetPixelData(unsigned int x, unsigned int y, const SFVEC3F &aNormal, const SFVEC3F &aColor, const SFVEC3F &aHitPosition, float aDepth, float aShadowAttFactor)
Definition: post_shader.cpp:79
bool Refract(const SFVEC3F &aInVector, const SFVEC3F &aNormal, float aRin_over_Rout, SFVEC3F &aOutVector)
Based on: https://github.com/mmp/pbrt-v3/blob/master/src/core/reflection.h See also: http://www....
Definition: 3d_math.h:112
size_t m_blockRenderProgressCount
Save the number of blocks progress of the render.
Base material class that can be used to derive other material implementations.
Definition: material.h:239
std::vector< SFVEC2UI > m_blockPositionsFast
COLOR_RGB BlendColor(const COLOR_RGB &aC1, const COLOR_RGB &aC2)
Definition: color_rgb.cpp:41
RENDER_ENGINE GetRenderEngine() const noexcept
SFVEC3F m_HitPoint
(12) hit position
Definition: hitinfo.h:44
A class used to derive camera objects from.
Definition: camera.h:77
glm::uvec2 SFVEC2UI
Definition: xv3d_types.h:38
float GetReflection() const
Definition: material.h:274
#define SRGB_GAMA
void renderTracing(GLubyte *ptrPBO, REPORTER *aStatusReporter)
unsigned int m_converted2dRoundSegmentCount
const SFVEC3F & GetColorAtNotProtected(const SFVEC2I &aPos) const
float m_RtSpreadReflections
SFVEC3F Shade(const SFVEC2I &aShaderPos) const override
SFVEC4F m_BgColorTop
background top color
glm::vec2 SFVEC2F
Definition: xv3d_types.h:42
unsigned int GetRefractionRayCount() const
Definition: material.h:276
Implements Morton Codes https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/ http://www....
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
bool Redraw(bool aIsMoving, REPORTER *aStatusReporter, REPORTER *aWarningReporter) override
Redraw the view.
void Reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter, bool aOnlyLoadCopperAndShapes)
void InitFrame()
Definition: post_shader.h:56
#define _(s)
void renderFinalColor(GLubyte *ptrPBO, const SFVEC3F &rgbColor, bool applyColorSpaceConversion)
SFVEC4F m_BgColorBot
background bottom color
HITINFO m_HitInfo
Definition: hitinfo.h:58
RENDER_3D_RAYTRACE(EDA_3D_CANVAS *aCanvas, BOARD_ADAPTER &aAdapter, CAMERA &aCamera)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
This is a base class to hold data and functions for render targets.
const OBJECT_3D * pHitObject
( 4) Object that was hitted
Definition: hitinfo.h:40
SFVEC3F m_Dir
Definition: ray.h:67
POST_SHADER_SSAO m_postShaderSsao
bool m_is_opengl_initialized
static SFVEC3F convertLinearToSRGB(const SFVEC3F &aRGBcolor)
BOARD_ITEM * IntersectBoardItem(const RAY &aRay)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
SFVEC3F UniformRandomHemisphereDirection()
Definition: 3d_math.h:55
void SetCurWindowSize(const wxSize &aSize) override
Before each render, the canvas will tell the render what is the size of its windows,...
std::unique_ptr< BUSY_INDICATOR > CreateBusyIndicator() const
Return a created busy indicator, if a factory has been set, else a null pointer.
bool m_reloadRequested
The window size that this camera is working.
SFVEC3F m_backgroundColorBottom
Used to see if the windows size changed.
SFVEC3F Blur(const SFVEC2I &aShaderPos) const
SFVEC3F m_Origin
Definition: ray.h:64
void renderAntiAliasPackets(const SFVEC3F *aBgColorY, const HITINFO_PACKET *aHitPck_X0Y0, const HITINFO_PACKET *aHitPck_AA_X1Y1, const RAY *aRayPck, SFVEC3F *aOutHitColor)
DIRECTIONAL_LIGHT * m_cameraLight
const SFVEC3F & GetDir() const
Definition: camera.h:106
const SFVEC3F & GetAmbientColor() const
Definition: material.h:268
static void SetPixel(GLubyte *p, const COLOR_RGB &v)
Stores the hit information of a ray with a point on the surface of a object.
Definition: hitinfo.h:35
unsigned int GetReflectionRayCount() const
Definition: material.h:277
virtual bool Intersect(const RAY &aRay, HITINFO &aHitInfo) const =0
#define RAYPACKET_RAYS_PER_PACKET
Definition: raypacket.h:35
void OglDrawBackground(const SFVEC3F &aTopColor, const SFVEC3F &aBotColor)
Definition: ogl_utils.cpp:160
unsigned GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
unsigned int m_acc_node_info
( 4) The acc stores here the node that it hits
Definition: hitinfo.h:42
glm::vec3 SFVEC3F
Definition: xv3d_types.h:44
virtual SFVEC3F GetDiffuseColor(const HITINFO &aHitInfo) const =0
void UpdateSize(const SFVEC2UI &aSize)
Definition: post_shader.cpp:73
void postProcessShading(GLubyte *ptrPBO, REPORTER *aStatusReporter)
CAMERA & m_camera
Flag if the opengl specific for this render was already initialized.
void SetDirection(const SFVEC3F &aDir)
Set directional light orientation.
Definition: light.h:131
Defines math related functions.
#define DISP_FACTOR
SFVEC3F m_HitNormal
(12) normal at the hit point
Definition: hitinfo.h:37
bool ParametersChanged()
Definition: camera.cpp:590
void postProcessBlurFinish(GLubyte *ptrPBO, REPORTER *aStatusReporter)
bool m_hitresult
Definition: hitinfo.h:57
void render(GLubyte *ptrPBO, REPORTER *aStatusReporter)
float m_RtSpreadShadows
ACCELERATOR_3D * m_accelerator
float GetAbsorvance() const
Definition: material.h:275
Helper class to handle information needed to display 3D board.
Definition: board_adapter.h:68
SFVEC3F ConvertSRGBToLinear(const SFVEC3F &aSRGBcolor)
CONTAINER_2D * m_outlineBoard2dObjects
HITINFO_PACKET * m_firstHitinfo
unsigned int GetReflectionRecursionCount() const
Definition: material.h:278
unsigned int GetRefractionRecursionCount() const
Definition: material.h:279
BVH_CONTAINER_2D * m_antioutlineBoard2dObjects
int GetWaitForEditingTimeOut() override
Give the interface the time (in ms) that it should wait for editing or movements before (this works f...
const MATERIAL * GetMaterial() const
Definition: object_3d.h:64
wxSize m_oldWindowsSize
Encode Morton code positions.