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