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