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