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