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