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