KiCad PCB EDA Suite
render_3d_raytrace.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2020 Mario Luzeiro <mrluzeiro@ua.pt>
5  * Copyright (C) 2015-2021 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 
29 #include <gal/opengl/kiglew.h> // Must be included first
30 
31 #include <algorithm>
32 #include <atomic>
33 #include <chrono>
34 #include <climits>
35 #include <thread>
36 
37 #include "render_3d_raytrace.h"
38 #include "mortoncodes.h"
39 #include "../color_rgb.h"
40 #include "3d_fastmath.h"
41 #include "3d_math.h"
42 #include "../common_ogl/ogl_utils.h"
43 #include <profile.h> // To use GetRunningMicroSecs or another profiling utility
44 
45 
47  RENDER_3D_BASE( aAdapter, aCamera ),
48  m_postShaderSsao( aCamera )
49 {
50  wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE::RENDER_3D_RAYTRACE" ) );
51 
53  m_pboId = GL_NONE;
54  m_pboDataSize = 0;
55  m_accelerator = nullptr;
58  m_oldWindowsSize.x = 0;
59  m_oldWindowsSize.y = 0;
60  m_outlineBoard2dObjects = nullptr;
62  m_firstHitinfo = nullptr;
63  m_shaderBuffer = nullptr;
64  m_cameraLight = nullptr;
65 
66  m_xoffset = 0;
67  m_yoffset = 0;
68 
69  m_isPreview = false;
70  m_renderState = RT_RENDER_STATE_MAX; // Set to an initial invalid state
73 }
74 
75 
77 {
78  wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE::~RENDER_3D_RAYTRACE" ) );
79 
80  delete m_accelerator;
81  m_accelerator = nullptr;
82 
84  m_outlineBoard2dObjects = nullptr;
85 
88 
89  delete[] m_shaderBuffer;
90  m_shaderBuffer = nullptr;
91 
92  deletePbo();
93 }
94 
95 
97 {
98  return 1000; // ms
99 }
100 
101 
103 {
104  // Delete PBO if it was created
106  {
107  if( glIsBufferARB( m_pboId ) )
108  glDeleteBuffers( 1, &m_pboId );
109 
110  m_pboId = GL_NONE;
111  }
112 }
113 
114 
115 void RENDER_3D_RAYTRACE::SetCurWindowSize( const wxSize& aSize )
116 {
117  if( m_windowSize != aSize )
118  {
119  m_windowSize = aSize;
120  glViewport( 0, 0, m_windowSize.x, m_windowSize.y );
121 
123  }
124 }
125 
126 
128 {
130 
133 
135 
137 
138  // Mark the blocks not processed yet
139  std::fill( m_blockPositionsWasProcessed.begin(), m_blockPositionsWasProcessed.end(), 0 );
140 }
141 
142 
143 static inline void SetPixel( GLubyte* p, const COLOR_RGB& v )
144 {
145  p[0] = v.c[0];
146  p[1] = v.c[1];
147  p[2] = v.c[2];
148  p[3] = 255;
149 }
150 
151 
152 bool RENDER_3D_RAYTRACE::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
153  REPORTER* aWarningReporter )
154 {
155  bool requestRedraw = false;
156 
157  // Initialize openGL if need
159  {
160  if( !initializeOpenGL() )
161  return false;
162 
163  //aIsMoving = true;
164  requestRedraw = true;
165 
166  // It will assign the first time the windows size, so it will now
167  // revert to preview mode the first time the Redraw is called
170  }
171 
172  std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
173 
174  // Reload board if it was requested
175  if( m_reloadRequested )
176  {
177  if( aStatusReporter )
178  aStatusReporter->Report( _( "Loading..." ) );
179 
180  //aIsMoving = true;
181  requestRedraw = true;
182  Reload( aStatusReporter, aWarningReporter, false );
183  }
184 
185 
186  // Recalculate constants if windows size was changed
188  {
190  aIsMoving = true;
191  requestRedraw = true;
192 
194  }
195 
196 
197  // Clear buffers
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  glDisable( GL_MULTISAMPLE );
213 
214  const bool was_camera_changed = m_camera.ParametersChanged();
215 
216  if( requestRedraw || aIsMoving || was_camera_changed )
217  m_renderState = RT_RENDER_STATE_MAX; // Set to an invalid state,
218  // so it will restart again latter
219 
220  // This will only render if need, otherwise it will redraw the PBO on the screen again
221  if( aIsMoving || was_camera_changed )
222  {
223  // Set head light (camera view light) with the opposite direction of the camera
224  if( m_cameraLight )
226 
229 
230  // Bind PBO
231  glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
232 
233  // Get the PBO pixel pointer to write the data
234  GLubyte* ptrPBO = (GLubyte *)glMapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB,
235  GL_WRITE_ONLY_ARB );
236 
237  if( ptrPBO )
238  {
239  renderPreview( ptrPBO );
240 
241  // release pointer to mapping buffer, this initialize the coping to PBO
242  glUnmapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB );
243  }
244 
245  glWindowPos2i( m_xoffset, m_yoffset );
246  }
247  else
248  {
249  // Bind PBO
250  glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
251 
253  {
254  // Get the PBO pixel pointer to write the data
255  GLubyte* ptrPBO = (GLubyte *)glMapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB,
256  GL_WRITE_ONLY_ARB );
257 
258  if( ptrPBO )
259  {
260  render( ptrPBO, aStatusReporter );
261 
263  requestRedraw = true;
264 
265  // release pointer to mapping buffer, this initialize the coping to PBO
266  glUnmapBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB );
267  }
268  }
269 
271  {
272  glClear( GL_COLOR_BUFFER_BIT );
273  }
274 
275  glWindowPos2i( m_xoffset, m_yoffset );
276  }
277 
278  // This way it will blend the progress rendering with the last buffer. eg:
279  // if it was called after a openGL.
280  glEnable( GL_BLEND );
281  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
282  glEnable( GL_ALPHA_TEST );
283  glDrawPixels( m_realBufferSize.x, m_realBufferSize.y, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
284  glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
285 
286  return requestRedraw;
287 }
288 
289 
290 void RENDER_3D_RAYTRACE::render( GLubyte* ptrPBO, REPORTER* aStatusReporter )
291 {
293  {
295 
296  if( m_cameraLight )
298 
300  {
301  // Set all pixels of PBO transparent (Alpha to 0)
302  // This way it will draw the full buffer but only shows the updated (
303  // already calculated) squares
304  unsigned int nPixels = m_realBufferSize.x * m_realBufferSize.y;
305  GLubyte* tmp_ptrPBO = ptrPBO + 3; // PBO is RGBA
306 
307  for( unsigned int i = 0; i < nPixels; ++i )
308  {
309  *tmp_ptrPBO = 0;
310  tmp_ptrPBO += 4; // PBO is RGBA
311  }
312  }
313 
316  }
317 
318  switch( m_renderState )
319  {
321  renderTracing( ptrPBO, aStatusReporter );
322  break;
323 
325  postProcessShading( ptrPBO, aStatusReporter );
326  break;
327 
329  postProcessBlurFinish( ptrPBO, aStatusReporter );
330  break;
331 
332  default:
333  wxASSERT_MSG( false, "Invalid state on m_renderState");
335  break;
336  }
337 
338  if( aStatusReporter && ( m_renderState == RT_RENDER_STATE_FINISH ) )
339  {
340  // Calculation time in seconds
341  const double elapsed_time = (double)( GetRunningMicroSecs() - m_renderStartTime ) / 1e6;
342 
343  aStatusReporter->Report( wxString::Format( _( "Rendering time %.3f s" ), elapsed_time ) );
344  }
345 }
346 
347 
348 void RENDER_3D_RAYTRACE::renderTracing( GLubyte* ptrPBO, REPORTER* aStatusReporter )
349 {
350  m_isPreview = false;
351 
352  auto startTime = std::chrono::steady_clock::now();
353  bool breakLoop = false;
354 
355  std::atomic<size_t> numBlocksRendered( 0 );
356  std::atomic<size_t> currentBlock( 0 );
357  std::atomic<size_t> threadsFinished( 0 );
358 
359  size_t parallelThreadCount = std::min<size_t>(
360  std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
361  m_blockPositions.size() );
362 
363  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
364  {
365  std::thread t = std::thread( [&]()
366  {
367  for( size_t iBlock = currentBlock.fetch_add( 1 );
368  iBlock < m_blockPositions.size() && !breakLoop;
369  iBlock = currentBlock.fetch_add( 1 ) )
370  {
371  if( !m_blockPositionsWasProcessed[iBlock] )
372  {
373  renderBlockTracing( ptrPBO, iBlock );
374  numBlocksRendered++;
375  m_blockPositionsWasProcessed[iBlock] = 1;
376 
377  // Check if it spend already some time render and request to exit
378  // to display the progress
379  if( std::chrono::duration_cast<std::chrono::milliseconds>(
380  std::chrono::steady_clock::now() - startTime ).count() > 150 )
381  breakLoop = true;
382  }
383  }
384 
385  threadsFinished++;
386  } );
387 
388  t.detach();
389  }
390 
391  while( threadsFinished < parallelThreadCount )
392  std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
393 
394  m_blockRenderProgressCount += numBlocksRendered;
395 
396  if( aStatusReporter )
397  aStatusReporter->Report( wxString::Format( _( "Rendering: %.0f %%" ),
398  (float) ( m_blockRenderProgressCount * 100 )
399  / (float) m_blockPositions.size() ) );
400 
401  // Check if it finish the rendering and if should continue to a post processing
402  // or mark it as finished
404  {
407  else
409  }
410 }
411 
412 
413 #ifdef USE_SRGB_SPACE
414 
416 #define SRGB_GAMA 2.4f
417 
418 
419 // This function implements the conversion from linear RGB to sRGB
420 // https://github.com/g-truc/glm/blob/master/glm/gtc/color_space.inl#L12
421 static SFVEC3F convertLinearToSRGB( const SFVEC3F& aRGBcolor )
422 {
423  const float gammaCorrection = 1.0f / SRGB_GAMA;
424  const SFVEC3F clampedColor = glm::clamp( aRGBcolor, SFVEC3F( 0.0f ), SFVEC3F( 1.0f ) );
425 
426  return glm::mix( glm::pow( clampedColor, SFVEC3F(gammaCorrection) ) * 1.055f - 0.055f,
427  clampedColor * 12.92f,
428  glm::lessThan( clampedColor, SFVEC3F(0.0031308f) ) );
429 }
430 
431 
432 // This function implements the conversion from sRGB to linear RGB
433 // https://github.com/g-truc/glm/blob/master/glm/gtc/color_space.inl#L35
434 SFVEC3F ConvertSRGBToLinear( const SFVEC3F& aSRGBcolor )
435 {
436  const float gammaCorrection = SRGB_GAMA;
437 
438  return glm::mix( glm::pow( ( aSRGBcolor + SFVEC3F( 0.055f ) )
439  * SFVEC3F( 0.94786729857819905213270142180095f ),
440  SFVEC3F( gammaCorrection ) ),
441  aSRGBcolor * SFVEC3F( 0.07739938080495356037151702786378f ),
442  glm::lessThanEqual( aSRGBcolor, SFVEC3F( 0.04045f ) ) );
443 }
444 
445 #endif
446 
447 
448 void RENDER_3D_RAYTRACE::renderFinalColor( GLubyte* ptrPBO, const SFVEC3F& rgbColor,
449  bool applyColorSpaceConversion )
450 {
451  SFVEC3F color = rgbColor;
452 
453 #ifdef USE_SRGB_SPACE
454  // if( applyColorSpaceConversion )
456  // rgbColor = glm::convertLinearToSRGB( rgbColor );
457 
458  if( applyColorSpaceConversion )
459  color = convertLinearToSRGB( rgbColor );
460 #endif
461 
462  ptrPBO[0] = (unsigned int) glm::clamp( (int) ( color.r * 255 ), 0, 255 );
463  ptrPBO[1] = (unsigned int) glm::clamp( (int) ( color.g * 255 ), 0, 255 );
464  ptrPBO[2] = (unsigned int) glm::clamp( (int) ( color.b * 255 ), 0, 255 );
465  ptrPBO[3] = 255;
466 }
467 
468 
469 static void HITINFO_PACKET_init( HITINFO_PACKET* aHitPacket )
470 {
471  // Initialize hitPacket with a "not hit" information
472  for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
473  {
474  aHitPacket[i].m_HitInfo.m_tHit = std::numeric_limits<float>::infinity();
475  aHitPacket[i].m_HitInfo.m_acc_node_info = 0;
476  aHitPacket[i].m_hitresult = false;
477  aHitPacket[i].m_HitInfo.m_HitNormal = SFVEC3F( 0.0f );
478  aHitPacket[i].m_HitInfo.m_ShadowFactor = 1.0f;
479  }
480 }
481 
482 
483 void RENDER_3D_RAYTRACE::renderRayPackets( const SFVEC3F* bgColorY, const RAY* aRayPkt,
484  HITINFO_PACKET* aHitPacket, bool is_testShadow,
485  SFVEC3F* aOutHitColor )
486 {
487  for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
488  {
489  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
490  {
491  if( aHitPacket[i].m_hitresult == true )
492  {
493  aOutHitColor[i] = shadeHit( bgColorY[y], aRayPkt[i], aHitPacket[i].m_HitInfo,
494  false, 0, is_testShadow );
495  }
496  else
497  {
498  aOutHitColor[i] = bgColorY[y];
499  }
500  }
501  }
502 }
503 
504 
506  const HITINFO_PACKET* aHitPck_X0Y0,
507  const HITINFO_PACKET* aHitPck_AA_X1Y1,
508  const RAY* aRayPck, SFVEC3F* aOutHitColor )
509 {
510  const bool is_testShadow = m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_SHADOWS );
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  const RAY& rayAA = aRayPck[i];
517 
518  HITINFO hitAA;
519  hitAA.m_tHit = std::numeric_limits<float>::infinity();
520  hitAA.m_acc_node_info = 0;
521 
522  bool hitted = false;
523 
524  const unsigned int idx0y1 = ( x + 0 ) + RAYPACKET_DIM * ( y + 1 );
525  const unsigned int idx1y1 = ( x + 1 ) + RAYPACKET_DIM * ( y + 1 );
526 
527  // Gets the node info from the hit.
528  const unsigned int nodex0y0 = aHitPck_X0Y0[ i ].m_HitInfo.m_acc_node_info;
529  const unsigned int node_AA_x0y0 = aHitPck_AA_X1Y1[ i ].m_HitInfo.m_acc_node_info;
530 
531  unsigned int nodex1y0 = 0;
532 
533  if( x < (RAYPACKET_DIM - 1) )
534  nodex1y0 = aHitPck_X0Y0[ i + 1 ].m_HitInfo.m_acc_node_info;
535 
536  unsigned int nodex0y1 = 0;
537 
538  if( y < ( RAYPACKET_DIM - 1 ) && idx0y1 < RAYPACKET_RAYS_PER_PACKET )
539  nodex0y1 = aHitPck_X0Y0[idx0y1].m_HitInfo.m_acc_node_info;
540 
541  unsigned int nodex1y1 = 0;
542 
543  if( ( x < ( RAYPACKET_DIM - 1 ) ) && ( y < ( RAYPACKET_DIM - 1 ) )
544  && idx1y1 < RAYPACKET_RAYS_PER_PACKET )
545  nodex1y1 = aHitPck_X0Y0[idx1y1].m_HitInfo.m_acc_node_info;
546 
547  // If all notes are equal we assume there was no change on the object hits.
548  if( ( ( nodex0y0 == nodex1y0 ) || ( nodex1y0 == 0 ) )
549  && ( ( nodex0y0 == nodex0y1 ) || ( nodex0y1 == 0 ) )
550  && ( ( nodex0y0 == nodex1y1 ) || ( nodex1y1 == 0 ) )
551  && ( nodex0y0 == node_AA_x0y0 ) )
552  {
555  // Option 1
556  // This option will give a very good quality on reflections (slow)
557  /*
558  if( m_accelerator->Intersect( rayAA, hitAA, nodex0y0 ) )
559  {
560  aOutHitColor[i] += shadeHit( aBgColorY[y], rayAA, hitAA, false, 0 );
561  }
562  else
563  {
564  if( m_accelerator->Intersect( rayAA, hitAA ) )
565  aOutHitColor[i] += shadeHit( aBgColorY[y], rayAA, hitAA, false, 0 );
566  else
567  aOutHitColor[i] += hitColor[i];
568  }
569  */
570 
571  // Option 2
572  // Trace again with the same node,
573  // then if miss just give the same color as before
574  //if( m_accelerator->Intersect( rayAA, hitAA, nodex0y0 ) )
575  // aOutHitColor[i] += shadeHit( aBgColorY[y], rayAA, hitAA, false, 0 );
576 
577  // Option 3
578  // Use same color
579  }
580  else
581  {
582  // Try to intersect the different nodes
583  // It tests the possible combination of hitted or not hitted points
584  // This will try to get the best hit for this ray
585 
586  if( nodex0y0 != 0 )
587  hitted |= m_accelerator->Intersect( rayAA, hitAA, nodex0y0 );
588 
589  if( ( nodex1y0 != 0 ) && ( nodex0y0 != nodex1y0 ) )
590  hitted |= m_accelerator->Intersect( rayAA, hitAA, nodex1y0 );
591 
592  if( ( nodex0y1 != 0 ) && ( nodex0y0 != nodex0y1 ) && ( nodex1y0 != nodex0y1 ) )
593  hitted |= m_accelerator->Intersect( rayAA, hitAA, nodex0y1 );
594 
595  if( ( nodex1y1 != 0 ) && ( nodex0y0 != nodex1y1 ) && ( nodex0y1 != nodex1y1 ) &&
596  ( nodex1y0 != nodex1y1 ) )
597  hitted |= m_accelerator->Intersect( rayAA, hitAA, nodex1y1 );
598 
599  if( (node_AA_x0y0 != 0 ) && ( nodex0y0 != node_AA_x0y0 ) &&
600  ( nodex0y1 != node_AA_x0y0 ) && ( nodex1y0 != node_AA_x0y0 ) &&
601  ( nodex1y1 != node_AA_x0y0 ) )
602  hitted |= m_accelerator->Intersect( rayAA, hitAA, node_AA_x0y0 );
603 
604  if( hitted )
605  {
606  // If we got any result, shade it
607  aOutHitColor[i] = shadeHit( aBgColorY[y], rayAA, hitAA, false, 0,
608  is_testShadow );
609  }
610  else
611  {
612  // Note: There are very few cases that will end on this situation
613  // so it is not so expensive to trace a single ray from the beginning
614 
615  // It was missed the 'last nodes' so, trace a ray from the beginning
616  if( m_accelerator->Intersect( rayAA, hitAA ) )
617  aOutHitColor[i] = shadeHit( aBgColorY[y], rayAA, hitAA, false, 0,
618  is_testShadow );
619  }
620  }
621  }
622  }
623 }
624 
625 
626 #define DISP_FACTOR 0.075f
627 
628 
629 void RENDER_3D_RAYTRACE::renderBlockTracing( GLubyte* ptrPBO, signed int iBlock )
630 {
631  // Initialize ray packets
632  const SFVEC2UI& blockPos = m_blockPositions[iBlock];
633  const SFVEC2I blockPosI = SFVEC2I( blockPos.x + m_xoffset, blockPos.y + m_yoffset );
634 
635  RAYPACKET blockPacket( m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, DISP_FACTOR ),
636  SFVEC2F( DISP_FACTOR, DISP_FACTOR ) /* Displacement random factor */ );
637 
638 
640 
641  HITINFO_PACKET_init( hitPacket_X0Y0 );
642 
643  // Calculate background gradient color
644  SFVEC3F bgColor[RAYPACKET_DIM];// Store a vertical gradient color
645 
646  for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
647  {
648  const float posYfactor = (float) ( blockPosI.y + y ) / (float) m_windowSize.y;
649 
650  bgColor[y] = m_backgroundColorTop * SFVEC3F(posYfactor) +
651  m_backgroundColorBottom * ( SFVEC3F(1.0f) - SFVEC3F(posYfactor) );
652  }
653 
654  // Intersect ray packets (calculate the intersection with rays and objects)
655  if( !m_accelerator->Intersect( blockPacket, hitPacket_X0Y0 ) )
656  {
657  // If block is empty then set shades and continue
659  {
660  for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
661  {
662  const SFVEC3F& outColor = bgColor[y];
663 
664  const unsigned int yBlockPos = blockPos.y + y;
665 
666  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x )
667  {
668  m_postShaderSsao.SetPixelData( blockPos.x + x, yBlockPos,
669  SFVEC3F( 0.0f ), outColor,
670  SFVEC3F( 0.0f ), 0, 1.0f );
671  }
672  }
673  }
674 
675  // This will set the output color to be displayed
676  // If post processing is enabled, it will not reflect the final result
677  // (as the final color will be computed on post processing)
678  // but it is used for report progress
679  const bool isFinalColor = !m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_POST_PROCESSING );
680 
681  for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
682  {
683  const SFVEC3F& outColor = bgColor[y];
684 
685  const unsigned int yConst = blockPos.x + ( ( y + blockPos.y ) * m_realBufferSize.x );
686 
687  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x )
688  {
689  GLubyte* ptr = &ptrPBO[( yConst + x ) * 4];
690 
691  renderFinalColor( ptr, outColor, isFinalColor );
692  }
693  }
694 
695  // There is nothing more here to do.. there are no hits ..
696  // just background so continue
697  return;
698  }
699 
700  SFVEC3F hitColor_X0Y0[RAYPACKET_RAYS_PER_PACKET];
701 
702  // Shade original (0, 0) hits ("paint" the intersected objects)
703  renderRayPackets( bgColor, blockPacket.m_ray, hitPacket_X0Y0,
705 
707  {
708  SFVEC3F hitColor_AA_X1Y1[RAYPACKET_RAYS_PER_PACKET];
709 
710  // Intersect one blockPosI + (0.5, 0.5) used for anti aliasing calculation
711  HITINFO_PACKET hitPacket_AA_X1Y1[RAYPACKET_RAYS_PER_PACKET];
712  HITINFO_PACKET_init( hitPacket_AA_X1Y1 );
713 
714  RAYPACKET blockPacket_AA_X1Y1( m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f, 0.5f ),
716 
717  if( !m_accelerator->Intersect( blockPacket_AA_X1Y1, hitPacket_AA_X1Y1 ) )
718  {
719  // Missed all the package
720  for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
721  {
722  const SFVEC3F& outColor = bgColor[y];
723 
724  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
725  {
726  hitColor_AA_X1Y1[i] = outColor;
727  }
728  }
729  }
730  else
731  {
732  renderRayPackets( bgColor, blockPacket_AA_X1Y1.m_ray, hitPacket_AA_X1Y1,
734  hitColor_AA_X1Y1 );
735  }
736 
737  SFVEC3F hitColor_AA_X1Y0[RAYPACKET_RAYS_PER_PACKET];
738  SFVEC3F hitColor_AA_X0Y1[RAYPACKET_RAYS_PER_PACKET];
739  SFVEC3F hitColor_AA_X0Y1_half[RAYPACKET_RAYS_PER_PACKET];
740 
741  for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
742  {
743  const SFVEC3F color_average = ( hitColor_X0Y0[i] +
744  hitColor_AA_X1Y1[i] ) * SFVEC3F( 0.5f );
745 
746  hitColor_AA_X1Y0[i] = color_average;
747  hitColor_AA_X0Y1[i] = color_average;
748  hitColor_AA_X0Y1_half[i] = color_average;
749  }
750 
751  RAY blockRayPck_AA_X1Y0[RAYPACKET_RAYS_PER_PACKET];
752  RAY blockRayPck_AA_X0Y1[RAYPACKET_RAYS_PER_PACKET];
753  RAY blockRayPck_AA_X1Y1_half[RAYPACKET_RAYS_PER_PACKET];
754 
756  m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f - DISP_FACTOR, DISP_FACTOR ),
757  SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y0 );
758 
760  m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, 0.5f - DISP_FACTOR ),
761  SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X0Y1 );
762 
764  m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.25f - DISP_FACTOR, 0.25f - DISP_FACTOR ),
765  SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y1_half );
766 
767  renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1, blockRayPck_AA_X1Y0,
768  hitColor_AA_X1Y0 );
769 
770  renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1, blockRayPck_AA_X0Y1,
771  hitColor_AA_X0Y1 );
772 
773  renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1,
774  blockRayPck_AA_X1Y1_half, hitColor_AA_X0Y1_half );
775 
776  // Average the result
777  for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
778  {
779  hitColor_X0Y0[i] = ( hitColor_X0Y0[i] + hitColor_AA_X1Y1[i] + hitColor_AA_X1Y0[i] +
780  hitColor_AA_X0Y1[i] + hitColor_AA_X0Y1_half[i] ) *
781  SFVEC3F( 1.0f / 5.0f );
782  }
783  }
784 
785  // Copy results to the next stage
786  GLubyte* ptr = &ptrPBO[( blockPos.x + ( blockPos.y * m_realBufferSize.x ) ) * 4];
787 
788  const uint32_t ptrInc = ( m_realBufferSize.x - RAYPACKET_DIM ) * 4;
789 
791  {
792  SFVEC2I bPos;
793  bPos.y = blockPos.y;
794 
795  for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
796  {
797  bPos.x = blockPos.x;
798 
799  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
800  {
801  const SFVEC3F& hColor = hitColor_X0Y0[i];
802 
803  if( hitPacket_X0Y0[i].m_hitresult == true )
804  m_postShaderSsao.SetPixelData( bPos.x, bPos.y,
805  hitPacket_X0Y0[i].m_HitInfo.m_HitNormal,
806  hColor,
807  blockPacket.m_ray[i].at(
808  hitPacket_X0Y0[i].m_HitInfo.m_tHit ),
809  hitPacket_X0Y0[i].m_HitInfo.m_tHit,
810  hitPacket_X0Y0[i].m_HitInfo.m_ShadowFactor );
811  else
812  m_postShaderSsao.SetPixelData( bPos.x, bPos.y, SFVEC3F( 0.0f ), hColor,
813  SFVEC3F( 0.0f ), 0, 1.0f );
814 
815  renderFinalColor( ptr, hColor, false );
816 
817  bPos.x++;
818  ptr += 4;
819  }
820 
821  ptr += ptrInc;
822  bPos.y++;
823  }
824  }
825  else
826  {
827  for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
828  {
829  for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
830  {
831  renderFinalColor( ptr, hitColor_X0Y0[i], true );
832  ptr += 4;
833  }
834 
835  ptr += ptrInc;
836  }
837  }
838 }
839 
840 
841 void RENDER_3D_RAYTRACE::postProcessShading( GLubyte* ptrPBO, REPORTER* aStatusReporter )
842 {
843  (void)ptrPBO; // unused
844 
846  {
847  if( aStatusReporter )
848  aStatusReporter->Report( _( "Rendering: Post processing shader" ) );
849 
852 
853  std::atomic<size_t> nextBlock( 0 );
854  std::atomic<size_t> threadsFinished( 0 );
855 
856  size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
857 
858  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
859  {
860  std::thread t = std::thread( [&]()
861  {
862  for( size_t y = nextBlock.fetch_add( 1 ); y < m_realBufferSize.y;
863  y = nextBlock.fetch_add( 1 ) )
864  {
865  SFVEC3F* ptr = &m_shaderBuffer[ y * m_realBufferSize.x ];
866 
867  for( signed int x = 0; x < (int)m_realBufferSize.x; ++x )
868  {
869  *ptr = m_postShaderSsao.Shade( SFVEC2I( x, y ) );
870  ptr++;
871  }
872  }
873 
874  threadsFinished++;
875  } );
876 
877  t.detach();
878  }
879 
880  while( threadsFinished < parallelThreadCount )
881  std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
882 
884 
885  // Set next state
887  }
888  else
889  {
890  // As this was an invalid state, set to finish
892  }
893 }
894 
895 
896 void RENDER_3D_RAYTRACE::postProcessBlurFinish( GLubyte* ptrPBO, REPORTER* aStatusReporter )
897 {
898  (void) aStatusReporter; //unused
899 
901  {
902  // Now blurs the shader result and compute the final color
903  std::atomic<size_t> nextBlock( 0 );
904  std::atomic<size_t> threadsFinished( 0 );
905 
906  size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
907 
908  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
909  {
910  std::thread t = std::thread( [&]()
911  {
912  for( size_t y = nextBlock.fetch_add( 1 ); y < m_realBufferSize.y;
913  y = nextBlock.fetch_add( 1 ) )
914  {
915  GLubyte* ptr = &ptrPBO[ y * m_realBufferSize.x * 4 ];
916 
917  for( signed int x = 0; x < (int)m_realBufferSize.x; ++x )
918  {
919  const SFVEC3F bluredShadeColor = m_postShaderSsao.Blur( SFVEC2I( x, y ) );
920 
921 #ifdef USE_SRGB_SPACE
922  const SFVEC3F originColor = convertLinearToSRGB(
924 #else
925  const SFVEC3F originColor =
927 #endif
928  const SFVEC3F shadedColor = m_postShaderSsao.ApplyShadeColor(
929  SFVEC2I( x, y ), originColor, bluredShadeColor );
930 
931  renderFinalColor( ptr, shadedColor, false );
932 
933  ptr += 4;
934  }
935  }
936 
937  threadsFinished++;
938  } );
939 
940  t.detach();
941  }
942 
943  while( threadsFinished < parallelThreadCount )
944  std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
945 
946  // Debug code
947  //m_postShaderSsao.DebugBuffersOutputAsImages();
948  }
949 
950  // End rendering
952 }
953 
954 
955 void RENDER_3D_RAYTRACE::renderPreview( GLubyte* ptrPBO )
956 {
957  m_isPreview = true;
958 
959  std::atomic<size_t> nextBlock( 0 );
960  std::atomic<size_t> threadsFinished( 0 );
961 
962  size_t parallelThreadCount = std::min<size_t>(
963  std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
964  m_blockPositions.size() );
965 
966  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
967  {
968  std::thread t = std::thread( [&]()
969  {
970  for( size_t iBlock = nextBlock.fetch_add( 1 ); iBlock < m_blockPositionsFast.size();
971  iBlock = nextBlock.fetch_add( 1 ) )
972  {
973  const SFVEC2UI& windowPosUI = m_blockPositionsFast[ iBlock ];
974  const SFVEC2I windowsPos = SFVEC2I( windowPosUI.x + m_xoffset,
975  windowPosUI.y + m_yoffset );
976 
977  RAYPACKET blockPacket( m_camera, windowsPos, 4 );
978 
980 
981  // Initialize hitPacket with a "not hit" information
982  for( HITINFO_PACKET& packet : hitPacket )
983  {
984  packet.m_HitInfo.m_tHit = std::numeric_limits<float>::infinity();
985  packet.m_HitInfo.m_acc_node_info = 0;
986  packet.m_hitresult = false;
987  }
988 
989  // Intersect packet block
990  m_accelerator->Intersect( blockPacket, hitPacket );
991 
992  // Calculate background gradient color
993  SFVEC3F bgColor[RAYPACKET_DIM];
994 
995  for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
996  {
997  const float posYfactor =
998  (float) ( windowsPos.y + y * 4.0f ) / (float) m_windowSize.y;
999 
1000  bgColor[y] = (SFVEC3F) m_boardAdapter.m_BgColorTop * SFVEC3F( posYfactor )
1002  * ( SFVEC3F( 1.0f ) - SFVEC3F( posYfactor ) );
1003  }
1004 
1005  COLOR_RGB hitColorShading[RAYPACKET_RAYS_PER_PACKET];
1006 
1007  for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
1008  {
1009  const SFVEC3F bhColorY = bgColor[i / RAYPACKET_DIM];
1010 
1011  if( hitPacket[i].m_hitresult == true )
1012  {
1013  const SFVEC3F hitColor = shadeHit( bhColorY, blockPacket.m_ray[i],
1014  hitPacket[i].m_HitInfo, false,
1015  0, false );
1016 
1017  hitColorShading[i] = COLOR_RGB( hitColor );
1018  }
1019  else
1020  hitColorShading[i] = bhColorY;
1021  }
1022 
1023  COLOR_RGB cLRB_old[(RAYPACKET_DIM - 1)];
1024 
1025  for( unsigned int y = 0; y < (RAYPACKET_DIM - 1); ++y )
1026  {
1027  const SFVEC3F bgColorY = bgColor[y];
1028  const COLOR_RGB bgColorYRGB = COLOR_RGB( bgColorY );
1029 
1030  // This stores cRTB from the last block to be reused next time in a cLTB pixel
1031  COLOR_RGB cRTB_old;
1032 
1033  //RAY cRTB_ray;
1034  //HITINFO cRTB_hitInfo;
1035 
1036  for( unsigned int x = 0; x < ( RAYPACKET_DIM - 1 ); ++x )
1037  {
1038  // pxl 0 pxl 1 pxl 2 pxl 3 pxl 4
1039  // x0 x1 ...
1040  // .---------------------------.
1041  // y0 | cLT | cxxx | cLRT | cxxx | cRT |
1042  // | cxxx | cLTC | cxxx | cRTC | cxxx |
1043  // | cLTB | cxxx | cC | cxxx | cRTB |
1044  // | cxxx | cLBC | cxxx | cRBC | cxxx |
1045  // '---------------------------'
1046  // y1 | cLB | cxxx | cLRB | cxxx | cRB |
1047 
1048  const unsigned int iLT = ( ( x + 0 ) + RAYPACKET_DIM * ( y + 0 ) );
1049  const unsigned int iRT = ( ( x + 1 ) + RAYPACKET_DIM * ( y + 0 ) );
1050  const unsigned int iLB = ( ( x + 0 ) + RAYPACKET_DIM * ( y + 1 ) );
1051  const unsigned int iRB = ( ( x + 1 ) + RAYPACKET_DIM * ( y + 1 ) );
1052 
1053  // !TODO: skip when there are no hits
1054  const COLOR_RGB& cLT = hitColorShading[ iLT ];
1055  const COLOR_RGB& cRT = hitColorShading[ iRT ];
1056  const COLOR_RGB& cLB = hitColorShading[ iLB ];
1057  const COLOR_RGB& cRB = hitColorShading[ iRB ];
1058 
1059  // Trace and shade cC
1060  COLOR_RGB cC = bgColorYRGB;
1061 
1062  const SFVEC3F& oriLT = blockPacket.m_ray[ iLT ].m_Origin;
1063  const SFVEC3F& oriRB = blockPacket.m_ray[ iRB ].m_Origin;
1064 
1065  const SFVEC3F& dirLT = blockPacket.m_ray[ iLT ].m_Dir;
1066  const SFVEC3F& dirRB = blockPacket.m_ray[ iRB ].m_Dir;
1067 
1068  SFVEC3F oriC;
1069  SFVEC3F dirC;
1070 
1071  HITINFO centerHitInfo;
1072  centerHitInfo.m_tHit = std::numeric_limits<float>::infinity();
1073 
1074  bool hittedC = false;
1075 
1076  if( ( hitPacket[iLT].m_hitresult == true )
1077  || ( hitPacket[iRT].m_hitresult == true )
1078  || ( hitPacket[iLB].m_hitresult == true )
1079  || ( hitPacket[iRB].m_hitresult == true ) )
1080  {
1081  oriC = ( oriLT + oriRB ) * 0.5f;
1082  dirC = glm::normalize( ( dirLT + dirRB ) * 0.5f );
1083 
1084  // Trace the center ray
1085  RAY centerRay;
1086  centerRay.Init( oriC, dirC );
1087 
1088  const unsigned int nodeLT = hitPacket[ iLT ].m_HitInfo.m_acc_node_info;
1089  const unsigned int nodeRT = hitPacket[ iRT ].m_HitInfo.m_acc_node_info;
1090  const unsigned int nodeLB = hitPacket[ iLB ].m_HitInfo.m_acc_node_info;
1091  const unsigned int nodeRB = hitPacket[ iRB ].m_HitInfo.m_acc_node_info;
1092 
1093  if( nodeLT != 0 )
1094  hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1095  nodeLT );
1096 
1097  if( ( nodeRT != 0 ) && ( nodeRT != nodeLT ) )
1098  hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1099  nodeRT );
1100 
1101  if( ( nodeLB != 0 ) && ( nodeLB != nodeLT ) && ( nodeLB != nodeRT ) )
1102  hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1103  nodeLB );
1104 
1105  if( ( nodeRB != 0 ) && ( nodeRB != nodeLB ) && ( nodeRB != nodeLT )
1106  && ( nodeRB != nodeRT ) )
1107  hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1108  nodeRB );
1109 
1110  if( hittedC )
1111  {
1112  cC = COLOR_RGB( shadeHit( bgColorY, centerRay, centerHitInfo,
1113  false, 0, false ) );
1114  }
1115  else
1116  {
1117  centerHitInfo.m_tHit = std::numeric_limits<float>::infinity();
1118  hittedC = m_accelerator->Intersect( centerRay, centerHitInfo );
1119 
1120  if( hittedC )
1121  cC = COLOR_RGB( shadeHit( bgColorY, centerRay, centerHitInfo,
1122  false, 0, false ) );
1123  }
1124  }
1125 
1126  // Trace and shade cLRT
1127  COLOR_RGB cLRT = bgColorYRGB;
1128 
1129  const SFVEC3F& oriRT = blockPacket.m_ray[ iRT ].m_Origin;
1130  const SFVEC3F& dirRT = blockPacket.m_ray[ iRT ].m_Dir;
1131 
1132  if( y == 0 )
1133  {
1134  // Trace the center ray
1135  RAY rayLRT;
1136  rayLRT.Init( ( oriLT + oriRT ) * 0.5f,
1137  glm::normalize( ( dirLT + dirRT ) * 0.5f ) );
1138 
1139  HITINFO hitInfoLRT;
1140  hitInfoLRT.m_tHit = std::numeric_limits<float>::infinity();
1141 
1142  if( hitPacket[iLT].m_hitresult && hitPacket[iRT].m_hitresult
1143  && ( hitPacket[iLT].m_HitInfo.pHitObject
1144  == hitPacket[iRT].m_HitInfo.pHitObject ) )
1145  {
1146  hitInfoLRT.pHitObject = hitPacket[ iLT ].m_HitInfo.pHitObject;
1147  hitInfoLRT.m_tHit = ( hitPacket[ iLT ].m_HitInfo.m_tHit +
1148  hitPacket[ iRT ].m_HitInfo.m_tHit ) * 0.5f;
1149  hitInfoLRT.m_HitNormal =
1150  glm::normalize( ( hitPacket[ iLT ].m_HitInfo.m_HitNormal +
1151  hitPacket[ iRT ].m_HitInfo.m_HitNormal ) * 0.5f );
1152 
1153  cLRT = COLOR_RGB( shadeHit( bgColorY, rayLRT, hitInfoLRT, false,
1154  0, false ) );
1155  cLRT = BlendColor( cLRT, BlendColor( cLT, cRT ) );
1156  }
1157  else
1158  {
1159  // If any hits
1160  if( hitPacket[ iLT ].m_hitresult || hitPacket[ iRT ].m_hitresult )
1161  {
1162  const unsigned int nodeLT =
1163  hitPacket[ iLT ].m_HitInfo.m_acc_node_info;
1164  const unsigned int nodeRT =
1165  hitPacket[ iRT ].m_HitInfo.m_acc_node_info;
1166 
1167  bool hittedLRT = false;
1168 
1169  if( nodeLT != 0 )
1170  hittedLRT |= m_accelerator->Intersect( rayLRT, hitInfoLRT,
1171  nodeLT );
1172 
1173  if( ( nodeRT != 0 ) && ( nodeRT != nodeLT ) )
1174  hittedLRT |= m_accelerator->Intersect( rayLRT, hitInfoLRT,
1175  nodeRT );
1176 
1177  if( hittedLRT )
1178  cLRT = COLOR_RGB( shadeHit( bgColorY, rayLRT, hitInfoLRT,
1179  false, 0, false ) );
1180  else
1181  {
1182  hitInfoLRT.m_tHit = std::numeric_limits<float>::infinity();
1183 
1184  if( m_accelerator->Intersect( rayLRT,hitInfoLRT ) )
1185  cLRT = COLOR_RGB( shadeHit( bgColorY, rayLRT,
1186  hitInfoLRT, false,
1187  0, false ) );
1188  }
1189  }
1190  }
1191  }
1192  else
1193  {
1194  cLRT = cLRB_old[x];
1195  }
1196 
1197  // Trace and shade cLTB
1198  COLOR_RGB cLTB = bgColorYRGB;
1199 
1200  if( x == 0 )
1201  {
1202  const SFVEC3F &oriLB = blockPacket.m_ray[ iLB ].m_Origin;
1203  const SFVEC3F& dirLB = blockPacket.m_ray[ iLB ].m_Dir;
1204 
1205  // Trace the center ray
1206  RAY rayLTB;
1207  rayLTB.Init( ( oriLT + oriLB ) * 0.5f,
1208  glm::normalize( ( dirLT + dirLB ) * 0.5f ) );
1209 
1210  HITINFO hitInfoLTB;
1211  hitInfoLTB.m_tHit = std::numeric_limits<float>::infinity();
1212 
1213  if( hitPacket[ iLT ].m_hitresult && hitPacket[ iLB ].m_hitresult
1214  && ( hitPacket[ iLT ].m_HitInfo.pHitObject ==
1215  hitPacket[ iLB ].m_HitInfo.pHitObject ) )
1216  {
1217  hitInfoLTB.pHitObject = hitPacket[ iLT ].m_HitInfo.pHitObject;
1218  hitInfoLTB.m_tHit = ( hitPacket[ iLT ].m_HitInfo.m_tHit +
1219  hitPacket[ iLB ].m_HitInfo.m_tHit ) * 0.5f;
1220  hitInfoLTB.m_HitNormal =
1221  glm::normalize( ( hitPacket[ iLT ].m_HitInfo.m_HitNormal +
1222  hitPacket[ iLB ].m_HitInfo.m_HitNormal ) * 0.5f );
1223  cLTB = COLOR_RGB( shadeHit( bgColorY, rayLTB, hitInfoLTB, false,
1224  0, false ) );
1225  cLTB = BlendColor( cLTB, BlendColor( cLT, cLB) );
1226  }
1227  else
1228  {
1229  // If any hits
1230  if( hitPacket[ iLT ].m_hitresult || hitPacket[ iLB ].m_hitresult )
1231  {
1232  const unsigned int nodeLT =
1233  hitPacket[ iLT ].m_HitInfo.m_acc_node_info;
1234  const unsigned int nodeLB =
1235  hitPacket[ iLB ].m_HitInfo.m_acc_node_info;
1236 
1237  bool hittedLTB = false;
1238 
1239  if( nodeLT != 0 )
1240  hittedLTB |= m_accelerator->Intersect( rayLTB, hitInfoLTB,
1241  nodeLT );
1242 
1243  if( ( nodeLB != 0 ) && ( nodeLB != nodeLT ) )
1244  hittedLTB |= m_accelerator->Intersect( rayLTB, hitInfoLTB,
1245  nodeLB );
1246 
1247  if( hittedLTB )
1248  cLTB = COLOR_RGB( shadeHit( bgColorY, rayLTB, hitInfoLTB,
1249  false, 0, false ) );
1250  else
1251  {
1252  hitInfoLTB.m_tHit = std::numeric_limits<float>::infinity();
1253 
1254  if( m_accelerator->Intersect( rayLTB, hitInfoLTB ) )
1255  cLTB = COLOR_RGB( shadeHit( bgColorY, rayLTB,
1256  hitInfoLTB, false,
1257  0, false ) );
1258  }
1259  }
1260  }
1261  }
1262  else
1263  {
1264  cLTB = cRTB_old;
1265  }
1266 
1267  // Trace and shade cRTB
1268  COLOR_RGB cRTB = bgColorYRGB;
1269 
1270  // Trace the center ray
1271  RAY rayRTB;
1272  rayRTB.Init( ( oriRT + oriRB ) * 0.5f,
1273  glm::normalize( ( dirRT + dirRB ) * 0.5f ) );
1274 
1275  HITINFO hitInfoRTB;
1276  hitInfoRTB.m_tHit = std::numeric_limits<float>::infinity();
1277 
1278  if( hitPacket[ iRT ].m_hitresult && hitPacket[ iRB ].m_hitresult
1279  && ( hitPacket[ iRT ].m_HitInfo.pHitObject ==
1280  hitPacket[ iRB ].m_HitInfo.pHitObject ) )
1281  {
1282  hitInfoRTB.pHitObject = hitPacket[ iRT ].m_HitInfo.pHitObject;
1283 
1284  hitInfoRTB.m_tHit = ( hitPacket[ iRT ].m_HitInfo.m_tHit +
1285  hitPacket[ iRB ].m_HitInfo.m_tHit ) * 0.5f;
1286 
1287  hitInfoRTB.m_HitNormal =
1288  glm::normalize( ( hitPacket[ iRT ].m_HitInfo.m_HitNormal +
1289  hitPacket[ iRB ].m_HitInfo.m_HitNormal ) * 0.5f );
1290 
1291  cRTB = COLOR_RGB( shadeHit( bgColorY, rayRTB, hitInfoRTB, false, 0,
1292  false ) );
1293  cRTB = BlendColor( cRTB, BlendColor( cRT, cRB ) );
1294  }
1295  else
1296  {
1297  // If any hits
1298  if( hitPacket[ iRT ].m_hitresult || hitPacket[ iRB ].m_hitresult )
1299  {
1300  const unsigned int nodeRT =
1301  hitPacket[ iRT ].m_HitInfo.m_acc_node_info;
1302  const unsigned int nodeRB =
1303  hitPacket[ iRB ].m_HitInfo.m_acc_node_info;
1304 
1305  bool hittedRTB = false;
1306 
1307  if( nodeRT != 0 )
1308  hittedRTB |= m_accelerator->Intersect( rayRTB, hitInfoRTB,
1309  nodeRT );
1310 
1311  if( ( nodeRB != 0 ) && ( nodeRB != nodeRT ) )
1312  hittedRTB |= m_accelerator->Intersect( rayRTB, hitInfoRTB,
1313  nodeRB );
1314 
1315  if( hittedRTB )
1316  {
1317  cRTB = COLOR_RGB( shadeHit( bgColorY, rayRTB, hitInfoRTB,
1318  false, 0, false) );
1319  }
1320  else
1321  {
1322  hitInfoRTB.m_tHit = std::numeric_limits<float>::infinity();
1323 
1324  if( m_accelerator->Intersect( rayRTB, hitInfoRTB ) )
1325  cRTB = COLOR_RGB( shadeHit( bgColorY, rayRTB, hitInfoRTB,
1326  false, 0, false ) );
1327  }
1328  }
1329  }
1330 
1331  cRTB_old = cRTB;
1332 
1333  // Trace and shade cLRB
1334  COLOR_RGB cLRB = bgColorYRGB;
1335 
1336  const SFVEC3F& oriLB = blockPacket.m_ray[ iLB ].m_Origin;
1337  const SFVEC3F& dirLB = blockPacket.m_ray[ iLB ].m_Dir;
1338 
1339  // Trace the center ray
1340  RAY rayLRB;
1341  rayLRB.Init( ( oriLB + oriRB ) * 0.5f,
1342  glm::normalize( ( dirLB + dirRB ) * 0.5f ) );
1343 
1344  HITINFO hitInfoLRB;
1345  hitInfoLRB.m_tHit = std::numeric_limits<float>::infinity();
1346 
1347  if( hitPacket[iLB].m_hitresult && hitPacket[iRB].m_hitresult
1348  && ( hitPacket[iLB].m_HitInfo.pHitObject ==
1349  hitPacket[iRB].m_HitInfo.pHitObject ) )
1350  {
1351  hitInfoLRB.pHitObject = hitPacket[ iLB ].m_HitInfo.pHitObject;
1352 
1353  hitInfoLRB.m_tHit = ( hitPacket[ iLB ].m_HitInfo.m_tHit +
1354  hitPacket[ iRB ].m_HitInfo.m_tHit ) * 0.5f;
1355 
1356  hitInfoLRB.m_HitNormal =
1357  glm::normalize( ( hitPacket[ iLB ].m_HitInfo.m_HitNormal +
1358  hitPacket[ iRB ].m_HitInfo.m_HitNormal ) * 0.5f );
1359 
1360  cLRB = COLOR_RGB( shadeHit( bgColorY, rayLRB, hitInfoLRB, false, 0,
1361  false ) );
1362  cLRB = BlendColor( cLRB, BlendColor( cLB, cRB ) );
1363  }
1364  else
1365  {
1366  // If any hits
1367  if( hitPacket[ iLB ].m_hitresult || hitPacket[ iRB ].m_hitresult )
1368  {
1369  const unsigned int nodeLB =
1370  hitPacket[ iLB ].m_HitInfo.m_acc_node_info;
1371  const unsigned int nodeRB =
1372  hitPacket[ iRB ].m_HitInfo.m_acc_node_info;
1373 
1374  bool hittedLRB = false;
1375 
1376  if( nodeLB != 0 )
1377  hittedLRB |= m_accelerator->Intersect( rayLRB, hitInfoLRB,
1378  nodeLB );
1379 
1380  if( ( nodeRB != 0 ) && ( nodeRB != nodeLB ) )
1381  hittedLRB |= m_accelerator->Intersect( rayLRB, hitInfoLRB,
1382  nodeRB );
1383 
1384  if( hittedLRB )
1385  {
1386  cLRB = COLOR_RGB( shadeHit( bgColorY, rayLRB, hitInfoLRB,
1387  false, 0, false ) );
1388  }
1389  else
1390  {
1391  hitInfoLRB.m_tHit = std::numeric_limits<float>::infinity();
1392 
1393  if( m_accelerator->Intersect( rayLRB, hitInfoLRB ) )
1394  cLRB = COLOR_RGB( shadeHit( bgColorY, rayLRB, hitInfoLRB,
1395  false, 0, false ) );
1396  }
1397  }
1398  }
1399 
1400  cLRB_old[x] = cLRB;
1401 
1402  // Trace and shade cLTC
1403  COLOR_RGB cLTC = BlendColor( cLT , cC );
1404 
1405  if( hitPacket[ iLT ].m_hitresult || hittedC )
1406  {
1407  // Trace the center ray
1408  RAY rayLTC;
1409  rayLTC.Init( ( oriLT + oriC ) * 0.5f,
1410  glm::normalize( ( dirLT + dirC ) * 0.5f ) );
1411 
1412  HITINFO hitInfoLTC;
1413  hitInfoLTC.m_tHit = std::numeric_limits<float>::infinity();
1414 
1415  bool hitted = false;
1416 
1417  if( hittedC )
1418  hitted = centerHitInfo.pHitObject->Intersect( rayLTC, hitInfoLTC );
1419  else if( hitPacket[ iLT ].m_hitresult )
1420  hitted = hitPacket[ iLT ].m_HitInfo.pHitObject->Intersect(
1421  rayLTC,
1422  hitInfoLTC );
1423 
1424  if( hitted )
1425  cLTC = COLOR_RGB( shadeHit( bgColorY, rayLTC, hitInfoLTC, false,
1426  0, false ) );
1427  }
1428 
1429  // Trace and shade cRTC
1430  COLOR_RGB cRTC = BlendColor( cRT , cC );
1431 
1432  if( hitPacket[ iRT ].m_hitresult || hittedC )
1433  {
1434  // Trace the center ray
1435  RAY rayRTC;
1436  rayRTC.Init( ( oriRT + oriC ) * 0.5f,
1437  glm::normalize( ( dirRT + dirC ) * 0.5f ) );
1438 
1439  HITINFO hitInfoRTC;
1440  hitInfoRTC.m_tHit = std::numeric_limits<float>::infinity();
1441 
1442  bool hitted = false;
1443 
1444  if( hittedC )
1445  hitted = centerHitInfo.pHitObject->Intersect( rayRTC, hitInfoRTC );
1446  else if( hitPacket[ iRT ].m_hitresult )
1447  hitted = hitPacket[ iRT ].m_HitInfo.pHitObject->Intersect( rayRTC,
1448  hitInfoRTC );
1449 
1450  if( hitted )
1451  cRTC = COLOR_RGB( shadeHit( bgColorY, rayRTC, hitInfoRTC, false,
1452  0, false ) );
1453  }
1454 
1455  // Trace and shade cLBC
1456  COLOR_RGB cLBC = BlendColor( cLB , cC );
1457 
1458  if( hitPacket[ iLB ].m_hitresult || hittedC )
1459  {
1460  // Trace the center ray
1461  RAY rayLBC;
1462  rayLBC.Init( ( oriLB + oriC ) * 0.5f,
1463  glm::normalize( ( dirLB + dirC ) * 0.5f ) );
1464 
1465  HITINFO hitInfoLBC;
1466  hitInfoLBC.m_tHit = std::numeric_limits<float>::infinity();
1467 
1468  bool hitted = false;
1469 
1470  if( hittedC )
1471  hitted = centerHitInfo.pHitObject->Intersect( rayLBC, hitInfoLBC );
1472  else if( hitPacket[ iLB ].m_hitresult )
1473  hitted = hitPacket[ iLB ].m_HitInfo.pHitObject->Intersect( rayLBC,
1474  hitInfoLBC );
1475 
1476  if( hitted )
1477  cLBC = COLOR_RGB( shadeHit( bgColorY, rayLBC, hitInfoLBC, false,
1478  0, false ) );
1479  }
1480 
1481  // Trace and shade cRBC
1482  COLOR_RGB cRBC = BlendColor( cRB , cC );
1483 
1484  if( hitPacket[ iRB ].m_hitresult || hittedC )
1485  {
1486  // Trace the center ray
1487  RAY rayRBC;
1488  rayRBC.Init( ( oriRB + oriC ) * 0.5f,
1489  glm::normalize( ( dirRB + dirC ) * 0.5f ) );
1490 
1491  HITINFO hitInfoRBC;
1492  hitInfoRBC.m_tHit = std::numeric_limits<float>::infinity();
1493 
1494  bool hitted = false;
1495 
1496  if( hittedC )
1497  hitted = centerHitInfo.pHitObject->Intersect( rayRBC, hitInfoRBC );
1498  else if( hitPacket[ iRB ].m_hitresult )
1499  hitted = hitPacket[ iRB ].m_HitInfo.pHitObject->Intersect( rayRBC,
1500  hitInfoRBC );
1501 
1502  if( hitted )
1503  cRBC = COLOR_RGB( shadeHit( bgColorY, rayRBC, hitInfoRBC, false,
1504  0, false ) );
1505  }
1506 
1507  // Set pixel colors
1508  GLubyte* ptr =
1509  &ptrPBO[( 4 * x + m_blockPositionsFast[iBlock].x
1510  + m_realBufferSize.x
1511  * ( m_blockPositionsFast[iBlock].y + 4 * y ) ) * 4];
1512  SetPixel( ptr + 0, cLT );
1513  SetPixel( ptr + 4, BlendColor( cLT, cLRT, cLTC ) );
1514  SetPixel( ptr + 8, cLRT );
1515  SetPixel( ptr + 12, BlendColor( cLRT, cRT, cRTC ) );
1516 
1517  ptr += m_realBufferSize.x * 4;
1518  SetPixel( ptr + 0, BlendColor( cLT , cLTB, cLTC ) );
1519  SetPixel( ptr + 4, BlendColor( cLTC, BlendColor( cLT , cC ) ) );
1520  SetPixel( ptr + 8, BlendColor( cC, BlendColor( cLRT, cLTC, cRTC ) ) );
1521  SetPixel( ptr + 12, BlendColor( cRTC, BlendColor( cRT , cC ) ) );
1522 
1523  ptr += m_realBufferSize.x * 4;
1524  SetPixel( ptr + 0, cLTB );
1525  SetPixel( ptr + 4, BlendColor( cC, BlendColor( cLTB, cLTC, cLBC ) ) );
1526  SetPixel( ptr + 8, cC );
1527  SetPixel( ptr + 12, BlendColor( cC, BlendColor( cRTB, cRTC, cRBC ) ) );
1528 
1529  ptr += m_realBufferSize.x * 4;
1530  SetPixel( ptr + 0, BlendColor( cLB , cLTB, cLBC ) );
1531  SetPixel( ptr + 4, BlendColor( cLBC, BlendColor( cLB , cC ) ) );
1532  SetPixel( ptr + 8, BlendColor( cC, BlendColor( cLRB, cLBC, cRBC ) ) );
1533  SetPixel( ptr + 12, BlendColor( cRBC, BlendColor( cRB , cC ) ) );
1534  }
1535  }
1536  }
1537 
1538  threadsFinished++;
1539  } );
1540 
1541  t.detach();
1542  }
1543 
1544  while( threadsFinished < parallelThreadCount )
1545  std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1546 }
1547 
1548 
1549 #define USE_EXPERIMENTAL_SOFT_SHADOWS 1
1550 
1551 SFVEC3F RENDER_3D_RAYTRACE::shadeHit( const SFVEC3F& aBgColor, const RAY& aRay, HITINFO& aHitInfo,
1552  bool aIsInsideObject, unsigned int aRecursiveLevel,
1553  bool is_testShadow ) const
1554 {
1555  const MATERIAL* objMaterial = aHitInfo.pHitObject->GetMaterial();
1556  wxASSERT( objMaterial != nullptr );
1557 
1558  SFVEC3F outColor = objMaterial->GetEmissiveColor() + objMaterial->GetAmbientColor();
1559 
1560  if( aRecursiveLevel > 7 )
1561  return outColor;
1562 
1563  SFVEC3F hitPoint = aHitInfo.m_HitPoint;
1564 
1565  hitPoint += aHitInfo.m_HitNormal * m_boardAdapter.GetNonCopperLayerThickness() * 0.6f;
1566 
1567  const SFVEC3F diffuseColorObj = aHitInfo.pHitObject->GetDiffuseColor( aHitInfo );
1568 
1569  const LIST_LIGHT& lightList = m_lights.GetList();
1570 
1571 #if USE_EXPERIMENTAL_SOFT_SHADOWS
1572  const bool is_aa_enabled = m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_ANTI_ALIASING ) &&
1573  (!m_isPreview);
1574 #endif
1575 
1576  float shadow_att_factor_sum = 0.0f;
1577 
1578  unsigned int nr_lights_that_can_cast_shadows = 0;
1579 
1580  for( LIST_LIGHT::const_iterator ii = lightList.begin(); ii != lightList.end(); ++ii )
1581  {
1582  const LIGHT* light = (LIGHT *)*ii;
1583 
1584  SFVEC3F vectorToLight;
1585  SFVEC3F colorOfLight;
1586  float distToLight;
1587 
1588  light->GetLightParameters( hitPoint, vectorToLight, colorOfLight, distToLight );
1589 
1590  if( m_isPreview )
1591  colorOfLight = SFVEC3F( 1.0f );
1592 
1593  const float NdotL = glm::dot( aHitInfo.m_HitNormal, vectorToLight );
1594 
1595  // Only calc shade if the normal is facing the direction of light,
1596  // otherwise it is in the shadow
1597  if( NdotL >= FLT_EPSILON )
1598  {
1599  float shadow_att_factor_light = 1.0f;
1600 
1601  if( is_testShadow && light->GetCastShadows() )
1602  {
1603  nr_lights_that_can_cast_shadows++;
1604 #if USE_EXPERIMENTAL_SOFT_SHADOWS
1605  // For rays that are recursive, just calculate one hit shadow
1606  if( aRecursiveLevel > 0 )
1607  {
1608 #endif
1609  RAY rayToLight;
1610  rayToLight.Init( hitPoint, vectorToLight );
1611 
1612  // Test if point is not in the shadow.
1613  // Test for any hit from the point in the direction of light
1614  if( m_accelerator->IntersectP( rayToLight, distToLight ) )
1615  shadow_att_factor_light = 0.0f;
1616 
1617 #if USE_EXPERIMENTAL_SOFT_SHADOWS
1618  }
1619  else // Experimental softshadow calculation
1620  {
1621 
1622  const unsigned int shadow_number_of_samples =
1624  const float shadow_inc_factor = 1.0f / (float) ( shadow_number_of_samples );
1625 
1626  for( unsigned int i = 0; i < shadow_number_of_samples; ++i )
1627  {
1628  RAY rayToLight;
1629 
1630  if( i == 0 )
1631  {
1632  rayToLight.Init( hitPoint, vectorToLight );
1633  }
1634  else
1635  {
1636  const SFVEC3F unifVector = UniformRandomHemisphereDirection();
1637  const SFVEC3F disturbed_vector_to_light =
1638  glm::normalize( vectorToLight + unifVector *
1640 
1641  rayToLight.Init( hitPoint, disturbed_vector_to_light );
1642  }
1643 
1644  // !TODO: there are multiple ways that this tests can be
1645  // optimized. Eg: by packing rays or to test against the
1646  // latest hit object.
1647  if( m_accelerator->IntersectP( rayToLight, distToLight ) )
1648  {
1649  shadow_att_factor_light -= shadow_inc_factor;
1650  }
1651  }
1652  }
1653 #endif
1654  shadow_att_factor_sum += shadow_att_factor_light;
1655  }
1656 
1657  outColor += objMaterial->Shade( aRay, aHitInfo, NdotL, diffuseColorObj, vectorToLight,
1658  colorOfLight, shadow_att_factor_light );
1659  }
1660 
1661  // Only use the headlight for preview
1662  if( m_isPreview )
1663  break;
1664  }
1665 
1666  // Improvement: this is not taking in account the lightcolor
1667  if( nr_lights_that_can_cast_shadows > 0 )
1668  {
1669  aHitInfo.m_ShadowFactor = glm::max(
1670  shadow_att_factor_sum / (float) ( nr_lights_that_can_cast_shadows * 1.0f ), 0.0f );
1671  }
1672  else
1673  {
1674  aHitInfo.m_ShadowFactor = 1.0f;
1675  }
1676 
1677  // Clamp color to not be brighter than 1.0f
1678  outColor = glm::min( outColor, SFVEC3F( 1.0f ) );
1679 
1680  if( !m_isPreview )
1681  {
1682  // Reflections
1683  if( ( objMaterial->GetReflection() > 0.0f )
1685  && ( aRecursiveLevel < objMaterial->GetReflectionRecursionCount() ) )
1686  {
1687  const unsigned int reflection_number_of_samples =
1688  objMaterial->GetReflectionRayCount();
1689 
1690  SFVEC3F sum_color = SFVEC3F( 0.0f );
1691 
1692  const SFVEC3F reflectVector = aRay.m_Dir - 2.0f *
1693  glm::dot( aRay.m_Dir, aHitInfo.m_HitNormal ) * aHitInfo.m_HitNormal;
1694 
1695  for( unsigned int i = 0; i < reflection_number_of_samples; ++i )
1696  {
1697  RAY reflectedRay;
1698 
1699  if( i == 0 )
1700  {
1701  reflectedRay.Init( hitPoint, reflectVector );
1702  }
1703  else
1704  {
1705  // Apply some randomize to the reflected vector
1706  const SFVEC3F random_reflectVector =
1707  glm::normalize( reflectVector +
1710 
1711  reflectedRay.Init( hitPoint, random_reflectVector );
1712  }
1713 
1714  HITINFO reflectedHit;
1715  reflectedHit.m_tHit = std::numeric_limits<float>::infinity();
1716 
1717  if( m_accelerator->Intersect( reflectedRay, reflectedHit ) )
1718  {
1719  sum_color += ( diffuseColorObj + objMaterial->GetSpecularColor() ) *
1720  shadeHit( aBgColor, reflectedRay, reflectedHit, false,
1721  aRecursiveLevel + 1, is_testShadow ) *
1722  SFVEC3F( objMaterial->GetReflection() *
1723  // Falloff factor
1724  (1.0f / ( 1.0f + 0.75f * reflectedHit.m_tHit *
1725  reflectedHit.m_tHit) ) );
1726  }
1727  }
1728 
1729  outColor += (sum_color / SFVEC3F( (float)reflection_number_of_samples) );
1730  }
1731 
1732  // Refraction
1733  const float objTransparency = aHitInfo.pHitObject->GetModelTransparency();
1734 
1735  if( ( objTransparency > 0.0f ) && m_boardAdapter.GetFlag( FL_RENDER_RAYTRACING_REFRACTIONS )
1736  && ( aRecursiveLevel < objMaterial->GetRefractionRecursionCount() ) )
1737  {
1738  const float airIndex = 1.000293f;
1739  const float glassIndex = 1.49f;
1740  const float air_over_glass = airIndex / glassIndex;
1741  const float glass_over_air = glassIndex / airIndex;
1742 
1743  const float refractionRatio = aIsInsideObject?glass_over_air:air_over_glass;
1744 
1745  SFVEC3F refractedVector;
1746 
1747  if( Refract( aRay.m_Dir, aHitInfo.m_HitNormal, refractionRatio, refractedVector ) )
1748  {
1749  // This increase the start point by a "fixed" factor so it will work the
1750  // same for all distances
1751  const SFVEC3F startPoint =
1752  aRay.at( aHitInfo.m_tHit + m_boardAdapter.GetNonCopperLayerThickness() *
1753  0.25f );
1754 
1755  const unsigned int refractions_number_of_samples =
1756  objMaterial->GetRefractionRayCount();
1757 
1758  SFVEC3F sum_color = SFVEC3F(0.0f);
1759 
1760  for( unsigned int i = 0; i < refractions_number_of_samples; ++i )
1761  {
1762  RAY refractedRay;
1763 
1764  if( i == 0 )
1765  {
1766  refractedRay.Init( startPoint, refractedVector );
1767  }
1768  else
1769  {
1770  // apply some randomize to the refracted vector
1771  const SFVEC3F randomizeRefractedVector =
1772  glm::normalize( refractedVector +
1775 
1776  refractedRay.Init( startPoint, randomizeRefractedVector );
1777  }
1778 
1779  HITINFO refractedHit;
1780  refractedHit.m_tHit = std::numeric_limits<float>::infinity();
1781 
1782  SFVEC3F refractedColor = aBgColor;
1783 
1784  if( m_accelerator->Intersect( refractedRay, refractedHit ) )
1785  {
1786  refractedColor = shadeHit( aBgColor, refractedRay, refractedHit,
1787  !aIsInsideObject, aRecursiveLevel + 1, false );
1788 
1789  const SFVEC3F absorbance = ( SFVEC3F(1.0f) - diffuseColorObj ) *
1790  (1.0f - objTransparency ) *
1791  objMaterial->GetAbsorvance() *
1792  refractedHit.m_tHit;
1793 
1794  const SFVEC3F transparency = 1.0f / ( absorbance + 1.0f );
1795 
1796  sum_color += refractedColor * transparency;
1797  }
1798  else
1799  {
1800  sum_color += refractedColor;
1801  }
1802  }
1803 
1804  outColor = outColor * ( 1.0f - objTransparency ) + objTransparency * sum_color
1805  / SFVEC3F( (float) refractions_number_of_samples );
1806  }
1807  else
1808  {
1809  outColor = outColor * ( 1.0f - objTransparency ) + objTransparency * aBgColor;
1810  }
1811  }
1812  }
1813 
1814  return outColor;
1815 }
1816 
1817 
1819 {
1820  initPbo();
1821 }
1822 
1823 
1825 {
1826  if( GLEW_ARB_pixel_buffer_object )
1827  {
1829 
1830  // Try to delete vbo if it was already initialized
1831  deletePbo();
1832 
1833  // Learn about Pixel buffer objects at:
1834  // http://www.songho.ca/opengl/gl_pbo.html
1835  // http://web.eecs.umich.edu/~sugih/courses/eecs487/lectures/25-PBO+Mipmapping.pdf
1836  // "create 2 pixel buffer objects, you need to delete them when program exits.
1837  // glBufferDataARB with NULL pointer reserves only memory space."
1838 
1839  // This sets the number of RGBA pixels
1841 
1842  glGenBuffersARB( 1, &m_pboId );
1843  glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
1844  glBufferDataARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboDataSize, 0, GL_STREAM_DRAW_ARB );
1845  glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
1846 
1847  wxLogTrace( m_logTrace,
1848  wxT( "RENDER_3D_RAYTRACE:: GLEW_ARB_pixel_buffer_object is supported" ) );
1849  }
1850 }
1851 
1852 
1854 {
1855  m_is_opengl_initialized = true;
1856 
1857  return true;
1858 }
1859 
1860 
1861 static float distance( const SFVEC2UI& a, const SFVEC2UI& b )
1862 {
1863  const float dx = (float) a.x - (float) b.x;
1864  const float dy = (float) a.y - (float) b.y;
1865  return hypotf( dx, dy );
1866 }
1867 
1868 
1870 {
1871  m_realBufferSize = SFVEC2UI( 0 );
1872 
1873  // Calc block positions for fast preview mode
1874  m_blockPositionsFast.clear();
1875 
1876  unsigned int i = 0;
1877 
1878  while(1)
1879  {
1880  const unsigned int mX = DecodeMorton2X(i);
1881  const unsigned int mY = DecodeMorton2Y(i);
1882 
1883  i++;
1884 
1885  const SFVEC2UI blockPos( mX * 4 * RAYPACKET_DIM - mX * 4,
1886  mY * 4 * RAYPACKET_DIM - mY * 4 );
1887 
1888  if( ( blockPos.x >= ( (unsigned int)m_windowSize.x - ( 4 * RAYPACKET_DIM + 4 ) ) ) &&
1889  ( blockPos.y >= ( (unsigned int)m_windowSize.y - ( 4 * RAYPACKET_DIM + 4 ) ) ) )
1890  break;
1891 
1892  if( ( blockPos.x < ( (unsigned int)m_windowSize.x - ( 4 * RAYPACKET_DIM + 4 ) ) ) &&
1893  ( blockPos.y < ( (unsigned int)m_windowSize.y - ( 4 * RAYPACKET_DIM + 4 ) ) ) )
1894  {
1895  m_blockPositionsFast.push_back( blockPos );
1896 
1897  if( blockPos.x > m_realBufferSize.x )
1898  m_realBufferSize.x = blockPos.x;
1899 
1900  if( blockPos.y > m_realBufferSize.y )
1901  m_realBufferSize.y = blockPos.y;
1902  }
1903  }
1904 
1906 
1909 
1910  m_xoffset = ( m_windowSize.x - m_realBufferSize.x ) / 2;
1911  m_yoffset = ( m_windowSize.y - m_realBufferSize.y ) / 2;
1912 
1914 
1915  // Calc block positions for regular rendering. Choose an 'inside out' style of rendering.
1916  m_blockPositions.clear();
1917  const int blocks_x = m_realBufferSize.x / RAYPACKET_DIM;
1918  const int blocks_y = m_realBufferSize.y / RAYPACKET_DIM;
1919  m_blockPositions.reserve( blocks_x * blocks_y );
1920 
1921  for( int x = 0; x < blocks_x; ++x )
1922  {
1923  for( int y = 0; y < blocks_y; ++y )
1924  m_blockPositions.emplace_back( x * RAYPACKET_DIM, y * RAYPACKET_DIM );
1925  }
1926 
1927  const SFVEC2UI center( m_realBufferSize.x / 2, m_realBufferSize.y / 2 );
1928  std::sort( m_blockPositions.begin(), m_blockPositions.end(),
1929  [&]( const SFVEC2UI& a, const SFVEC2UI& b ) {
1930  // Sort order: inside out.
1931  return distance( a, center ) < distance( b, center );
1932  } );
1933 
1934  // Create m_shader buffer
1935  delete[] m_shaderBuffer;
1937 
1938  initPbo();
1939 }
1940 
1941 
1943 {
1944  HITINFO hitInfo;
1945  hitInfo.m_tHit = std::numeric_limits<float>::infinity();
1946 
1947  if( m_accelerator )
1948  {
1949  if( m_accelerator->Intersect( aRay, hitInfo ) )
1950  {
1951  if( hitInfo.pHitObject )
1952  return hitInfo.pHitObject->GetBoardItem();
1953  }
1954  }
1955 
1956  return nullptr;
1957 }
unsigned char c[3]
Definition: color_rgb.h:36
#define RAYPACKET_DIM
Definition: raypacket.h:37
float m_ShadowFactor
( 4) Shadow attenuation (1.0 no shadow, 0.0f darkness)
Definition: hitinfo.h:50
bool GetFlag(DISPLAY3D_FLG aFlag) const
Get a configuration status of a flag.
BOARD_ADAPTER & m_boardAdapter
std::vector< int > m_blockPositionsWasProcessed
Encode the Morton code positions (on fast preview mode).
void SetShadowsEnabled(bool aIsShadowsEnabled)
int m_RtShadowSampleCount
Defines math related functions.
A base light class to derive to implement other light classes.
Definition: light.h:40
RAY m_ray[RAYPACKET_RAYS_PER_PACKET]
Definition: raypacket.h:59
void SetShadedBuffer(SFVEC3F *aShadedBuffer)
SFVEC3F shadeHit(const SFVEC3F &aBgColor, const RAY &aRay, HITINFO &aHitInfo, bool aIsInsideObject, unsigned int aRecursiveLevel, bool is_testShadow) const
const SFVEC3F & GetEmissiveColor() const
Definition: material.h:273
virtual bool IntersectP(const RAY &aRay, float aMaxDistance) const =0
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
unsigned int m_convertedDummyBlockCount
uint32_t DecodeMorton2X(uint32_t code)
Definition: mortoncodes.cpp:98
virtual bool Intersect(const RAY &aRay, HITINFO &aHitInfo) const =0
void Init(const SFVEC3F &o, const SFVEC3F &d)
Definition: ray.cpp:41
virtual void GetLightParameters(const SFVEC3F &aHitPoint, SFVEC3F &aOutVectorToLight, SFVEC3F &aOutLightColor, float &aOutDistance) const =0
Get parameters from this light.
BOARD_ITEM * GetBoardItem() const
Definition: object_3d.h:56
#define RAYPACKET_INVMASK
Definition: raypacket.h:39
int color
Definition: DXF_plotter.cpp:60
unsigned long int m_renderStartTime
Time that the render starts.
void renderRayPackets(const SFVEC3F *bgColorY, const RAY *aRayPkt, HITINFO_PACKET *aHitPacket, bool is_testShadow, SFVEC3F *aOutHitColor)
float GetNonCopperLayerThickness() const noexcept
Get the current non copper layers thickness.
static void HITINFO_PACKET_init(HITINFO_PACKET *aHitPacket)
SFVEC3F ApplyShadeColor(const SFVEC2I &aShaderPos, const SFVEC3F &aInputColor, const SFVEC3F &aShadeColor) const override
Apply the final color process using a previous stage color.
RT_RENDER_STATE m_renderState
State used on quality render.
Definition: ray.h:67
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:64
glm::ivec2 SFVEC2I
Definition: xv3d_types.h:39
float GetModelTransparency() const
Definition: object_3d.h:65
bool GetCastShadows() const
Definition: light.h:60
const SFVEC3F & GetSpecularColor() const
Definition: material.h:274
float m_RtSpreadRefractions
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
void RAYPACKET_InitRays_with2DDisplacement(const CAMERA &aCamera, const SFVEC2F &aWindowsPosition, const SFVEC2F &a2DWindowsPosDisplacementFactor, RAY *aRayPck)
Definition: raypacket.cpp:167
float m_tHit
( 4) distance
Definition: hitinfo.h:43
void renderPreview(GLubyte *ptrPBO)
std::vector< SFVEC2UI > m_blockPositions
Flag if a position was already processed (cleared each new render).
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 an intersection point.
SFVEC3F at(float t) const
Definition: ray.h:89
uint32_t DecodeMorton2Y(uint32_t code)
void renderBlockTracing(GLubyte *ptrPBO, signed int iBlock)
void SetPixelData(unsigned int x, unsigned int y, const SFVEC3F &aNormal, const SFVEC3F &aColor, const SFVEC3F &aHitPosition, float aDepth, float aShadowAttFactor)
Definition: post_shader.cpp:79
bool Refract(const SFVEC3F &aInVector, const SFVEC3F &aNormal, float aRin_over_Rout, SFVEC3F &aOutVector)
Based on: https://github.com/mmp/pbrt-v3/blob/master/src/core/reflection.h See also: http://www....
Definition: 3d_math.h:112
size_t m_blockRenderProgressCount
Save the number of blocks progress of the render.
Base material class that can be used to derive other material implementations.
Definition: material.h:243
std::vector< SFVEC2UI > m_blockPositionsFast
COLOR_RGB BlendColor(const COLOR_RGB &aC1, const COLOR_RGB &aC2)
Definition: color_rgb.cpp:41
RENDER_ENGINE GetRenderEngine() const noexcept
SFVEC3F m_HitPoint
(12) hit position
Definition: hitinfo.h:49
A class used to derive camera objects from.
Definition: camera.h:77
glm::uvec2 SFVEC2UI
Definition: xv3d_types.h:38
float GetReflection() const
Definition: material.h:278
#define SRGB_GAMA
void renderTracing(GLubyte *ptrPBO, REPORTER *aStatusReporter)
unsigned int m_converted2dRoundSegmentCount
const SFVEC3F & GetColorAtNotProtected(const SFVEC2I &aPos) const
float m_RtSpreadReflections
SFVEC3F Shade(const SFVEC2I &aShaderPos) const override
SFVEC4F m_BgColorTop
background top color
glm::vec2 SFVEC2F
Definition: xv3d_types.h:42
unsigned int GetRefractionRayCount() const
Definition: material.h:280
Implementes Morton Codes https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/ http://www....
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
bool Redraw(bool aIsMoving, REPORTER *aStatusReporter, REPORTER *aWarningReporter) override
Redraw the view.
const LIST_LIGHT & GetList() const
Get light list of this container.
Definition: light.h:196
void Reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter, bool aOnlyLoadCopperAndShapes)
void InitFrame()
Definition: post_shader.h:56
void renderFinalColor(GLubyte *ptrPBO, const SFVEC3F &rgbColor, bool applyColorSpaceConversion)
SFVEC4F m_BgColorBot
background bottom color
HITINFO m_HitInfo
Definition: hitinfo.h:63
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
This is a base class to hold data and functions for render targets.
const OBJECT_3D * pHitObject
( 4) Object that was hitted
Definition: hitinfo.h:45
SFVEC3F m_Dir
Definition: ray.h:72
POST_SHADER_SSAO m_postShaderSsao
bool m_is_opengl_initialized
static SFVEC3F convertLinearToSRGB(const SFVEC3F &aRGBcolor)
BOARD_ITEM * IntersectBoardItem(const RAY &aRay)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
SFVEC3F UniformRandomHemisphereDirection()
Definition: 3d_math.h:55
void SetCurWindowSize(const wxSize &aSize) override
Before each render, the canvas will tell the render what is the size of its windows,...
std::unique_ptr< BUSY_INDICATOR > CreateBusyIndicator() const
Return a created busy indicator, if a factory has been set, else a null pointer.
bool m_reloadRequested
The window size that this camera is working.
SFVEC3F m_backgroundColorBottom
Used to see if the windows size changed.
SFVEC3F Blur(const SFVEC2I &aShaderPos) const
SFVEC3F m_Origin
Definition: ray.h:69
void renderAntiAliasPackets(const SFVEC3F *aBgColorY, const HITINFO_PACKET *aHitPck_X0Y0, const HITINFO_PACKET *aHitPck_AA_X1Y1, const RAY *aRayPck, SFVEC3F *aOutHitColor)
DIRECTIONAL_LIGHT * m_cameraLight
const SFVEC3F & GetDir() const
Definition: camera.h:108
const SFVEC3F & GetAmbientColor() const
Definition: material.h:272
static void SetPixel(GLubyte *p, const COLOR_RGB &v)
Stores the hit information of a ray with a point on the surface of a object.
Definition: hitinfo.h:40
unsigned int GetReflectionRayCount() const
Definition: material.h:281
virtual bool Intersect(const RAY &aRay, HITINFO &aHitInfo) const =0
#define RAYPACKET_RAYS_PER_PACKET
Definition: raypacket.h:40
#define _(s)
Definition: 3d_actions.cpp:33
void OglDrawBackground(const SFVEC3F &aTopColor, const SFVEC3F &aBotColor)
Definition: ogl_utils.cpp:157
unsigned GetRunningMicroSecs()
An alternate way to calculate an elapset time (in microsecondes) to class PROF_COUNTER.
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:44
virtual SFVEC3F GetDiffuseColor(const HITINFO &aHitInfo) const =0
void UpdateSize(const SFVEC2UI &aSize)
Definition: post_shader.cpp:73
void postProcessShading(GLubyte *ptrPBO, REPORTER *aStatusReporter)
CAMERA & m_camera
Flag if the opengl specific for this render was already initialized.
void SetDirection(const SFVEC3F &aDir)
Set directional light orientation.
Definition: light.h:131
Defines math related functions.
#define DISP_FACTOR
SFVEC3F m_HitNormal
(12) normal at the hit point
Definition: hitinfo.h:42
bool ParametersChanged()
Definition: camera.cpp:581
std::list< LIGHT * > LIST_LIGHT
Definition: light.h:150
void postProcessBlurFinish(GLubyte *ptrPBO, REPORTER *aStatusReporter)
bool m_hitresult
Definition: hitinfo.h:62
void render(GLubyte *ptrPBO, REPORTER *aStatusReporter)
float m_RtSpreadShadows
RENDER_3D_RAYTRACE(BOARD_ADAPTER &aAdapter, CAMERA &aCamera)
ACCELERATOR_3D * m_accelerator
float GetAbsorvance() const
Definition: material.h:279
Helper class to handle information needed to display 3D board.
Definition: board_adapter.h:67
SFVEC3F ConvertSRGBToLinear(const SFVEC3F &aSRGBcolor)
CONTAINER_2D * m_outlineBoard2dObjects
HITINFO_PACKET * m_firstHitinfo
unsigned int GetReflectionRecursionCount() const
Definition: material.h:282
unsigned int GetRefractionRecursionCount() const
Definition: material.h:283
BVH_CONTAINER_2D * m_antioutlineBoard2dObjects
int GetWaitForEditingTimeOut() override
Give the interface the time (in ms) that it should wait for editing or movements before (this works f...
const MATERIAL * GetMaterial() const
Definition: object_3d.h:64
wxSize m_oldWindowsSize
Encode Morton code positions.