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