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