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