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