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 <[email protected]>
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
44 RENDER_3D_BASE( aCanvas, aAdapter, aCamera ),
45 m_postShaderSsao( aCamera )
46{
47 wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE::RENDER_3D_RAYTRACE" ) );
48
50 m_pboId = GL_NONE;
51 m_pboDataSize = 0;
52 m_accelerator = nullptr;
55 m_oldWindowsSize.x = 0;
56 m_oldWindowsSize.y = 0;
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
70}
71
72
74{
75 wxLogTrace( m_logTrace, wxT( "RENDER_3D_RAYTRACE::~RENDER_3D_RAYTRACE" ) );
76
77 delete m_accelerator;
78 m_accelerator = nullptr;
79
82
85
86 delete[] m_shaderBuffer;
87 m_shaderBuffer = nullptr;
88
89 deletePbo();
90}
91
92
94{
95 return 1000; // ms
96}
97
98
100{
101 // Delete PBO if it was created
103 {
104 if( glIsBufferARB( m_pboId ) )
105 glDeleteBuffers( 1, &m_pboId );
106
107 m_pboId = GL_NONE;
108 }
109}
110
111
112void 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
120 }
121}
122
123
125{
127
130
132
134
135 // Mark the blocks not processed yet
136 std::fill( m_blockPositionsWasProcessed.begin(), m_blockPositionsWasProcessed.end(), 0 );
137}
138
139
140static 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
149bool RENDER_3D_RAYTRACE::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
150 REPORTER* aWarningReporter )
151{
152 bool requestRedraw = false;
153
154 // Initialize openGL if need
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
167 }
168
169 std::unique_ptr<BUSY_INDICATOR> busy = CreateBusyIndicator();
170
171 // Reload board if it was requested
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
185 {
187 aIsMoving = true;
188 requestRedraw = true;
189
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 )
223
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
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
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
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
287void RENDER_3D_RAYTRACE::render( GLubyte* ptrPBO, REPORTER* aStatusReporter )
288{
290 {
292
293 if( m_cameraLight )
295
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
313 }
314
315 switch( m_renderState )
316 {
318 renderTracing( ptrPBO, aStatusReporter );
319 break;
320
322 postProcessShading( ptrPBO, aStatusReporter );
323 break;
324
326 postProcessBlurFinish( ptrPBO, aStatusReporter );
327 break;
328
329 default:
330 wxASSERT_MSG( false, wxT( "Invalid state on m_renderState" ) );
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
345void 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.m_Cfg->m_Render.raytrace_post_processing )
404 else
405 m_renderState = RT_RENDER_STATE_FINISH;
406 }
407}
408
409
410#ifdef USE_SRGB_SPACE
411
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
418static 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
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
445void RENDER_3D_RAYTRACE::renderFinalColor( GLubyte* ptrPBO, const SFVEC3F& rgbColor,
446 bool applyColorSpaceConversion )
447{
448 SFVEC3F color = rgbColor;
449
450#ifdef USE_SRGB_SPACE
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
466static 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
480void 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
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.m_Cfg->m_Render.raytrace_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 {
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
626void 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
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
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 (as the final
674 // color will be computed on post processing) but it is used for report progress
675 const bool isFinalColor = !m_boardAdapter.m_Cfg->m_Render.raytrace_post_processing;
676
677 for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
678 {
679 const SFVEC3F& outColor = bgColor[y];
680
681 const unsigned int yConst = blockPos.x + ( ( y + blockPos.y ) * m_realBufferSize.x );
682
683 for( unsigned int x = 0; x < RAYPACKET_DIM; ++x )
684 {
685 GLubyte* ptr = &ptrPBO[( yConst + x ) * 4];
686
687 renderFinalColor( ptr, outColor, isFinalColor );
688 }
689 }
690
691 // There is nothing more here to do.. there are no hits ..
692 // just background so continue
693 return;
694 }
695
696 SFVEC3F hitColor_X0Y0[RAYPACKET_RAYS_PER_PACKET];
697
698 // Shade original (0, 0) hits ("paint" the intersected objects)
699 renderRayPackets( bgColor, blockPacket.m_ray, hitPacket_X0Y0,
701
703 {
704 SFVEC3F hitColor_AA_X1Y1[RAYPACKET_RAYS_PER_PACKET];
705
706 // Intersect one blockPosI + (0.5, 0.5) used for anti aliasing calculation
707 HITINFO_PACKET hitPacket_AA_X1Y1[RAYPACKET_RAYS_PER_PACKET];
708 HITINFO_PACKET_init( hitPacket_AA_X1Y1 );
709
710 RAYPACKET blockPacket_AA_X1Y1( m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f, 0.5f ),
712
713 if( !m_accelerator->Intersect( blockPacket_AA_X1Y1, hitPacket_AA_X1Y1 ) )
714 {
715 // Missed all the package
716 for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
717 {
718 const SFVEC3F& outColor = bgColor[y];
719
720 for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
721 hitColor_AA_X1Y1[i] = outColor;
722 }
723 }
724 else
725 {
726 renderRayPackets( bgColor, blockPacket_AA_X1Y1.m_ray, hitPacket_AA_X1Y1,
727 m_boardAdapter.m_Cfg->m_Render.raytrace_shadows, hitColor_AA_X1Y1 );
728 }
729
730 SFVEC3F hitColor_AA_X1Y0[RAYPACKET_RAYS_PER_PACKET];
731 SFVEC3F hitColor_AA_X0Y1[RAYPACKET_RAYS_PER_PACKET];
732 SFVEC3F hitColor_AA_X0Y1_half[RAYPACKET_RAYS_PER_PACKET];
733
734 for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
735 {
736 SFVEC3F color_average = ( hitColor_X0Y0[i] + hitColor_AA_X1Y1[i] ) * SFVEC3F( 0.5f );
737
738 hitColor_AA_X1Y0[i] = color_average;
739 hitColor_AA_X0Y1[i] = color_average;
740 hitColor_AA_X0Y1_half[i] = color_average;
741 }
742
743 RAY blockRayPck_AA_X1Y0[RAYPACKET_RAYS_PER_PACKET];
744 RAY blockRayPck_AA_X0Y1[RAYPACKET_RAYS_PER_PACKET];
745 RAY blockRayPck_AA_X1Y1_half[RAYPACKET_RAYS_PER_PACKET];
746
748 m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f - DISP_FACTOR, DISP_FACTOR ),
749 SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y0 );
750
752 m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, 0.5f - DISP_FACTOR ),
753 SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X0Y1 );
754
756 m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.25f - DISP_FACTOR, 0.25f - DISP_FACTOR ),
757 SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y1_half );
758
759 renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1, blockRayPck_AA_X1Y0,
760 hitColor_AA_X1Y0 );
761
762 renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1, blockRayPck_AA_X0Y1,
763 hitColor_AA_X0Y1 );
764
765 renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1,
766 blockRayPck_AA_X1Y1_half, hitColor_AA_X0Y1_half );
767
768 // Average the result
769 for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
770 {
771 hitColor_X0Y0[i] = ( hitColor_X0Y0[i] + hitColor_AA_X1Y1[i] + hitColor_AA_X1Y0[i] +
772 hitColor_AA_X0Y1[i] + hitColor_AA_X0Y1_half[i] ) *
773 SFVEC3F( 1.0f / 5.0f );
774 }
775 }
776
777 // Copy results to the next stage
778 GLubyte* ptr = &ptrPBO[( blockPos.x + ( blockPos.y * m_realBufferSize.x ) ) * 4];
779
780 const uint32_t ptrInc = ( m_realBufferSize.x - RAYPACKET_DIM ) * 4;
781
783 {
784 SFVEC2I bPos;
785 bPos.y = blockPos.y;
786
787 for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
788 {
789 bPos.x = blockPos.x;
790
791 for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
792 {
793 const SFVEC3F& hColor = hitColor_X0Y0[i];
794
795 if( hitPacket_X0Y0[i].m_hitresult == true )
796 {
797 m_postShaderSsao.SetPixelData( bPos.x, bPos.y,
798 hitPacket_X0Y0[i].m_HitInfo.m_HitNormal,
799 hColor,
800 blockPacket.m_ray[i].at(
801 hitPacket_X0Y0[i].m_HitInfo.m_tHit ),
802 hitPacket_X0Y0[i].m_HitInfo.m_tHit,
803 hitPacket_X0Y0[i].m_HitInfo.m_ShadowFactor );
804 }
805 else
806 {
807 m_postShaderSsao.SetPixelData( bPos.x, bPos.y, SFVEC3F( 0.0f ), hColor,
808 SFVEC3F( 0.0f ), 0, 1.0f );
809 }
810
811 renderFinalColor( ptr, hColor, false );
812
813 bPos.x++;
814 ptr += 4;
815 }
816
817 ptr += ptrInc;
818 bPos.y++;
819 }
820 }
821 else
822 {
823 for( unsigned int y = 0, i = 0; y < RAYPACKET_DIM; ++y )
824 {
825 for( unsigned int x = 0; x < RAYPACKET_DIM; ++x, ++i )
826 {
827 renderFinalColor( ptr, hitColor_X0Y0[i], true );
828 ptr += 4;
829 }
830
831 ptr += ptrInc;
832 }
833 }
834}
835
836
837void RENDER_3D_RAYTRACE::postProcessShading( GLubyte* /* ptrPBO */, REPORTER* aStatusReporter )
838{
840 {
841 if( aStatusReporter )
842 aStatusReporter->Report( _( "Rendering: Post processing shader" ) );
843
845
846 std::atomic<size_t> nextBlock( 0 );
847 std::atomic<size_t> threadsFinished( 0 );
848
849 size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
850
851 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
852 {
853 std::thread t = std::thread( [&]()
854 {
855 for( size_t y = nextBlock.fetch_add( 1 ); y < m_realBufferSize.y;
856 y = nextBlock.fetch_add( 1 ) )
857 {
858 SFVEC3F* ptr = &m_shaderBuffer[ y * m_realBufferSize.x ];
859
860 for( signed int x = 0; x < (int)m_realBufferSize.x; ++x )
861 {
862 *ptr = m_postShaderSsao.Shade( SFVEC2I( x, y ) );
863 ptr++;
864 }
865 }
866
867 threadsFinished++;
868 } );
869
870 t.detach();
871 }
872
873 while( threadsFinished < parallelThreadCount )
874 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
875
877
878 // Set next state
880 }
881 else
882 {
883 // As this was an invalid state, set to finish
884 m_renderState = RT_RENDER_STATE_FINISH;
885 }
886}
887
888
889void RENDER_3D_RAYTRACE::postProcessBlurFinish( GLubyte* ptrPBO, REPORTER* /* aStatusReporter */ )
890{
892 {
893 // Now blurs the shader result and compute the final color
894 std::atomic<size_t> nextBlock( 0 );
895 std::atomic<size_t> threadsFinished( 0 );
896
897 size_t parallelThreadCount = std::max<size_t>( std::thread::hardware_concurrency(), 2 );
898
899 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
900 {
901 std::thread t = std::thread( [&]()
902 {
903 for( size_t y = nextBlock.fetch_add( 1 ); y < m_realBufferSize.y;
904 y = nextBlock.fetch_add( 1 ) )
905 {
906 GLubyte* ptr = &ptrPBO[ y * m_realBufferSize.x * 4 ];
907
908 for( signed int x = 0; x < (int)m_realBufferSize.x; ++x )
909 {
910 const SFVEC3F bluredShadeColor = m_postShaderSsao.Blur( SFVEC2I( x, y ) );
911
912#ifdef USE_SRGB_SPACE
913 const SFVEC3F originColor = convertLinearToSRGB(
914 m_postShaderSsao.GetColorAtNotProtected( SFVEC2I( x, y ) ) );
915#else
916 const SFVEC3F originColor =
917 m_postShaderSsao.GetColorAtNotProtected( SFVEC2I( x, y ) );
918#endif
919 const SFVEC3F shadedColor = m_postShaderSsao.ApplyShadeColor(
920 SFVEC2I( x, y ), originColor, bluredShadeColor );
921
922 renderFinalColor( ptr, shadedColor, false );
923
924 ptr += 4;
925 }
926 }
927
928 threadsFinished++;
929 } );
930
931 t.detach();
932 }
933
934 while( threadsFinished < parallelThreadCount )
935 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
936
937 // Debug code
938 //m_postShaderSsao.DebugBuffersOutputAsImages();
939 }
940
941 // End rendering
942 m_renderState = RT_RENDER_STATE_FINISH;
943}
944
945
947{
948 m_isPreview = true;
949
950 std::atomic<size_t> nextBlock( 0 );
951 std::atomic<size_t> threadsFinished( 0 );
952
953 size_t parallelThreadCount = std::min<size_t>(
954 std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
955 m_blockPositions.size() );
956
957 for( size_t ii = 0; ii < parallelThreadCount; ++ii )
958 {
959 std::thread t = std::thread( [&]()
960 {
961 for( size_t iBlock = nextBlock.fetch_add( 1 ); iBlock < m_blockPositionsFast.size();
962 iBlock = nextBlock.fetch_add( 1 ) )
963 {
964 const SFVEC2UI& windowPosUI = m_blockPositionsFast[ iBlock ];
965 const SFVEC2I windowsPos = SFVEC2I( windowPosUI.x + m_xoffset,
966 windowPosUI.y + m_yoffset );
967
968 RAYPACKET blockPacket( m_camera, windowsPos, 4 );
969
970 HITINFO_PACKET hitPacket[RAYPACKET_RAYS_PER_PACKET];
971
972 // Initialize hitPacket with a "not hit" information
973 for( HITINFO_PACKET& packet : hitPacket )
974 {
975 packet.m_HitInfo.m_tHit = std::numeric_limits<float>::infinity();
976 packet.m_HitInfo.m_acc_node_info = 0;
977 packet.m_hitresult = false;
978 }
979
980 // Intersect packet block
981 m_accelerator->Intersect( blockPacket, hitPacket );
982
983 // Calculate background gradient color
984 SFVEC3F bgColor[RAYPACKET_DIM];
985
986 for( unsigned int y = 0; y < RAYPACKET_DIM; ++y )
987 {
988 const float posYfactor =
989 (float) ( windowsPos.y + y * 4.0f ) / (float) m_windowSize.y;
990
991 bgColor[y] = (SFVEC3F) m_boardAdapter.m_BgColorTop * SFVEC3F( posYfactor )
992 + (SFVEC3F) m_boardAdapter.m_BgColorBot
993 * ( SFVEC3F( 1.0f ) - SFVEC3F( posYfactor ) );
994 }
995
996 COLOR_RGB hitColorShading[RAYPACKET_RAYS_PER_PACKET];
997
998 for( unsigned int i = 0; i < RAYPACKET_RAYS_PER_PACKET; ++i )
999 {
1000 const SFVEC3F bhColorY = bgColor[i / RAYPACKET_DIM];
1001
1002 if( hitPacket[i].m_hitresult == true )
1003 {
1004 const SFVEC3F hitColor = shadeHit( bhColorY, blockPacket.m_ray[i],
1005 hitPacket[i].m_HitInfo, false,
1006 0, false );
1007
1008 hitColorShading[i] = COLOR_RGB( hitColor );
1009 }
1010 else
1011 hitColorShading[i] = bhColorY;
1012 }
1013
1014 COLOR_RGB cLRB_old[(RAYPACKET_DIM - 1)];
1015
1016 for( unsigned int y = 0; y < (RAYPACKET_DIM - 1); ++y )
1017 {
1018 const SFVEC3F bgColorY = bgColor[y];
1019 const COLOR_RGB bgColorYRGB = COLOR_RGB( bgColorY );
1020
1021 // This stores cRTB from the last block to be reused next time in a cLTB pixel
1022 COLOR_RGB cRTB_old;
1023
1024 //RAY cRTB_ray;
1025 //HITINFO cRTB_hitInfo;
1026
1027 for( unsigned int x = 0; x < ( RAYPACKET_DIM - 1 ); ++x )
1028 {
1029 // pxl 0 pxl 1 pxl 2 pxl 3 pxl 4
1030 // x0 x1 ...
1031 // .---------------------------.
1032 // y0 | cLT | cxxx | cLRT | cxxx | cRT |
1033 // | cxxx | cLTC | cxxx | cRTC | cxxx |
1034 // | cLTB | cxxx | cC | cxxx | cRTB |
1035 // | cxxx | cLBC | cxxx | cRBC | cxxx |
1036 // '---------------------------'
1037 // y1 | cLB | cxxx | cLRB | cxxx | cRB |
1038
1039 const unsigned int iLT = ( ( x + 0 ) + RAYPACKET_DIM * ( y + 0 ) );
1040 const unsigned int iRT = ( ( x + 1 ) + RAYPACKET_DIM * ( y + 0 ) );
1041 const unsigned int iLB = ( ( x + 0 ) + RAYPACKET_DIM * ( y + 1 ) );
1042 const unsigned int iRB = ( ( x + 1 ) + RAYPACKET_DIM * ( y + 1 ) );
1043
1044 // !TODO: skip when there are no hits
1045 const COLOR_RGB& cLT = hitColorShading[ iLT ];
1046 const COLOR_RGB& cRT = hitColorShading[ iRT ];
1047 const COLOR_RGB& cLB = hitColorShading[ iLB ];
1048 const COLOR_RGB& cRB = hitColorShading[ iRB ];
1049
1050 // Trace and shade cC
1051 COLOR_RGB cC = bgColorYRGB;
1052
1053 const SFVEC3F& oriLT = blockPacket.m_ray[ iLT ].m_Origin;
1054 const SFVEC3F& oriRB = blockPacket.m_ray[ iRB ].m_Origin;
1055
1056 const SFVEC3F& dirLT = blockPacket.m_ray[ iLT ].m_Dir;
1057 const SFVEC3F& dirRB = blockPacket.m_ray[ iRB ].m_Dir;
1058
1059 SFVEC3F oriC;
1060 SFVEC3F dirC;
1061
1062 HITINFO centerHitInfo;
1063 centerHitInfo.m_tHit = std::numeric_limits<float>::infinity();
1064
1065 bool hittedC = false;
1066
1067 if( ( hitPacket[iLT].m_hitresult == true )
1068 || ( hitPacket[iRT].m_hitresult == true )
1069 || ( hitPacket[iLB].m_hitresult == true )
1070 || ( hitPacket[iRB].m_hitresult == true ) )
1071 {
1072 oriC = ( oriLT + oriRB ) * 0.5f;
1073 dirC = glm::normalize( ( dirLT + dirRB ) * 0.5f );
1074
1075 // Trace the center ray
1076 RAY centerRay;
1077 centerRay.Init( oriC, dirC );
1078
1079 const unsigned int nodeLT = hitPacket[ iLT ].m_HitInfo.m_acc_node_info;
1080 const unsigned int nodeRT = hitPacket[ iRT ].m_HitInfo.m_acc_node_info;
1081 const unsigned int nodeLB = hitPacket[ iLB ].m_HitInfo.m_acc_node_info;
1082 const unsigned int nodeRB = hitPacket[ iRB ].m_HitInfo.m_acc_node_info;
1083
1084 if( nodeLT != 0 )
1085 hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1086 nodeLT );
1087
1088 if( ( nodeRT != 0 ) && ( nodeRT != nodeLT ) )
1089 hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1090 nodeRT );
1091
1092 if( ( nodeLB != 0 ) && ( nodeLB != nodeLT ) && ( nodeLB != nodeRT ) )
1093 hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1094 nodeLB );
1095
1096 if( ( nodeRB != 0 ) && ( nodeRB != nodeLB ) && ( nodeRB != nodeLT )
1097 && ( nodeRB != nodeRT ) )
1098 hittedC |= m_accelerator->Intersect( centerRay, centerHitInfo,
1099 nodeRB );
1100
1101 if( hittedC )
1102 {
1103 cC = COLOR_RGB( shadeHit( bgColorY, centerRay, centerHitInfo,
1104 false, 0, false ) );
1105 }
1106 else
1107 {
1108 centerHitInfo.m_tHit = std::numeric_limits<float>::infinity();
1109 hittedC = m_accelerator->Intersect( centerRay, centerHitInfo );
1110
1111 if( hittedC )
1112 cC = COLOR_RGB( shadeHit( bgColorY, centerRay, centerHitInfo,
1113 false, 0, false ) );
1114 }
1115 }
1116
1117 // Trace and shade cLRT
1118 COLOR_RGB cLRT = bgColorYRGB;
1119
1120 const SFVEC3F& oriRT = blockPacket.m_ray[ iRT ].m_Origin;
1121 const SFVEC3F& dirRT = blockPacket.m_ray[ iRT ].m_Dir;
1122
1123 if( y == 0 )
1124 {
1125 // Trace the center ray
1126 RAY rayLRT;
1127 rayLRT.Init( ( oriLT + oriRT ) * 0.5f,
1128 glm::normalize( ( dirLT + dirRT ) * 0.5f ) );
1129
1130 HITINFO hitInfoLRT;
1131 hitInfoLRT.m_tHit = std::numeric_limits<float>::infinity();
1132
1133 if( hitPacket[iLT].m_hitresult && hitPacket[iRT].m_hitresult
1134 && ( hitPacket[iLT].m_HitInfo.pHitObject
1135 == hitPacket[iRT].m_HitInfo.pHitObject ) )
1136 {
1137 hitInfoLRT.pHitObject = hitPacket[ iLT ].m_HitInfo.pHitObject;
1138 hitInfoLRT.m_tHit = ( hitPacket[ iLT ].m_HitInfo.m_tHit +
1139 hitPacket[ iRT ].m_HitInfo.m_tHit ) * 0.5f;
1140 hitInfoLRT.m_HitNormal =
1141 glm::normalize( ( hitPacket[ iLT ].m_HitInfo.m_HitNormal +
1142 hitPacket[ iRT ].m_HitInfo.m_HitNormal ) * 0.5f );
1143
1144 cLRT = COLOR_RGB( shadeHit( bgColorY, rayLRT, hitInfoLRT, false,
1145 0, false ) );
1146 cLRT = BlendColor( cLRT, BlendColor( cLT, cRT ) );
1147 }
1148 else
1149 {
1150 // If any hits
1151 if( hitPacket[ iLT ].m_hitresult || hitPacket[ iRT ].m_hitresult )
1152 {
1153 const unsigned int nodeLT =
1154 hitPacket[ iLT ].m_HitInfo.m_acc_node_info;
1155 const unsigned int nodeRT =
1156 hitPacket[ iRT ].m_HitInfo.m_acc_node_info;
1157
1158 bool hittedLRT = false;
1159
1160 if( nodeLT != 0 )
1161 hittedLRT |= m_accelerator->Intersect( rayLRT, hitInfoLRT,
1162 nodeLT );
1163
1164 if( ( nodeRT != 0 ) && ( nodeRT != nodeLT ) )
1165 hittedLRT |= m_accelerator->Intersect( rayLRT, hitInfoLRT,
1166 nodeRT );
1167
1168 if( hittedLRT )
1169 cLRT = COLOR_RGB( shadeHit( bgColorY, rayLRT, hitInfoLRT,
1170 false, 0, false ) );
1171 else
1172 {
1173 hitInfoLRT.m_tHit = std::numeric_limits<float>::infinity();
1174
1175 if( m_accelerator->Intersect( rayLRT,hitInfoLRT ) )
1176 cLRT = COLOR_RGB( shadeHit( bgColorY, rayLRT,
1177 hitInfoLRT, false,
1178 0, false ) );
1179 }
1180 }
1181 }
1182 }
1183 else
1184 {
1185 cLRT = cLRB_old[x];
1186 }
1187
1188 // Trace and shade cLTB
1189 COLOR_RGB cLTB = bgColorYRGB;
1190
1191 if( x == 0 )
1192 {
1193 const SFVEC3F &oriLB = blockPacket.m_ray[ iLB ].m_Origin;
1194 const SFVEC3F& dirLB = blockPacket.m_ray[ iLB ].m_Dir;
1195
1196 // Trace the center ray
1197 RAY rayLTB;
1198 rayLTB.Init( ( oriLT + oriLB ) * 0.5f,
1199 glm::normalize( ( dirLT + dirLB ) * 0.5f ) );
1200
1201 HITINFO hitInfoLTB;
1202 hitInfoLTB.m_tHit = std::numeric_limits<float>::infinity();
1203
1204 if( hitPacket[ iLT ].m_hitresult && hitPacket[ iLB ].m_hitresult
1205 && ( hitPacket[ iLT ].m_HitInfo.pHitObject ==
1206 hitPacket[ iLB ].m_HitInfo.pHitObject ) )
1207 {
1208 hitInfoLTB.pHitObject = hitPacket[ iLT ].m_HitInfo.pHitObject;
1209 hitInfoLTB.m_tHit = ( hitPacket[ iLT ].m_HitInfo.m_tHit +
1210 hitPacket[ iLB ].m_HitInfo.m_tHit ) * 0.5f;
1211 hitInfoLTB.m_HitNormal =
1212 glm::normalize( ( hitPacket[ iLT ].m_HitInfo.m_HitNormal +
1213 hitPacket[ iLB ].m_HitInfo.m_HitNormal ) * 0.5f );
1214 cLTB = COLOR_RGB( shadeHit( bgColorY, rayLTB, hitInfoLTB, false,
1215 0, false ) );
1216 cLTB = BlendColor( cLTB, BlendColor( cLT, cLB) );
1217 }
1218 else
1219 {
1220 // If any hits
1221 if( hitPacket[ iLT ].m_hitresult || hitPacket[ iLB ].m_hitresult )
1222 {
1223 const unsigned int nodeLT =
1224 hitPacket[ iLT ].m_HitInfo.m_acc_node_info;
1225 const unsigned int nodeLB =
1226 hitPacket[ iLB ].m_HitInfo.m_acc_node_info;
1227
1228 bool hittedLTB = false;
1229
1230 if( nodeLT != 0 )
1231 hittedLTB |= m_accelerator->Intersect( rayLTB, hitInfoLTB,
1232 nodeLT );
1233
1234 if( ( nodeLB != 0 ) && ( nodeLB != nodeLT ) )
1235 hittedLTB |= m_accelerator->Intersect( rayLTB, hitInfoLTB,
1236 nodeLB );
1237
1238 if( hittedLTB )
1239 cLTB = COLOR_RGB( shadeHit( bgColorY, rayLTB, hitInfoLTB,
1240 false, 0, false ) );
1241 else
1242 {
1243 hitInfoLTB.m_tHit = std::numeric_limits<float>::infinity();
1244
1245 if( m_accelerator->Intersect( rayLTB, hitInfoLTB ) )
1246 cLTB = COLOR_RGB( shadeHit( bgColorY, rayLTB,
1247 hitInfoLTB, false,
1248 0, false ) );
1249 }
1250 }
1251 }
1252 }
1253 else
1254 {
1255 cLTB = cRTB_old;
1256 }
1257
1258 // Trace and shade cRTB
1259 COLOR_RGB cRTB = bgColorYRGB;
1260
1261 // Trace the center ray
1262 RAY rayRTB;
1263 rayRTB.Init( ( oriRT + oriRB ) * 0.5f,
1264 glm::normalize( ( dirRT + dirRB ) * 0.5f ) );
1265
1266 HITINFO hitInfoRTB;
1267 hitInfoRTB.m_tHit = std::numeric_limits<float>::infinity();
1268
1269 if( hitPacket[ iRT ].m_hitresult && hitPacket[ iRB ].m_hitresult
1270 && ( hitPacket[ iRT ].m_HitInfo.pHitObject ==
1271 hitPacket[ iRB ].m_HitInfo.pHitObject ) )
1272 {
1273 hitInfoRTB.pHitObject = hitPacket[ iRT ].m_HitInfo.pHitObject;
1274
1275 hitInfoRTB.m_tHit = ( hitPacket[ iRT ].m_HitInfo.m_tHit +
1276 hitPacket[ iRB ].m_HitInfo.m_tHit ) * 0.5f;
1277
1278 hitInfoRTB.m_HitNormal =
1279 glm::normalize( ( hitPacket[ iRT ].m_HitInfo.m_HitNormal +
1280 hitPacket[ iRB ].m_HitInfo.m_HitNormal ) * 0.5f );
1281
1282 cRTB = COLOR_RGB( shadeHit( bgColorY, rayRTB, hitInfoRTB, false, 0,
1283 false ) );
1284 cRTB = BlendColor( cRTB, BlendColor( cRT, cRB ) );
1285 }
1286 else
1287 {
1288 // If any hits
1289 if( hitPacket[ iRT ].m_hitresult || hitPacket[ iRB ].m_hitresult )
1290 {
1291 const unsigned int nodeRT =
1292 hitPacket[ iRT ].m_HitInfo.m_acc_node_info;
1293 const unsigned int nodeRB =
1294 hitPacket[ iRB ].m_HitInfo.m_acc_node_info;
1295
1296 bool hittedRTB = false;
1297
1298 if( nodeRT != 0 )
1299 hittedRTB |= m_accelerator->Intersect( rayRTB, hitInfoRTB,
1300 nodeRT );
1301
1302 if( ( nodeRB != 0 ) && ( nodeRB != nodeRT ) )
1303 hittedRTB |= m_accelerator->Intersect( rayRTB, hitInfoRTB,
1304 nodeRB );
1305
1306 if( hittedRTB )
1307 {
1308 cRTB = COLOR_RGB( shadeHit( bgColorY, rayRTB, hitInfoRTB,
1309 false, 0, false) );
1310 }
1311 else
1312 {
1313 hitInfoRTB.m_tHit = std::numeric_limits<float>::infinity();
1314
1315 if( m_accelerator->Intersect( rayRTB, hitInfoRTB ) )
1316 cRTB = COLOR_RGB( shadeHit( bgColorY, rayRTB, hitInfoRTB,
1317 false, 0, false ) );
1318 }
1319 }
1320 }
1321
1322 cRTB_old = cRTB;
1323
1324 // Trace and shade cLRB
1325 COLOR_RGB cLRB = bgColorYRGB;
1326
1327 const SFVEC3F& oriLB = blockPacket.m_ray[ iLB ].m_Origin;
1328 const SFVEC3F& dirLB = blockPacket.m_ray[ iLB ].m_Dir;
1329
1330 // Trace the center ray
1331 RAY rayLRB;
1332 rayLRB.Init( ( oriLB + oriRB ) * 0.5f,
1333 glm::normalize( ( dirLB + dirRB ) * 0.5f ) );
1334
1335 HITINFO hitInfoLRB;
1336 hitInfoLRB.m_tHit = std::numeric_limits<float>::infinity();
1337
1338 if( hitPacket[iLB].m_hitresult && hitPacket[iRB].m_hitresult
1339 && ( hitPacket[iLB].m_HitInfo.pHitObject ==
1340 hitPacket[iRB].m_HitInfo.pHitObject ) )
1341 {
1342 hitInfoLRB.pHitObject = hitPacket[ iLB ].m_HitInfo.pHitObject;
1343
1344 hitInfoLRB.m_tHit = ( hitPacket[ iLB ].m_HitInfo.m_tHit +
1345 hitPacket[ iRB ].m_HitInfo.m_tHit ) * 0.5f;
1346
1347 hitInfoLRB.m_HitNormal =
1348 glm::normalize( ( hitPacket[ iLB ].m_HitInfo.m_HitNormal +
1349 hitPacket[ iRB ].m_HitInfo.m_HitNormal ) * 0.5f );
1350
1351 cLRB = COLOR_RGB( shadeHit( bgColorY, rayLRB, hitInfoLRB, false, 0,
1352 false ) );
1353 cLRB = BlendColor( cLRB, BlendColor( cLB, cRB ) );
1354 }
1355 else
1356 {
1357 // If any hits
1358 if( hitPacket[ iLB ].m_hitresult || hitPacket[ iRB ].m_hitresult )
1359 {
1360 const unsigned int nodeLB =
1361 hitPacket[ iLB ].m_HitInfo.m_acc_node_info;
1362 const unsigned int nodeRB =
1363 hitPacket[ iRB ].m_HitInfo.m_acc_node_info;
1364
1365 bool hittedLRB = false;
1366
1367 if( nodeLB != 0 )
1368 hittedLRB |= m_accelerator->Intersect( rayLRB, hitInfoLRB,
1369 nodeLB );
1370
1371 if( ( nodeRB != 0 ) && ( nodeRB != nodeLB ) )
1372 hittedLRB |= m_accelerator->Intersect( rayLRB, hitInfoLRB,
1373 nodeRB );
1374
1375 if( hittedLRB )
1376 {
1377 cLRB = COLOR_RGB( shadeHit( bgColorY, rayLRB, hitInfoLRB,
1378 false, 0, false ) );
1379 }
1380 else
1381 {
1382 hitInfoLRB.m_tHit = std::numeric_limits<float>::infinity();
1383
1384 if( m_accelerator->Intersect( rayLRB, hitInfoLRB ) )
1385 cLRB = COLOR_RGB( shadeHit( bgColorY, rayLRB, hitInfoLRB,
1386 false, 0, false ) );
1387 }
1388 }
1389 }
1390
1391 cLRB_old[x] = cLRB;
1392
1393 // Trace and shade cLTC
1394 COLOR_RGB cLTC = BlendColor( cLT , cC );
1395
1396 if( hitPacket[ iLT ].m_hitresult || hittedC )
1397 {
1398 // Trace the center ray
1399 RAY rayLTC;
1400 rayLTC.Init( ( oriLT + oriC ) * 0.5f,
1401 glm::normalize( ( dirLT + dirC ) * 0.5f ) );
1402
1403 HITINFO hitInfoLTC;
1404 hitInfoLTC.m_tHit = std::numeric_limits<float>::infinity();
1405
1406 bool hitted = false;
1407
1408 if( hittedC )
1409 hitted = centerHitInfo.pHitObject->Intersect( rayLTC, hitInfoLTC );
1410 else if( hitPacket[ iLT ].m_hitresult )
1411 hitted = hitPacket[ iLT ].m_HitInfo.pHitObject->Intersect(
1412 rayLTC,
1413 hitInfoLTC );
1414
1415 if( hitted )
1416 cLTC = COLOR_RGB( shadeHit( bgColorY, rayLTC, hitInfoLTC, false,
1417 0, false ) );
1418 }
1419
1420 // Trace and shade cRTC
1421 COLOR_RGB cRTC = BlendColor( cRT , cC );
1422
1423 if( hitPacket[ iRT ].m_hitresult || hittedC )
1424 {
1425 // Trace the center ray
1426 RAY rayRTC;
1427 rayRTC.Init( ( oriRT + oriC ) * 0.5f,
1428 glm::normalize( ( dirRT + dirC ) * 0.5f ) );
1429
1430 HITINFO hitInfoRTC;
1431 hitInfoRTC.m_tHit = std::numeric_limits<float>::infinity();
1432
1433 bool hitted = false;
1434
1435 if( hittedC )
1436 hitted = centerHitInfo.pHitObject->Intersect( rayRTC, hitInfoRTC );
1437 else if( hitPacket[ iRT ].m_hitresult )
1438 hitted = hitPacket[ iRT ].m_HitInfo.pHitObject->Intersect( rayRTC,
1439 hitInfoRTC );
1440
1441 if( hitted )
1442 cRTC = COLOR_RGB( shadeHit( bgColorY, rayRTC, hitInfoRTC, false,
1443 0, false ) );
1444 }
1445
1446 // Trace and shade cLBC
1447 COLOR_RGB cLBC = BlendColor( cLB , cC );
1448
1449 if( hitPacket[ iLB ].m_hitresult || hittedC )
1450 {
1451 // Trace the center ray
1452 RAY rayLBC;
1453 rayLBC.Init( ( oriLB + oriC ) * 0.5f,
1454 glm::normalize( ( dirLB + dirC ) * 0.5f ) );
1455
1456 HITINFO hitInfoLBC;
1457 hitInfoLBC.m_tHit = std::numeric_limits<float>::infinity();
1458
1459 bool hitted = false;
1460
1461 if( hittedC )
1462 hitted = centerHitInfo.pHitObject->Intersect( rayLBC, hitInfoLBC );
1463 else if( hitPacket[ iLB ].m_hitresult )
1464 hitted = hitPacket[ iLB ].m_HitInfo.pHitObject->Intersect( rayLBC,
1465 hitInfoLBC );
1466
1467 if( hitted )
1468 cLBC = COLOR_RGB( shadeHit( bgColorY, rayLBC, hitInfoLBC, false,
1469 0, false ) );
1470 }
1471
1472 // Trace and shade cRBC
1473 COLOR_RGB cRBC = BlendColor( cRB , cC );
1474
1475 if( hitPacket[ iRB ].m_hitresult || hittedC )
1476 {
1477 // Trace the center ray
1478 RAY rayRBC;
1479 rayRBC.Init( ( oriRB + oriC ) * 0.5f,
1480 glm::normalize( ( dirRB + dirC ) * 0.5f ) );
1481
1482 HITINFO hitInfoRBC;
1483 hitInfoRBC.m_tHit = std::numeric_limits<float>::infinity();
1484
1485 bool hitted = false;
1486
1487 if( hittedC )
1488 hitted = centerHitInfo.pHitObject->Intersect( rayRBC, hitInfoRBC );
1489 else if( hitPacket[ iRB ].m_hitresult )
1490 hitted = hitPacket[ iRB ].m_HitInfo.pHitObject->Intersect( rayRBC,
1491 hitInfoRBC );
1492
1493 if( hitted )
1494 cRBC = COLOR_RGB( shadeHit( bgColorY, rayRBC, hitInfoRBC, false,
1495 0, false ) );
1496 }
1497
1498 // Set pixel colors
1499 GLubyte* ptr =
1500 &ptrPBO[( 4 * x + m_blockPositionsFast[iBlock].x
1502 * ( m_blockPositionsFast[iBlock].y + 4 * y ) ) * 4];
1503 SetPixel( ptr + 0, cLT );
1504 SetPixel( ptr + 4, BlendColor( cLT, cLRT, cLTC ) );
1505 SetPixel( ptr + 8, cLRT );
1506 SetPixel( ptr + 12, BlendColor( cLRT, cRT, cRTC ) );
1507
1508 ptr += m_realBufferSize.x * 4;
1509 SetPixel( ptr + 0, BlendColor( cLT , cLTB, cLTC ) );
1510 SetPixel( ptr + 4, BlendColor( cLTC, BlendColor( cLT , cC ) ) );
1511 SetPixel( ptr + 8, BlendColor( cC, BlendColor( cLRT, cLTC, cRTC ) ) );
1512 SetPixel( ptr + 12, BlendColor( cRTC, BlendColor( cRT , cC ) ) );
1513
1514 ptr += m_realBufferSize.x * 4;
1515 SetPixel( ptr + 0, cLTB );
1516 SetPixel( ptr + 4, BlendColor( cC, BlendColor( cLTB, cLTC, cLBC ) ) );
1517 SetPixel( ptr + 8, cC );
1518 SetPixel( ptr + 12, BlendColor( cC, BlendColor( cRTB, cRTC, cRBC ) ) );
1519
1520 ptr += m_realBufferSize.x * 4;
1521 SetPixel( ptr + 0, BlendColor( cLB , cLTB, cLBC ) );
1522 SetPixel( ptr + 4, BlendColor( cLBC, BlendColor( cLB , cC ) ) );
1523 SetPixel( ptr + 8, BlendColor( cC, BlendColor( cLRB, cLBC, cRBC ) ) );
1524 SetPixel( ptr + 12, BlendColor( cRBC, BlendColor( cRB , cC ) ) );
1525 }
1526 }
1527 }
1528
1529 threadsFinished++;
1530 } );
1531
1532 t.detach();
1533 }
1534
1535 while( threadsFinished < parallelThreadCount )
1536 std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
1537}
1538
1539
1540#define USE_EXPERIMENTAL_SOFT_SHADOWS 1
1541
1542SFVEC3F RENDER_3D_RAYTRACE::shadeHit( const SFVEC3F& aBgColor, const RAY& aRay, HITINFO& aHitInfo,
1543 bool aIsInsideObject, unsigned int aRecursiveLevel,
1544 bool is_testShadow ) const
1545{
1546 const MATERIAL* objMaterial = aHitInfo.pHitObject->GetMaterial();
1547 wxASSERT( objMaterial != nullptr );
1548
1549 SFVEC3F outColor = objMaterial->GetEmissiveColor() + objMaterial->GetAmbientColor();
1550
1551 if( aRecursiveLevel > 7 )
1552 return outColor;
1553
1554 SFVEC3F hitPoint = aHitInfo.m_HitPoint;
1555
1556 hitPoint += aHitInfo.m_HitNormal * m_boardAdapter.GetNonCopperLayerThickness() * 0.6f;
1557
1558 const SFVEC3F diffuseColorObj = aHitInfo.pHitObject->GetDiffuseColor( aHitInfo );
1559
1560#if USE_EXPERIMENTAL_SOFT_SHADOWS
1562#endif
1563
1564 float shadow_att_factor_sum = 0.0f;
1565
1566 unsigned int nr_lights_that_can_cast_shadows = 0;
1567
1568 for( const LIGHT* light : m_lights )
1569 {
1570 SFVEC3F vectorToLight;
1571 SFVEC3F colorOfLight;
1572 float distToLight;
1573
1574 light->GetLightParameters( hitPoint, vectorToLight, colorOfLight, distToLight );
1575
1576 if( m_isPreview )
1577 colorOfLight = SFVEC3F( 1.0f );
1578
1579 const float NdotL = glm::dot( aHitInfo.m_HitNormal, vectorToLight );
1580
1581 // Only calc shade if the normal is facing the direction of light,
1582 // otherwise it is in the shadow
1583 if( NdotL >= FLT_EPSILON )
1584 {
1585 float shadow_att_factor_light = 1.0f;
1586
1587 if( is_testShadow && light->GetCastShadows() )
1588 {
1589 nr_lights_that_can_cast_shadows++;
1590#if USE_EXPERIMENTAL_SOFT_SHADOWS
1591 // For rays that are recursive, just calculate one hit shadow
1592 if( aRecursiveLevel > 0 )
1593 {
1594#endif
1595 RAY rayToLight;
1596 rayToLight.Init( hitPoint, vectorToLight );
1597
1598 // Test if point is not in the shadow.
1599 // Test for any hit from the point in the direction of light
1600 if( m_accelerator->IntersectP( rayToLight, distToLight ) )
1601 shadow_att_factor_light = 0.0f;
1602
1603#if USE_EXPERIMENTAL_SOFT_SHADOWS
1604 }
1605 else // Experimental softshadow calculation
1606 {
1607 const unsigned int shadow_number_of_samples =
1609 const float shadow_inc_factor = 1.0f / (float) ( shadow_number_of_samples );
1610
1611 for( unsigned int i = 0; i < shadow_number_of_samples; ++i )
1612 {
1613 RAY rayToLight;
1614
1615 if( i == 0 )
1616 {
1617 rayToLight.Init( hitPoint, vectorToLight );
1618 }
1619 else
1620 {
1621 const SFVEC3F unifVector = UniformRandomHemisphereDirection();
1622 const SFVEC3F disturbed_vector_to_light =
1623 glm::normalize( vectorToLight + unifVector *
1625
1626 rayToLight.Init( hitPoint, disturbed_vector_to_light );
1627 }
1628
1629 // !TODO: there are multiple ways that this tests can be
1630 // optimized. Eg: by packing rays or to test against the
1631 // latest hit object.
1632 if( m_accelerator->IntersectP( rayToLight, distToLight ) )
1633 {
1634 shadow_att_factor_light -= shadow_inc_factor;
1635 }
1636 }
1637 }
1638#endif
1639 shadow_att_factor_sum += shadow_att_factor_light;
1640 }
1641
1642 outColor += objMaterial->Shade( aRay, aHitInfo, NdotL, diffuseColorObj, vectorToLight,
1643 colorOfLight, shadow_att_factor_light );
1644 }
1645
1646 // Only use the headlight for preview
1647 if( m_isPreview )
1648 break;
1649 }
1650
1651 // Improvement: this is not taking in account the lightcolor
1652 if( nr_lights_that_can_cast_shadows > 0 )
1653 {
1654 aHitInfo.m_ShadowFactor = glm::max(
1655 shadow_att_factor_sum / (float) ( nr_lights_that_can_cast_shadows * 1.0f ), 0.0f );
1656 }
1657 else
1658 {
1659 aHitInfo.m_ShadowFactor = 1.0f;
1660 }
1661
1662 // Clamp color to not be brighter than 1.0f
1663 outColor = glm::min( outColor, SFVEC3F( 1.0f ) );
1664
1665 if( !m_isPreview )
1666 {
1667 // Reflections
1668 if( ( objMaterial->GetReflection() > 0.0f )
1670 && ( aRecursiveLevel < objMaterial->GetReflectionRecursionCount() ) )
1671 {
1672 const unsigned int reflection_number_of_samples =
1673 objMaterial->GetReflectionRayCount();
1674
1675 SFVEC3F sum_color = SFVEC3F( 0.0f );
1676
1677 const SFVEC3F reflectVector = aRay.m_Dir - 2.0f *
1678 glm::dot( aRay.m_Dir, aHitInfo.m_HitNormal ) * aHitInfo.m_HitNormal;
1679
1680 for( unsigned int i = 0; i < reflection_number_of_samples; ++i )
1681 {
1682 RAY reflectedRay;
1683
1684 if( i == 0 )
1685 {
1686 reflectedRay.Init( hitPoint, reflectVector );
1687 }
1688 else
1689 {
1690 // Apply some randomize to the reflected vector
1691 const SFVEC3F random_reflectVector =
1692 glm::normalize( reflectVector +
1695
1696 reflectedRay.Init( hitPoint, random_reflectVector );
1697 }
1698
1699 HITINFO reflectedHit;
1700 reflectedHit.m_tHit = std::numeric_limits<float>::infinity();
1701
1702 if( m_accelerator->Intersect( reflectedRay, reflectedHit ) )
1703 {
1704 sum_color += ( diffuseColorObj + objMaterial->GetSpecularColor() ) *
1705 shadeHit( aBgColor, reflectedRay, reflectedHit, false,
1706 aRecursiveLevel + 1, is_testShadow ) *
1707 SFVEC3F( objMaterial->GetReflection() *
1708 // Falloff factor
1709 (1.0f / ( 1.0f + 0.75f * reflectedHit.m_tHit *
1710 reflectedHit.m_tHit) ) );
1711 }
1712 }
1713
1714 outColor += (sum_color / SFVEC3F( (float)reflection_number_of_samples) );
1715 }
1716
1717 // Refraction
1718 const float objTransparency = aHitInfo.pHitObject->GetModelTransparency();
1719
1720 if( ( objTransparency > 0.0f ) && m_boardAdapter.m_Cfg->m_Render.raytrace_refractions
1721 && ( aRecursiveLevel < objMaterial->GetRefractionRecursionCount() ) )
1722 {
1723 const float airIndex = 1.000293f;
1724 const float glassIndex = 1.49f;
1725 const float air_over_glass = airIndex / glassIndex;
1726 const float glass_over_air = glassIndex / airIndex;
1727
1728 const float refractionRatio = aIsInsideObject?glass_over_air:air_over_glass;
1729
1730 SFVEC3F refractedVector;
1731
1732 if( Refract( aRay.m_Dir, aHitInfo.m_HitNormal, refractionRatio, refractedVector ) )
1733 {
1734 // This increase the start point by a "fixed" factor so it will work the
1735 // same for all distances
1736 const SFVEC3F startPoint =
1738 0.25f );
1739
1740 const unsigned int refractions_number_of_samples =
1741 objMaterial->GetRefractionRayCount();
1742
1743 SFVEC3F sum_color = SFVEC3F(0.0f);
1744
1745 for( unsigned int i = 0; i < refractions_number_of_samples; ++i )
1746 {
1747 RAY refractedRay;
1748
1749 if( i == 0 )
1750 {
1751 refractedRay.Init( startPoint, refractedVector );
1752 }
1753 else
1754 {
1755 // apply some randomize to the refracted vector
1756 const SFVEC3F randomizeRefractedVector =
1757 glm::normalize( refractedVector +
1760
1761 refractedRay.Init( startPoint, randomizeRefractedVector );
1762 }
1763
1764 HITINFO refractedHit;
1765 refractedHit.m_tHit = std::numeric_limits<float>::infinity();
1766
1767 SFVEC3F refractedColor = aBgColor;
1768
1769 if( m_accelerator->Intersect( refractedRay, refractedHit ) )
1770 {
1771 refractedColor = shadeHit( aBgColor, refractedRay, refractedHit,
1772 !aIsInsideObject, aRecursiveLevel + 1, false );
1773
1774 const SFVEC3F absorbance = ( SFVEC3F(1.0f) - diffuseColorObj ) *
1775 (1.0f - objTransparency ) *
1776 objMaterial->GetAbsorvance() *
1777 refractedHit.m_tHit;
1778
1779 const SFVEC3F transparency = 1.0f / ( absorbance + 1.0f );
1780
1781 sum_color += refractedColor * transparency;
1782 }
1783 else
1784 {
1785 sum_color += refractedColor;
1786 }
1787 }
1788
1789 outColor = outColor * ( 1.0f - objTransparency ) + objTransparency * sum_color
1790 / SFVEC3F( (float) refractions_number_of_samples );
1791 }
1792 else
1793 {
1794 outColor = outColor * ( 1.0f - objTransparency ) + objTransparency * aBgColor;
1795 }
1796 }
1797 }
1798
1799 return outColor;
1800}
1801
1802
1804{
1805 initPbo();
1806}
1807
1808
1810{
1811 if( GLEW_ARB_pixel_buffer_object )
1812 {
1814
1815 // Try to delete vbo if it was already initialized
1816 deletePbo();
1817
1818 // Learn about Pixel buffer objects at:
1819 // http://www.songho.ca/opengl/gl_pbo.html
1820 // http://web.eecs.umich.edu/~sugih/courses/eecs487/lectures/25-PBO+Mipmapping.pdf
1821 // "create 2 pixel buffer objects, you need to delete them when program exits.
1822 // glBufferDataARB with NULL pointer reserves only memory space."
1823
1824 // This sets the number of RGBA pixels
1826
1827 glGenBuffersARB( 1, &m_pboId );
1828 glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboId );
1829 glBufferDataARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_pboDataSize, 0, GL_STREAM_DRAW_ARB );
1830 glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
1831
1832 wxLogTrace( m_logTrace,
1833 wxT( "RENDER_3D_RAYTRACE:: GLEW_ARB_pixel_buffer_object is supported" ) );
1834 }
1835}
1836
1837
1839{
1841
1842 return true;
1843}
1844
1845
1846static float distance( const SFVEC2UI& a, const SFVEC2UI& b )
1847{
1848 const float dx = (float) a.x - (float) b.x;
1849 const float dy = (float) a.y - (float) b.y;
1850 return hypotf( dx, dy );
1851}
1852
1853
1855{
1857
1858 // Calc block positions for fast preview mode
1859 m_blockPositionsFast.clear();
1860
1861 unsigned int i = 0;
1862
1863 while(1)
1864 {
1865 const unsigned int mX = DecodeMorton2X(i);
1866 const unsigned int mY = DecodeMorton2Y(i);
1867
1868 i++;
1869
1870 const SFVEC2UI blockPos( mX * 4 * RAYPACKET_DIM - mX * 4,
1871 mY * 4 * RAYPACKET_DIM - mY * 4 );
1872
1873 if( ( blockPos.x >= ( (unsigned int)m_windowSize.x - ( 4 * RAYPACKET_DIM + 4 ) ) ) &&
1874 ( blockPos.y >= ( (unsigned int)m_windowSize.y - ( 4 * RAYPACKET_DIM + 4 ) ) ) )
1875 break;
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 {
1880 m_blockPositionsFast.push_back( blockPos );
1881
1882 if( blockPos.x > m_realBufferSize.x )
1883 m_realBufferSize.x = blockPos.x;
1884
1885 if( blockPos.y > m_realBufferSize.y )
1886 m_realBufferSize.y = blockPos.y;
1887 }
1888 }
1889
1891
1894
1895 m_xoffset = ( m_windowSize.x - m_realBufferSize.x ) / 2;
1896 m_yoffset = ( m_windowSize.y - m_realBufferSize.y ) / 2;
1897
1899
1900 // Calc block positions for regular rendering. Choose an 'inside out' style of rendering.
1901 m_blockPositions.clear();
1902 const int blocks_x = m_realBufferSize.x / RAYPACKET_DIM;
1903 const int blocks_y = m_realBufferSize.y / RAYPACKET_DIM;
1904 m_blockPositions.reserve( blocks_x * blocks_y );
1905
1906 for( int x = 0; x < blocks_x; ++x )
1907 {
1908 for( int y = 0; y < blocks_y; ++y )
1909 m_blockPositions.emplace_back( x * RAYPACKET_DIM, y * RAYPACKET_DIM );
1910 }
1911
1912 const SFVEC2UI center( m_realBufferSize.x / 2, m_realBufferSize.y / 2 );
1913 std::sort( m_blockPositions.begin(), m_blockPositions.end(),
1914 [&]( const SFVEC2UI& a, const SFVEC2UI& b ) {
1915 // Sort order: inside out.
1916 return distance( a, center ) < distance( b, center );
1917 } );
1918
1919 // Create m_shader buffer
1920 delete[] m_shaderBuffer;
1922
1923 initPbo();
1924}
1925
1926
1928{
1929 HITINFO hitInfo;
1930 hitInfo.m_tHit = std::numeric_limits<float>::infinity();
1931
1932 if( m_accelerator )
1933 {
1934 if( m_accelerator->Intersect( aRay, hitInfo ) )
1935 {
1936 if( hitInfo.pHitObject )
1937 return hitInfo.pHitObject->GetBoardItem();
1938 }
1939 }
1940
1941 return nullptr;
1942}
Defines math related functions.
Defines math related functions.
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
SFVEC3F UniformRandomHemisphereDirection()
Definition: 3d_math.h:55
int color
Definition: DXF_plotter.cpp:57
virtual bool Intersect(const RAY &aRay, HITINFO &aHitInfo) const =0
virtual bool IntersectP(const RAY &aRay, float aMaxDistance) const =0
Helper class to handle information needed to display 3D board.
Definition: board_adapter.h:69
SFVEC4F m_BgColorTop
background top color
float GetNonCopperLayerThickness() const noexcept
Get the non copper layers thickness (in 3D units).
EDA_3D_VIEWER_SETTINGS * m_Cfg
SFVEC4F m_BgColorBot
background bottom color
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:70
A class used to derive camera objects from.
Definition: camera.h:78
const SFVEC3F & GetDir() const
Definition: camera.h:109
bool ParametersChanged()
Definition: camera.cpp:662
void SetDirection(const SFVEC3F &aDir)
Set directional light orientation.
Definition: light.h:131
Implement a canvas based on a wxGLCanvas.
Definition: eda_3d_canvas.h:49
A base light class to derive to implement other light classes.
Definition: light.h:41
Base material class that can be used to derive other material implementations.
Definition: material.h:240
float GetAbsorvance() const
Definition: material.h:275
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.
const SFVEC3F & GetAmbientColor() const
Definition: material.h:268
unsigned int GetRefractionRayCount() const
Definition: material.h:276
unsigned int GetRefractionRecursionCount() const
Definition: material.h:279
const SFVEC3F & GetSpecularColor() const
Definition: material.h:270
const SFVEC3F & GetEmissiveColor() const
Definition: material.h:269
float GetReflection() const
Definition: material.h:274
unsigned int GetReflectionRayCount() const
Definition: material.h:277
virtual SFVEC3F GetDiffuseColor(const HITINFO &aHitInfo) const =0
BOARD_ITEM * GetBoardItem() const
Definition: object_3d.h:56
virtual bool Intersect(const RAY &aRay, HITINFO &aHitInfo) const =0
float GetModelTransparency() const
Definition: object_3d.h:65
const MATERIAL * GetMaterial() const
Definition: object_3d.h:64
void SetShadedBuffer(SFVEC3F *aShadedBuffer)
void SetShadowsEnabled(bool aIsShadowsEnabled)
void UpdateSize(const SFVEC2UI &aSize)
Definition: post_shader.cpp:73
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
void InitFrame()
Definition: post_shader.h:56
This is a base class to hold data and functions for render targets.
CAMERA & m_camera
Flag if the opengl specific for this render was already initialized.
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.
bool m_is_opengl_initialized
BOARD_ADAPTER & m_boardAdapter
DIRECTIONAL_LIGHT * m_cameraLight
unsigned int m_converted2dRoundSegmentCount
std::vector< SFVEC2UI > m_blockPositionsFast
int GetWaitForEditingTimeOut() override
Give the interface the time (in ms) that it should wait for editing or movements before (this works f...
HITINFO_PACKET * m_firstHitinfo
POST_SHADER_SSAO m_postShaderSsao
unsigned long int m_renderStartTime
Time that the render starts.
void SetCurWindowSize(const wxSize &aSize) override
Before each render, the canvas will tell the render what is the size of its windows,...
RENDER_3D_RAYTRACE(EDA_3D_CANVAS *aCanvas, BOARD_ADAPTER &aAdapter, CAMERA &aCamera)
BOARD_ITEM * IntersectBoardItem(const RAY &aRay)
CONTAINER_2D * m_outlineBoard2dObjects
std::vector< SFVEC2UI > m_blockPositions
Flag if a position was already processed (cleared each new render).
wxSize m_oldWindowsSize
Encode Morton code positions.
ACCELERATOR_3D * m_accelerator
unsigned int m_convertedDummyBlockCount
void postProcessShading(GLubyte *ptrPBO, REPORTER *aStatusReporter)
size_t m_blockRenderProgressCount
Save the number of blocks progress of the render.
void renderTracing(GLubyte *ptrPBO, REPORTER *aStatusReporter)
SFVEC3F shadeHit(const SFVEC3F &aBgColor, const RAY &aRay, HITINFO &aHitInfo, bool aIsInsideObject, unsigned int aRecursiveLevel, bool is_testShadow) const
void renderFinalColor(GLubyte *ptrPBO, const SFVEC3F &rgbColor, bool applyColorSpaceConversion)
std::vector< int > m_blockPositionsWasProcessed
Encode the Morton code positions (on fast preview mode).
void renderBlockTracing(GLubyte *ptrPBO, signed int iBlock)
void postProcessBlurFinish(GLubyte *ptrPBO, REPORTER *aStatusReporter)
void render(GLubyte *ptrPBO, REPORTER *aStatusReporter)
SFVEC3F m_backgroundColorBottom
Used to see if the windows size changed.
RT_RENDER_STATE m_renderState
State used on quality render.
void renderRayPackets(const SFVEC3F *bgColorY, const RAY *aRayPkt, HITINFO_PACKET *aHitPacket, bool is_testShadow, SFVEC3F *aOutHitColor)
std::list< LIGHT * > m_lights
void renderPreview(GLubyte *ptrPBO)
void Reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter, bool aOnlyLoadCopperAndShapes)
void renderAntiAliasPackets(const SFVEC3F *aBgColorY, const HITINFO_PACKET *aHitPck_X0Y0, const HITINFO_PACKET *aHitPck_AA_X1Y1, const RAY *aRayPck, SFVEC3F *aOutHitColor)
BVH_CONTAINER_2D * m_antioutlineBoard2dObjects
bool Redraw(bool aIsMoving, REPORTER *aStatusReporter, REPORTER *aWarningReporter) override
Redraw the view.
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
COLOR_RGB BlendColor(const COLOR_RGB &aC1, const COLOR_RGB &aC2)
Definition: color_rgb.cpp:41
#define _(s)
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
uint32_t DecodeMorton2Y(uint32_t code)
uint32_t DecodeMorton2X(uint32_t code)
Definition: mortoncodes.cpp:98
Implements Morton Codes https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/ http://www....
void OglDrawBackground(const SFVEC3F &aTopColor, const SFVEC3F &aBotColor)
Definition: ogl_utils.cpp:160
unsigned GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
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
void RAYPACKET_InitRays_with2DDisplacement(const CAMERA &aCamera, const SFVEC2F &aWindowsPosition, const SFVEC2F &a2DWindowsPosDisplacementFactor, RAY *aRayPck)
Definition: raypacket.cpp:162
#define RAYPACKET_INVMASK
Definition: raypacket.h:34
#define RAYPACKET_RAYS_PER_PACKET
Definition: raypacket.h:35
#define RAYPACKET_DIM
Definition: raypacket.h:32
#define SRGB_GAMA
SFVEC3F ConvertSRGBToLinear(const SFVEC3F &aSRGBcolor)
static void SetPixel(GLubyte *p, const COLOR_RGB &v)
static void HITINFO_PACKET_init(HITINFO_PACKET *aHitPacket)
static SFVEC3F convertLinearToSRGB(const SFVEC3F &aRGBcolor)
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
#define DISP_FACTOR
@ RT_RENDER_STATE_POST_PROCESS_SHADE
@ RT_RENDER_STATE_POST_PROCESS_BLUR_AND_FINISH
@ RT_RENDER_STATE_FINISH
@ RT_RENDER_STATE_TRACING
@ RT_RENDER_STATE_MAX
bool m_hitresult
Definition: hitinfo.h:57
HITINFO m_HitInfo
Definition: hitinfo.h:58
Stores the hit information of a ray with a point on the surface of a object.
Definition: hitinfo.h:36
unsigned int m_acc_node_info
( 4) The acc stores here the node that it hits
Definition: hitinfo.h:42
float m_tHit
( 4) distance
Definition: hitinfo.h:38
const OBJECT_3D * pHitObject
( 4) Object that was hitted
Definition: hitinfo.h:40
float m_ShadowFactor
( 4) Shadow attenuation (1.0 no shadow, 0.0f darkness)
Definition: hitinfo.h:45
SFVEC3F m_HitNormal
(12) normal at the hit point
Definition: hitinfo.h:37
SFVEC3F m_HitPoint
(12) hit position
Definition: hitinfo.h:44
RAY m_ray[RAYPACKET_RAYS_PER_PACKET]
Definition: raypacket.h:54
Definition: ray.h:63
SFVEC3F m_Dir
Definition: ray.h:67
void Init(const SFVEC3F &o, const SFVEC3F &d)
Definition: ray.cpp:35
SFVEC3F at(float t) const
Definition: ray.h:84
unsigned char c[3]
Definition: color_rgb.h:36
glm::ivec2 SFVEC2I
Definition: xv3d_types.h:39
glm::vec2 SFVEC2F
Definition: xv3d_types.h:42
glm::vec3 SFVEC3F
Definition: xv3d_types.h:44
glm::uvec2 SFVEC2UI
Definition: xv3d_types.h:38