KiCad PCB EDA Suite
Loading...
Searching...
No Matches
raytracing/create_scene.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-2022 Mario Luzeiro <[email protected]>
5 * Copyright (C) 2023 CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
27#include "shapes3D/plane_3d.h"
33#include "shapes2D/ring_2d.h"
34#include "shapes2D/polygon_2d.h"
38#include "3d_fastmath.h"
39#include "3d_math.h"
40
41#include <board.h>
42#include <footprint.h>
43#include <fp_lib_table.h>
44#include <eda_3d_viewer_frame.h>
45#include <project_pcb.h>
46
47#include <base_units.h>
48#include <core/profile.h> // To use GetRunningMicroSecs or another profiling utility
49
58static float TransparencyControl( float aGrayColorValue, float aTransparency )
59{
60 const float aaa = aTransparency * aTransparency * aTransparency;
61
62 // 1.00-1.05*(1.0-x)^3
63 float ca = 1.0f - aTransparency;
64 ca = 1.00f - 1.05f * ca * ca * ca;
65
66 return glm::max( glm::min( aGrayColorValue * ca + aaa, 1.0f ), 0.0f );
67}
68
72#define UNITS3D_TO_UNITSPCB ( pcbIUScale.IU_PER_MM )
73
74
76{
78 m_boardAdapter.m_Cfg->m_Render.raytrace_nrsamples_refractions );
80 m_boardAdapter.m_Cfg->m_Render.raytrace_nrsamples_reflections );
81
83 m_boardAdapter.m_Cfg->m_Render.raytrace_recursivelevel_refractions );
85 m_boardAdapter.m_Cfg->m_Render.raytrace_recursivelevel_reflections );
86
87 double mmTo3Dunits = pcbIUScale.IU_PER_MM * m_boardAdapter.BiuTo3dUnits();
88
89 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
90 {
91 m_boardMaterial = BOARD_NORMAL( 0.40f * mmTo3Dunits );
92 m_copperMaterial = COPPER_NORMAL( 4.0f * mmTo3Dunits, &m_boardMaterial );
93 m_platedCopperMaterial = PLATED_COPPER_NORMAL( 0.5f * mmTo3Dunits );
95 m_plasticMaterial = PLASTIC_NORMAL( 0.05f * mmTo3Dunits );
96 m_shinyPlasticMaterial = PLASTIC_SHINE_NORMAL( 0.1f * mmTo3Dunits );
97 m_brushedMetalMaterial = BRUSHED_METAL_NORMAL( 0.05f * mmTo3Dunits );
98 m_silkScreenMaterial = SILK_SCREEN_NORMAL( 0.25f * mmTo3Dunits );
99 }
100
101 // http://devernay.free.fr/cours/opengl/materials.html
102 // Copper
103 const SFVEC3F copperSpecularLinear =
104 ConvertSRGBToLinear( glm::clamp( (SFVEC3F) m_boardAdapter.m_CopperColor * 0.5f + 0.25f,
105 SFVEC3F( 0.0f ), SFVEC3F( 1.0f ) ) );
106
108 ConvertSRGBToLinear( (SFVEC3F) m_boardAdapter.m_CopperColor * 0.3f ),
109 SFVEC3F( 0.0f ), copperSpecularLinear, 0.4f * 128.0f, 0.0f, 0.0f );
110
111 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
112 m_materials.m_Copper.SetGenerator( &m_platedCopperMaterial );
113
114 m_materials.m_NonPlatedCopper = BLINN_PHONG_MATERIAL(
115 ConvertSRGBToLinear( SFVEC3F( 0.191f, 0.073f, 0.022f ) ), SFVEC3F( 0.0f, 0.0f, 0.0f ),
116 SFVEC3F( 0.256f, 0.137f, 0.086f ), 0.15f * 128.0f, 0.0f, 0.0f );
117
118 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
119 m_materials.m_NonPlatedCopper.SetGenerator( &m_copperMaterial );
120
122 ConvertSRGBToLinear( (SFVEC3F) m_boardAdapter.m_SolderPasteColor )
123 * ConvertSRGBToLinear( (SFVEC3F) m_boardAdapter.m_SolderPasteColor ),
124 SFVEC3F( 0.0f, 0.0f, 0.0f ),
125 ConvertSRGBToLinear( (SFVEC3F) m_boardAdapter.m_SolderPasteColor )
127 (SFVEC3F) m_boardAdapter.m_SolderPasteColor ),
128 0.10f * 128.0f, 0.0f, 0.0f );
129
131 SFVEC3F( 0.0f, 0.0f, 0.0f ),
132 glm::clamp( ( ( SFVEC3F )( 1.0f ) - ConvertSRGBToLinear(
133 (SFVEC3F) m_boardAdapter.m_SilkScreenColorTop ) ),
134 SFVEC3F( 0.0f ), SFVEC3F( 0.10f ) ), 0.078125f * 128.0f, 0.0f, 0.0f );
135
136 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
137 m_materials.m_SilkS.SetGenerator( &m_silkScreenMaterial );
138
139 // Assume that SolderMaskTop == SolderMaskBot
140 const float solderMask_gray =
141 ( m_boardAdapter.m_SolderMaskColorTop.r + m_boardAdapter.m_SolderMaskColorTop.g
142 + m_boardAdapter.m_SolderMaskColorTop.b )
143 / 3.0f;
144
145 const float solderMask_transparency = TransparencyControl( solderMask_gray,
146 1.0f - m_boardAdapter.m_SolderMaskColorTop.a );
147
148 m_materials.m_SolderMask = BLINN_PHONG_MATERIAL(
149 ConvertSRGBToLinear( (SFVEC3F) m_boardAdapter.m_SolderMaskColorTop ) * 0.10f,
150 SFVEC3F( 0.0f, 0.0f, 0.0f ),
151 SFVEC3F( glm::clamp( solderMask_gray * 2.0f, 0.25f, 1.0f ) ), 0.85f * 128.0f,
152 solderMask_transparency, 0.16f );
153
154 m_materials.m_SolderMask.SetCastShadows( true );
155 m_materials.m_SolderMask.SetRefractionRayCount( 1 );
156
157 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
158 m_materials.m_SolderMask.SetGenerator( &m_solderMaskMaterial );
159
160 m_materials.m_EpoxyBoard =
161 BLINN_PHONG_MATERIAL( ConvertSRGBToLinear( SFVEC3F( 16.0f / 255.0f, 14.0f / 255.0f,
162 10.0f / 255.0f ) ),
163 SFVEC3F( 0.0f, 0.0f, 0.0f ),
164 ConvertSRGBToLinear( SFVEC3F( 10.0f / 255.0f, 8.0f / 255.0f,
165 10.0f / 255.0f ) ),
166 0.1f * 128.0f, 1.0f - m_boardAdapter.m_BoardBodyColor.a, 0.0f );
167
168 m_materials.m_EpoxyBoard.SetAbsorvance( 10.0f );
169
170 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
171 m_materials.m_EpoxyBoard.SetGenerator( &m_boardMaterial );
172
173 SFVEC3F bgTop = ConvertSRGBToLinear( (SFVEC3F) m_boardAdapter.m_BgColorTop );
174
175 m_materials.m_Floor = BLINN_PHONG_MATERIAL( bgTop * 0.125f, SFVEC3F( 0.0f, 0.0f, 0.0f ),
176 ( SFVEC3F( 1.0f ) - bgTop ) / 3.0f,
177 0.10f * 128.0f, 1.0f, 0.50f );
178 m_materials.m_Floor.SetCastShadows( false );
179 m_materials.m_Floor.SetReflectionRecursionCount( 1 );
180}
181
182
183void RENDER_3D_RAYTRACE_BASE::createObject( CONTAINER_3D& aDstContainer, const OBJECT_2D* aObject2D,
184 float aZMin, float aZMax, const MATERIAL* aMaterial,
185 const SFVEC3F& aObjColor )
186{
187 switch( aObject2D->GetObjectType() )
188 {
190 {
192
193 XY_PLANE* objPtr;
194 objPtr = new XY_PLANE( BBOX_3D(
195 SFVEC3F( aObject2D->GetBBox().Min().x, aObject2D->GetBBox().Min().y, aZMin ),
196 SFVEC3F( aObject2D->GetBBox().Max().x, aObject2D->GetBBox().Max().y, aZMin ) ) );
197 objPtr->SetMaterial( aMaterial );
198 objPtr->SetColor( ConvertSRGBToLinear( aObjColor ) );
199 aDstContainer.Add( objPtr );
200
201 objPtr = new XY_PLANE( BBOX_3D(
202 SFVEC3F( aObject2D->GetBBox().Min().x, aObject2D->GetBBox().Min().y, aZMax ),
203 SFVEC3F( aObject2D->GetBBox().Max().x, aObject2D->GetBBox().Max().y, aZMax ) ) );
204 objPtr->SetMaterial( aMaterial );
205 objPtr->SetColor( ConvertSRGBToLinear( aObjColor ) );
206 aDstContainer.Add( objPtr );
207 break;
208 }
209
211 {
213
214 const ROUND_SEGMENT_2D* aRoundSeg2D = static_cast<const ROUND_SEGMENT_2D*>( aObject2D );
215 ROUND_SEGMENT* objPtr = new ROUND_SEGMENT( *aRoundSeg2D, aZMin, aZMax );
216 objPtr->SetMaterial( aMaterial );
217 objPtr->SetColor( ConvertSRGBToLinear( aObjColor ) );
218 aDstContainer.Add( objPtr );
219 break;
220 }
221
222 default:
223 {
224 LAYER_ITEM* objPtr = new LAYER_ITEM( aObject2D, aZMin, aZMax );
225 objPtr->SetMaterial( aMaterial );
226 objPtr->SetColor( ConvertSRGBToLinear( aObjColor ) );
227 aDstContainer.Add( objPtr );
228 break;
229 }
230 }
231}
232
233
235 PCB_LAYER_ID aLayer_id,
236 const MATERIAL* aMaterialLayer,
237 const SFVEC3F& aLayerColor,
238 float aLayerZOffset )
239{
240 if( aContainer2d == nullptr )
241 return;
242
244 bool isSilk = aLayer_id == B_SilkS || aLayer_id == F_SilkS;
245 const LIST_OBJECT2D& listObject2d = aContainer2d->GetList();
246
247 if( listObject2d.size() == 0 )
248 return;
249
250 for( const OBJECT_2D* object2d_A : listObject2d )
251 {
252 // not yet used / implemented (can be used in future to clip the objects in the
253 // board borders
254 OBJECT_2D* object2d_C = CSGITEM_FULL;
255
256 std::vector<const OBJECT_2D*>* object2d_B = CSGITEM_EMPTY;
257
258 object2d_B = new std::vector<const OBJECT_2D*>();
259
260 // Subtract holes but not in SolderPaste
261 // (can be added as an option in future)
262 if( !( aLayer_id == B_Paste || aLayer_id == F_Paste ) )
263 {
264 // Check if there are any layerhole that intersects this object
265 // Eg: a segment is cut by a via hole or THT hole.
266 const MAP_CONTAINER_2D_BASE& layerHolesMap = m_boardAdapter.GetLayerHoleMap();
267
268 if( layerHolesMap.find( aLayer_id ) != layerHolesMap.end() )
269 {
270 const BVH_CONTAINER_2D* holes2d = layerHolesMap.at( aLayer_id );
271
272 CONST_LIST_OBJECT2D intersecting;
273
274 holes2d->GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
275
276 for( const OBJECT_2D* hole2d : intersecting )
277 object2d_B->push_back( hole2d );
278 }
279
280 // Check if there are any THT that intersects this object. If we're processing a silk
281 // layer and the flag is set, then clip the silk at the outer edge of the annular ring,
282 // rather than the at the outer edge of the copper plating.
283 const BVH_CONTAINER_2D& throughHoleOuter =
284 cfg.clip_silk_on_via_annuli && isSilk ? m_boardAdapter.GetViaAnnuli()
285 : m_boardAdapter.GetTH_ODs();
286
287 if( !throughHoleOuter.GetList().empty() )
288 {
289 CONST_LIST_OBJECT2D intersecting;
290
291 throughHoleOuter.GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
292
293 for( const OBJECT_2D* hole2d : intersecting )
294 object2d_B->push_back( hole2d );
295 }
296 }
297
298 if( !m_antioutlineBoard2dObjects->GetList().empty() )
299 {
300 CONST_LIST_OBJECT2D intersecting;
301
302 m_antioutlineBoard2dObjects->GetIntersectingObjects( object2d_A->GetBBox(),
303 intersecting );
304
305 for( const OBJECT_2D* obj : intersecting )
306 object2d_B->push_back( obj );
307 }
308
309 const MAP_CONTAINER_2D_BASE& mapLayers = m_boardAdapter.GetLayerMap();
310
312 && ( ( aLayer_id == B_SilkS && mapLayers.find( B_Mask ) != mapLayers.end() )
313 || ( aLayer_id == F_SilkS && mapLayers.find( F_Mask ) != mapLayers.end() ) ) )
314 {
315 const PCB_LAYER_ID maskLayer = ( aLayer_id == B_SilkS ) ? B_Mask : F_Mask;
316
317 const BVH_CONTAINER_2D* containerMaskLayer2d = mapLayers.at( maskLayer );
318
319 CONST_LIST_OBJECT2D intersecting;
320
321 if( containerMaskLayer2d ) // can be null if B_Mask or F_Mask is not shown
322 containerMaskLayer2d->GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
323
324 for( const OBJECT_2D* obj2d : intersecting )
325 object2d_B->push_back( obj2d );
326 }
327
328 if( object2d_B->empty() )
329 {
330 delete object2d_B;
331 object2d_B = CSGITEM_EMPTY;
332 }
333
334 if( ( object2d_B == CSGITEM_EMPTY ) && ( object2d_C == CSGITEM_FULL ) )
335 {
336 LAYER_ITEM* objPtr = new LAYER_ITEM( object2d_A,
337 m_boardAdapter.GetLayerBottomZPos( aLayer_id ) - aLayerZOffset,
338 m_boardAdapter.GetLayerTopZPos( aLayer_id ) + aLayerZOffset );
339 objPtr->SetMaterial( aMaterialLayer );
340 objPtr->SetColor( ConvertSRGBToLinear( aLayerColor ) );
341 m_objectContainer.Add( objPtr );
342 }
343 else
344 {
345 LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( object2d_A, object2d_B, object2d_C,
346 object2d_A->GetBoardItem() );
347 m_containerWithObjectsToDelete.Add( itemCSG2d );
348
349 LAYER_ITEM* objPtr = new LAYER_ITEM( itemCSG2d,
350 m_boardAdapter.GetLayerBottomZPos( aLayer_id ) - aLayerZOffset,
351 m_boardAdapter.GetLayerTopZPos( aLayer_id ) + aLayerZOffset );
352
353 objPtr->SetMaterial( aMaterialLayer );
354 objPtr->SetColor( ConvertSRGBToLinear( aLayerColor ) );
355
356 m_objectContainer.Add( objPtr );
357 }
358 }
359}
360
361
362extern void buildBoardBoundingBoxPoly( const BOARD* aBoard, SHAPE_POLY_SET& aOutline );
363
364
365void RENDER_3D_RAYTRACE_BASE::Reload( REPORTER* aStatusReporter, REPORTER* aWarningReporter,
366 bool aOnlyLoadCopperAndShapes )
367{
368 m_reloadRequested = false;
369
370 m_modelMaterialMap.clear();
371
374
375 int64_t stats_startReloadTime = GetRunningMicroSecs();
376
377 if( !aOnlyLoadCopperAndShapes )
378 {
379 m_boardAdapter.InitSettings( aStatusReporter, aWarningReporter );
380
381 SFVEC3F camera_pos = m_boardAdapter.GetBoardCenter();
382 m_camera.SetBoardLookAtPos( camera_pos );
383 }
384
385 m_objectContainer.Clear();
387
389
390 if( aStatusReporter )
391 aStatusReporter->Report( _( "Load Raytracing: board" ) );
392
393 // Create and add the outline board
396
399
400 std::bitset<LAYER_3D_END> layerFlags = m_boardAdapter.GetVisibleLayers();
401
402 if( !aOnlyLoadCopperAndShapes )
403 {
404 const int outlineCount = m_boardAdapter.GetBoardPoly().OutlineCount();
405
406 if( outlineCount > 0 )
407 {
408 float divFactor = 0.0f;
409
410 if( m_boardAdapter.GetViaCount() )
411 divFactor = m_boardAdapter.GetAverageViaHoleDiameter() * 18.0f;
412 else if( m_boardAdapter.GetHoleCount() )
413 divFactor = m_boardAdapter.GetAverageHoleDiameter() * 8.0f;
414
415 SHAPE_POLY_SET boardPolyCopy = m_boardAdapter.GetBoardPoly();
416
417 // Calculate an antiboard outline
418 SHAPE_POLY_SET antiboardPoly;
419
420 buildBoardBoundingBoxPoly( m_boardAdapter.GetBoard(), antiboardPoly );
421
422 antiboardPoly.BooleanSubtract( boardPolyCopy );
423 antiboardPoly.Fracture();
424
425 for( int ii = 0; ii < antiboardPoly.OutlineCount(); ii++ )
426 {
428 m_boardAdapter.BiuTo3dUnits(), -1.0f,
429 *m_boardAdapter.GetBoard(), ii );
430 }
431
432 m_antioutlineBoard2dObjects->BuildBVH();
433
434 boardPolyCopy.Fracture();
435
436 for( int ii = 0; ii < boardPolyCopy.OutlineCount(); ii++ )
437 {
439 m_boardAdapter.BiuTo3dUnits(), divFactor,
440 *m_boardAdapter.GetBoard(), ii );
441 }
442
443 if( layerFlags.test( LAYER_3D_BOARD ) )
444 {
445 const LIST_OBJECT2D& listObjects = m_outlineBoard2dObjects->GetList();
446
447 for( const OBJECT_2D* object2d_A : listObjects )
448 {
449 std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
450
451 // Check if there are any THT that intersects this outline object part
452 if( !m_boardAdapter.GetTH_ODs().GetList().empty() )
453 {
454 const BVH_CONTAINER_2D& throughHoles = m_boardAdapter.GetTH_ODs();
455 CONST_LIST_OBJECT2D intersecting;
456
457 throughHoles.GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
458
459 for( const OBJECT_2D* hole : intersecting )
460 {
461 if( object2d_A->Intersects( hole->GetBBox() ) )
462 object2d_B->push_back( hole );
463 }
464 }
465
466 if( !m_antioutlineBoard2dObjects->GetList().empty() )
467 {
468 CONST_LIST_OBJECT2D intersecting;
469
470 m_antioutlineBoard2dObjects->GetIntersectingObjects( object2d_A->GetBBox(),
471 intersecting );
472
473 for( const OBJECT_2D* obj : intersecting )
474 object2d_B->push_back( obj );
475 }
476
477 if( object2d_B->empty() )
478 {
479 delete object2d_B;
480 object2d_B = CSGITEM_EMPTY;
481 }
482
483 if( object2d_B == CSGITEM_EMPTY )
484 {
485 LAYER_ITEM* objPtr = new LAYER_ITEM( object2d_A,
486 m_boardAdapter.GetLayerBottomZPos( F_Cu ),
487 m_boardAdapter.GetLayerBottomZPos( B_Cu ) );
488
489 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
490 objPtr->SetColor( ConvertSRGBToLinear( m_boardAdapter.m_BoardBodyColor ) );
491 m_objectContainer.Add( objPtr );
492 }
493 else
494 {
495
496 LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( object2d_A, object2d_B,
498 *m_boardAdapter.GetBoard() );
499
500 m_containerWithObjectsToDelete.Add( itemCSG2d );
501
502 LAYER_ITEM* objPtr = new LAYER_ITEM( itemCSG2d,
503 m_boardAdapter.GetLayerBottomZPos( F_Cu ),
504 m_boardAdapter.GetLayerBottomZPos( B_Cu ) );
505
506 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
507 objPtr->SetColor( ConvertSRGBToLinear( m_boardAdapter.m_BoardBodyColor ) );
508 m_objectContainer.Add( objPtr );
509 }
510 }
511
512 // Add cylinders of the board body to container
513 // Note: This is actually a workaround for the holes in the board.
514 // The issue is because if a hole is in a border of a divided polygon ( ex
515 // a polygon or dummy block) it will cut also the render of the hole.
516 // So this will add a full hole.
517 // In fact, that is not need if the hole have copper.
518 if( !m_boardAdapter.GetTH_ODs().GetList().empty() )
519 {
520 const LIST_OBJECT2D& holeList = m_boardAdapter.GetTH_ODs().GetList();
521
522 for( const OBJECT_2D* hole2d : holeList )
523 {
524 if( !m_antioutlineBoard2dObjects->GetList().empty() )
525 {
526 CONST_LIST_OBJECT2D intersecting;
527
528 m_antioutlineBoard2dObjects->GetIntersectingObjects( hole2d->GetBBox(),
529 intersecting );
530
531 // Do not add cylinder if it intersects the edge of the board
532 if( !intersecting.empty() )
533 continue;
534 }
535
536 switch( hole2d->GetObjectType() )
537 {
539 {
540 const float radius = hole2d->GetBBox().GetExtent().x * 0.5f * 0.999f;
541
542 CYLINDER* objPtr = new CYLINDER( hole2d->GetCentroid(),
543 NextFloatDown( m_boardAdapter.GetLayerBottomZPos( F_Cu ) ),
544 NextFloatUp( m_boardAdapter.GetLayerBottomZPos( B_Cu ) ),
545 radius );
546
547 objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
548 objPtr->SetColor(
549 ConvertSRGBToLinear( m_boardAdapter.m_BoardBodyColor ) );
550
551 m_objectContainer.Add( objPtr );
552 }
553 break;
554
555 default:
556 break;
557 }
558 }
559 }
560 }
561 }
562 }
563
564 if( aStatusReporter )
565 aStatusReporter->Report( _( "Load Raytracing: layers" ) );
566
567 // Add layers maps (except B_Mask and F_Mask)
568 for( const std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& entry :
569 m_boardAdapter.GetLayerMap() )
570 {
571 const PCB_LAYER_ID layer_id = entry.first;
572 const BVH_CONTAINER_2D* container2d = entry.second;
573
574 // Only process layers that exist
575 if( !container2d )
576 continue;
577
578 if( aOnlyLoadCopperAndShapes && !IsCopperLayer( layer_id ) )
579 continue;
580
581 // Mask layers are not processed here because they are a special case
582 if( layer_id == B_Mask || layer_id == F_Mask )
583 continue;
584
585 MATERIAL* materialLayer = &m_materials.m_SilkS;
586 SFVEC3F layerColor = SFVEC3F( 0.0f, 0.0f, 0.0f );
587
588 switch( layer_id )
589 {
590 case B_Adhes:
591 case F_Adhes:
592 break;
593
594 case B_Paste:
595 case F_Paste:
596 materialLayer = &m_materials.m_Paste;
597 layerColor = m_boardAdapter.m_SolderPasteColor;
598 break;
599
600 case B_SilkS:
601 materialLayer = &m_materials.m_SilkS;
602 layerColor = m_boardAdapter.m_SilkScreenColorBot;
603 break;
604
605 case F_SilkS:
606 materialLayer = &m_materials.m_SilkS;
607 layerColor = m_boardAdapter.m_SilkScreenColorTop;
608 break;
609
610 case Dwgs_User:
611 layerColor = m_boardAdapter.m_UserDrawingsColor;
612 break;
613
614 case Cmts_User:
615 layerColor = m_boardAdapter.m_UserCommentsColor;
616 break;
617
618 case Eco1_User:
619 layerColor = m_boardAdapter.m_ECO1Color;
620 break;
621
622 case Eco2_User:
623 layerColor = m_boardAdapter.m_ECO2Color;
624 break;
625
626 case B_CrtYd:
627 case F_CrtYd:
628 break;
629
630 case B_Fab:
631 case F_Fab:
632 break;
633
634 default:
635 {
636 int layer3D = MapPCBLayerTo3DLayer( layer_id );
637
638 // Note: MUST do this in LAYER_3D space; User_1..User_45 are NOT contiguous
639 if( layer3D >= LAYER_3D_USER_1 && layer3D <= LAYER_3D_USER_45 )
640 {
641 layerColor = m_boardAdapter.m_UserDefinedLayerColor[ layer3D - LAYER_3D_USER_1 ];
642 }
643 else if( m_boardAdapter.m_Cfg->m_Render.differentiate_plated_copper )
644 {
645 layerColor = SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f, 50.0f / 255.0f );
646 materialLayer = &m_materials.m_NonPlatedCopper;
647 }
648 else
649 {
650 layerColor = m_boardAdapter.m_CopperColor;
651 materialLayer = &m_materials.m_Copper;
652 }
653
654 break;
655 }
656 }
657
658 createItemsFromContainer( container2d, layer_id, materialLayer, layerColor, 0.0f );
659 } // for each layer on map
660
661 // Create plated copper
662 if( m_boardAdapter.m_Cfg->m_Render.differentiate_plated_copper )
663 {
664 createItemsFromContainer( m_boardAdapter.GetPlatedPadsFront(), F_Cu, &m_materials.m_Copper,
665 m_boardAdapter.m_CopperColor,
666 m_boardAdapter.GetFrontCopperThickness() * 0.1f );
667
668 createItemsFromContainer( m_boardAdapter.GetPlatedPadsBack(), B_Cu, &m_materials.m_Copper,
669 m_boardAdapter.m_CopperColor,
670 -m_boardAdapter.GetBackCopperThickness() * 0.1f );
671 }
672
673 if( !aOnlyLoadCopperAndShapes )
674 {
675 // Add Mask layer
676 // Solder mask layers are "negative" layers so the elements that we have in the container
677 // should remove the board outline. We will check for all objects in the outline if it
678 // intersects any object in the layer container and also any hole.
679 if( ( layerFlags.test( LAYER_3D_SOLDERMASK_TOP )
680 || layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
681 && !m_outlineBoard2dObjects->GetList().empty() )
682 {
683 const MATERIAL* materialLayer = &m_materials.m_SolderMask;
684
685 for( const std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& entry :
686 m_boardAdapter.GetLayerMap() )
687 {
688 const PCB_LAYER_ID layer_id = entry.first;
689 const BVH_CONTAINER_2D* container2d = entry.second;
690
691 // Only process layers that exist
692 if( !container2d )
693 continue;
694
695 // Only get the Solder mask layers (and only if the board has them)
696 if( layer_id == F_Mask && !layerFlags.test( LAYER_3D_SOLDERMASK_TOP ) )
697 continue;
698
699 if( layer_id == B_Mask && !layerFlags.test( LAYER_3D_SOLDERMASK_BOTTOM ) )
700 continue;
701
702 // Only Mask layers are processed here because they are negative layers
703 if( layer_id != F_Mask && layer_id != B_Mask )
704 continue;
705
706 SFVEC3F layerColor;
707
708 if( layer_id == B_Mask )
709 layerColor = m_boardAdapter.m_SolderMaskColorBot;
710 else
711 layerColor = m_boardAdapter.m_SolderMaskColorTop;
712
713 const float zLayerMin = m_boardAdapter.GetLayerBottomZPos( layer_id );
714 const float zLayerMax = m_boardAdapter.GetLayerTopZPos( layer_id );
715
716 // Get the outline board objects
717 for( const OBJECT_2D* object2d_A : m_outlineBoard2dObjects->GetList() )
718 {
719 std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
720
721 // Check if there are any THT that intersects this outline object part
722 if( !m_boardAdapter.GetTH_ODs().GetList().empty() )
723 {
724 const BVH_CONTAINER_2D& throughHoles = m_boardAdapter.GetTH_ODs();
725 CONST_LIST_OBJECT2D intersecting;
726
727 throughHoles.GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
728
729 for( const OBJECT_2D* hole : intersecting )
730 {
731 if( object2d_A->Intersects( hole->GetBBox() ) )
732 object2d_B->push_back( hole );
733 }
734 }
735
736 // Check if there are any objects in the layer to subtract with the current
737 // object
738 if( !container2d->GetList().empty() )
739 {
740 CONST_LIST_OBJECT2D intersecting;
741
742 container2d->GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
743
744 for( const OBJECT_2D* obj : intersecting )
745 object2d_B->push_back( obj );
746 }
747
748 if( object2d_B->empty() )
749 {
750 delete object2d_B;
751 object2d_B = CSGITEM_EMPTY;
752 }
753
754 if( object2d_B == CSGITEM_EMPTY )
755 {
756#if 0
757 createObject( m_objectContainer, object2d_A, zLayerMin, zLayerMax,
758 materialLayer, layerColor );
759#else
760 LAYER_ITEM* objPtr = new LAYER_ITEM( object2d_A, zLayerMin, zLayerMax );
761
762 objPtr->SetMaterial( materialLayer );
763 objPtr->SetColor( ConvertSRGBToLinear( layerColor ) );
764
765 m_objectContainer.Add( objPtr );
766#endif
767 }
768 else
769 {
770 LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( object2d_A, object2d_B,
772 object2d_A->GetBoardItem() );
773
774 m_containerWithObjectsToDelete.Add( itemCSG2d );
775
776 LAYER_ITEM* objPtr = new LAYER_ITEM( itemCSG2d, zLayerMin, zLayerMax );
777 objPtr->SetMaterial( materialLayer );
778 objPtr->SetColor( ConvertSRGBToLinear( layerColor ) );
779
780 m_objectContainer.Add( objPtr );
781 }
782 }
783 }
784 }
785
787 }
788
789#ifdef PRINT_STATISTICS_3D_VIEWER
790 int64_t stats_endConvertTime = GetRunningMicroSecs();
791 int64_t stats_startLoad3DmodelsTime = stats_endConvertTime;
792#endif
793
794 if( aStatusReporter )
795 aStatusReporter->Report( _( "Loading 3D models..." ) );
796
797 load3DModels( m_objectContainer, aOnlyLoadCopperAndShapes );
798
799#ifdef PRINT_STATISTICS_3D_VIEWER
800 int64_t stats_endLoad3DmodelsTime = GetRunningMicroSecs();
801#endif
802
803 if( !aOnlyLoadCopperAndShapes )
804 {
805 // Add floor
806 if( m_boardAdapter.m_Cfg->m_Render.raytrace_backfloor )
807 {
808 BBOX_3D boardBBox = m_boardAdapter.GetBBox();
809
810 if( boardBBox.IsInitialized() )
811 {
812 boardBBox.Scale( 3.0f );
813
814 if( m_objectContainer.GetList().size() > 0 )
815 {
816 BBOX_3D containerBBox = m_objectContainer.GetBBox();
817
818 containerBBox.Scale( 1.3f );
819
820 const SFVEC3F centerBBox = containerBBox.GetCenter();
821
822 // Floor triangles
823 const float minZ = glm::min( containerBBox.Min().z, boardBBox.Min().z );
824
825 const SFVEC3F v1 =
826 SFVEC3F( -RANGE_SCALE_3D * 4.0f, -RANGE_SCALE_3D * 4.0f, minZ )
827 + SFVEC3F( centerBBox.x, centerBBox.y, 0.0f );
828
829 const SFVEC3F v3 =
830 SFVEC3F( +RANGE_SCALE_3D * 4.0f, +RANGE_SCALE_3D * 4.0f, minZ )
831 + SFVEC3F( centerBBox.x, centerBBox.y, 0.0f );
832
833 const SFVEC3F v2 = SFVEC3F( v1.x, v3.y, v1.z );
834 const SFVEC3F v4 = SFVEC3F( v3.x, v1.y, v1.z );
835
836 SFVEC3F floorColor = ConvertSRGBToLinear( m_boardAdapter.m_BgColorTop );
837
838 TRIANGLE* newTriangle1 = new TRIANGLE( v1, v2, v3 );
839 TRIANGLE* newTriangle2 = new TRIANGLE( v3, v4, v1 );
840
841 m_objectContainer.Add( newTriangle1 );
842 m_objectContainer.Add( newTriangle2 );
843
844 newTriangle1->SetMaterial( &m_materials.m_Floor );
845 newTriangle2->SetMaterial( &m_materials.m_Floor );
846
847 newTriangle1->SetColor( floorColor );
848 newTriangle2->SetColor( floorColor );
849
850 // Ceiling triangles
851 const float maxZ = glm::max( containerBBox.Max().z, boardBBox.Max().z );
852
853 const SFVEC3F v5 = SFVEC3F( v1.x, v1.y, maxZ );
854 const SFVEC3F v6 = SFVEC3F( v2.x, v2.y, maxZ );
855 const SFVEC3F v7 = SFVEC3F( v3.x, v3.y, maxZ );
856 const SFVEC3F v8 = SFVEC3F( v4.x, v4.y, maxZ );
857
858 TRIANGLE* newTriangle3 = new TRIANGLE( v7, v6, v5 );
859 TRIANGLE* newTriangle4 = new TRIANGLE( v5, v8, v7 );
860
861 m_objectContainer.Add( newTriangle3 );
862 m_objectContainer.Add( newTriangle4 );
863
864 newTriangle3->SetMaterial( &m_materials.m_Floor );
865 newTriangle4->SetMaterial( &m_materials.m_Floor );
866
867 newTriangle3->SetColor( floorColor );
868 newTriangle4->SetColor( floorColor );
869 }
870 }
871 }
872
873 // Init initial lights
874 for( LIGHT* light : m_lights )
875 delete light;
876
877 m_lights.clear();
878
879 auto IsColorZero =
880 []( const SFVEC3F& aSource )
881 {
882 return ( ( aSource.r < ( 1.0f / 255.0f ) ) && ( aSource.g < ( 1.0f / 255.0f ) )
883 && ( aSource.b < ( 1.0f / 255.0f ) ) );
884 };
885
886 SFVEC3F cameraLightColor =
887 m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.raytrace_lightColorCamera );
888 SFVEC3F topLightColor =
889 m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.raytrace_lightColorTop );
890 SFVEC3F bottomLightColor =
891 m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.raytrace_lightColorBottom );
892
893 m_cameraLight = new DIRECTIONAL_LIGHT( SFVEC3F( 0.0f, 0.0f, 0.0f ), cameraLightColor );
894 m_cameraLight->SetCastShadows( false );
895
896 if( !IsColorZero( cameraLightColor ) )
897 m_lights.push_back( m_cameraLight );
898
899 const SFVEC3F& boardCenter = m_boardAdapter.GetBBox().GetCenter();
900
901 if( !IsColorZero( topLightColor ) )
902 {
903 m_lights.push_back( new POINT_LIGHT( SFVEC3F( boardCenter.x, boardCenter.y,
904 +RANGE_SCALE_3D * 2.0f ),
905 topLightColor ) );
906 }
907
908 if( !IsColorZero( bottomLightColor ) )
909 {
910 m_lights.push_back( new POINT_LIGHT( SFVEC3F( boardCenter.x, boardCenter.y,
911 -RANGE_SCALE_3D * 2.0f ),
912 bottomLightColor ) );
913 }
914
915 for( size_t i = 0; i < m_boardAdapter.m_Cfg->m_Render.raytrace_lightColor.size(); ++i )
916 {
917 SFVEC3F lightColor =
918 m_boardAdapter.GetColor( m_boardAdapter.m_Cfg->m_Render.raytrace_lightColor[i] );
919
920 if( !IsColorZero( lightColor ) )
921 {
922 const SFVEC2F sc = m_boardAdapter.GetSphericalCoord( i );
923
924 m_lights.push_back( new DIRECTIONAL_LIGHT(
925 SphericalToCartesian( glm::pi<float>() * sc.x, glm::pi<float>() * sc.y ),
926 lightColor ) );
927 }
928 }
929 }
930
931 // Set min. and max. zoom range. This doesn't really fit here, but moving this outside of this
932 // class would require reimplementing bounding box calculation (feel free to do this if you
933 // have time and patience).
934 if( m_objectContainer.GetList().size() > 0 )
935 {
936 float ratio =
937 std::max( 1.0f, m_objectContainer.GetBBox().GetMaxDimension() / RANGE_SCALE_3D );
938
939 float max_zoom = CAMERA::DEFAULT_MAX_ZOOM * ratio;
940 float min_zoom = static_cast<float>( MIN_DISTANCE_IU * m_boardAdapter.BiuTo3dUnits()
941 / -m_camera.GetCameraInitPos().z );
942
943 if( min_zoom > max_zoom )
944 std::swap( min_zoom, max_zoom );
945
946 float zoom_ratio = max_zoom / min_zoom;
947
948 // Set the minimum number of zoom 'steps' between max and min.
949 int steps = 3 * 3;
950 steps -= static_cast<int>( ceil( log( zoom_ratio ) / log( 1.26f ) ) );
951 steps = std::max( steps, 0 );
952
953 // Resize max and min zoom to accomplish the number of steps.
954 float increased_zoom = pow( 1.26f, steps / 2 );
955 max_zoom *= increased_zoom;
956 min_zoom /= increased_zoom;
957
958 if( steps & 1 )
959 min_zoom /= 1.26f;
960
961 min_zoom = std::min( min_zoom, 1.0f );
962
963 m_camera.SetMaxZoom( max_zoom );
964 m_camera.SetMinZoom( min_zoom );
965 }
966
967 // Create an accelerator
968 delete m_accelerator;
970
971 if( aStatusReporter )
972 {
973 // Calculation time in seconds
974 double calculation_time = (double) ( GetRunningMicroSecs() - stats_startReloadTime ) / 1e6;
975
976 aStatusReporter->Report( wxString::Format( _( "Reload time %.3f s" ), calculation_time ) );
977 }
978}
979
980
982{
983 PCB_LAYER_ID top_layer, bottom_layer;
984 int radiusBUI = ( aVia->GetDrillValue() / 2 );
985
986 aVia->LayerPair( &top_layer, &bottom_layer );
987
988 float topZ = m_boardAdapter.GetLayerBottomZPos( top_layer )
989 + m_boardAdapter.GetFrontCopperThickness();
990
991 float botZ = m_boardAdapter.GetLayerBottomZPos( bottom_layer )
992 - m_boardAdapter.GetBackCopperThickness();
993
994 const SFVEC2F center = SFVEC2F( aVia->GetStart().x * m_boardAdapter.BiuTo3dUnits(),
995 -aVia->GetStart().y * m_boardAdapter.BiuTo3dUnits() );
996
997 RING_2D* ring = new RING_2D( center, radiusBUI * m_boardAdapter.BiuTo3dUnits(),
998 ( radiusBUI + m_boardAdapter.GetHolePlatingThickness() )
999 * m_boardAdapter.BiuTo3dUnits(), *aVia );
1000
1002
1003 LAYER_ITEM* objPtr = new LAYER_ITEM( ring, topZ, botZ );
1004
1005 objPtr->SetMaterial( &m_materials.m_Copper );
1006 objPtr->SetColor( ConvertSRGBToLinear( m_boardAdapter.m_CopperColor ) );
1007
1008 m_objectContainer.Add( objPtr );
1009}
1010
1011
1013{
1014 const OBJECT_2D* object2d_A = nullptr;
1015
1016 SFVEC3F objColor = m_boardAdapter.m_CopperColor;
1017 const VECTOR2I drillsize = aPad->GetDrillSize();
1018 const bool hasHole = drillsize.x && drillsize.y;
1019
1020 if( !hasHole )
1021 return;
1022
1023 CONST_LIST_OBJECT2D antiOutlineIntersectionList;
1024
1025 const float topZ = m_boardAdapter.GetLayerBottomZPos( F_Cu )
1026 + m_boardAdapter.GetFrontCopperThickness() * 0.99f;
1027
1028 const float botZ = m_boardAdapter.GetLayerBottomZPos( B_Cu )
1029 - m_boardAdapter.GetBackCopperThickness() * 0.99f;
1030
1031 if( drillsize.x == drillsize.y ) // usual round hole
1032 {
1033 SFVEC2F center = SFVEC2F( aPad->GetPosition().x * m_boardAdapter.BiuTo3dUnits(),
1034 -aPad->GetPosition().y * m_boardAdapter.BiuTo3dUnits() );
1035
1036 int innerRadius = drillsize.x / 2;
1037 int outerRadius = innerRadius + m_boardAdapter.GetHolePlatingThickness();
1038
1039 RING_2D* ring = new RING_2D( center, innerRadius * m_boardAdapter.BiuTo3dUnits(),
1040 outerRadius * m_boardAdapter.BiuTo3dUnits(), *aPad );
1041
1043
1044 object2d_A = ring;
1045
1046 // If the object (ring) is intersected by an antioutline board,
1047 // it will use instead a CSG of two circles.
1048 if( object2d_A && !m_antioutlineBoard2dObjects->GetList().empty() )
1049 {
1050 m_antioutlineBoard2dObjects->GetIntersectingObjects( object2d_A->GetBBox(),
1051 antiOutlineIntersectionList );
1052 }
1053
1054 if( !antiOutlineIntersectionList.empty() )
1055 {
1056 FILLED_CIRCLE_2D* innerCircle = new FILLED_CIRCLE_2D(
1057 center, innerRadius * m_boardAdapter.BiuTo3dUnits(), *aPad );
1058
1059 FILLED_CIRCLE_2D* outterCircle = new FILLED_CIRCLE_2D(
1060 center, outerRadius * m_boardAdapter.BiuTo3dUnits(), *aPad );
1061 std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
1062 object2d_B->push_back( innerCircle );
1063
1064 LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( outterCircle, object2d_B, CSGITEM_FULL,
1065 *aPad );
1066
1067 m_containerWithObjectsToDelete.Add( itemCSG2d );
1068 m_containerWithObjectsToDelete.Add( innerCircle );
1069 m_containerWithObjectsToDelete.Add( outterCircle );
1070
1071 object2d_A = itemCSG2d;
1072 }
1073 }
1074 else // Oblong hole
1075 {
1076 VECTOR2I ends_offset;
1077 int width;
1078
1079 if( drillsize.x > drillsize.y ) // Horizontal oval
1080 {
1081 ends_offset.x = ( drillsize.x - drillsize.y ) / 2;
1082 width = drillsize.y;
1083 }
1084 else // Vertical oval
1085 {
1086 ends_offset.y = ( drillsize.y - drillsize.x ) / 2;
1087 width = drillsize.x;
1088 }
1089
1090 RotatePoint( ends_offset, aPad->GetOrientation() );
1091
1092 VECTOR2I start = VECTOR2I( aPad->GetPosition() ) + ends_offset;
1093 VECTOR2I end = VECTOR2I( aPad->GetPosition() ) - ends_offset;
1094
1095 ROUND_SEGMENT_2D* innerSeg =
1096 new ROUND_SEGMENT_2D( SFVEC2F( start.x * m_boardAdapter.BiuTo3dUnits(),
1097 -start.y * m_boardAdapter.BiuTo3dUnits() ),
1098 SFVEC2F( end.x * m_boardAdapter.BiuTo3dUnits(),
1099 -end.y * m_boardAdapter.BiuTo3dUnits() ),
1100 width * m_boardAdapter.BiuTo3dUnits(), *aPad );
1101
1102 ROUND_SEGMENT_2D* outerSeg =
1103 new ROUND_SEGMENT_2D( SFVEC2F( start.x * m_boardAdapter.BiuTo3dUnits(),
1104 -start.y * m_boardAdapter.BiuTo3dUnits() ),
1105 SFVEC2F( end.x * m_boardAdapter.BiuTo3dUnits(),
1106 -end.y * m_boardAdapter.BiuTo3dUnits() ),
1107 ( width + m_boardAdapter.GetHolePlatingThickness() * 2 )
1108 * m_boardAdapter.BiuTo3dUnits(), *aPad );
1109
1110 // NOTE: the round segment width is the "diameter", so we double the thickness
1111 std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
1112 object2d_B->push_back( innerSeg );
1113
1114 LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( outerSeg, object2d_B, CSGITEM_FULL, *aPad );
1115
1116 m_containerWithObjectsToDelete.Add( itemCSG2d );
1117 m_containerWithObjectsToDelete.Add( innerSeg );
1118 m_containerWithObjectsToDelete.Add( outerSeg );
1119
1120 object2d_A = itemCSG2d;
1121
1122 if( object2d_A && !m_antioutlineBoard2dObjects->GetList().empty() )
1123 {
1124 m_antioutlineBoard2dObjects->GetIntersectingObjects( object2d_A->GetBBox(),
1125 antiOutlineIntersectionList );
1126 }
1127 }
1128
1129 if( object2d_A )
1130 {
1131 std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
1132
1133 // Check if there are any other THT that intersects this hole
1134 // It will use the non inflated holes
1135 if( !m_boardAdapter.GetTH_IDs().GetList().empty() )
1136 {
1137 CONST_LIST_OBJECT2D intersecting;
1138
1139 m_boardAdapter.GetTH_IDs().GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
1140
1141 for( const OBJECT_2D* hole2d : intersecting )
1142 {
1143 if( object2d_A->Intersects( hole2d->GetBBox() ) )
1144 object2d_B->push_back( hole2d );
1145 }
1146 }
1147
1148 for( const OBJECT_2D* obj : antiOutlineIntersectionList )
1149 object2d_B->push_back( obj );
1150
1151 if( object2d_B->empty() )
1152 {
1153 delete object2d_B;
1154 object2d_B = CSGITEM_EMPTY;
1155 }
1156
1157 if( object2d_B == CSGITEM_EMPTY )
1158 {
1159 LAYER_ITEM* objPtr = new LAYER_ITEM( object2d_A, topZ, botZ );
1160
1161 objPtr->SetMaterial( &m_materials.m_Copper );
1162 objPtr->SetColor( ConvertSRGBToLinear( objColor ) );
1163 m_objectContainer.Add( objPtr );
1164 }
1165 else
1166 {
1167 LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( object2d_A, object2d_B, CSGITEM_FULL,
1168 *aPad );
1169
1170 m_containerWithObjectsToDelete.Add( itemCSG2d );
1171
1172 LAYER_ITEM* objPtr = new LAYER_ITEM( itemCSG2d, topZ, botZ );
1173
1174 objPtr->SetMaterial( &m_materials.m_Copper );
1175 objPtr->SetColor( ConvertSRGBToLinear( objColor ) );
1176
1177 m_objectContainer.Add( objPtr );
1178 }
1179 }
1180}
1181
1182
1184{
1185 if( !m_boardAdapter.GetBoard() )
1186 return;
1187
1188 // Insert plated vertical holes inside the board
1189
1190 // Insert vias holes (vertical cylinders)
1191 for( PCB_TRACK* track : m_boardAdapter.GetBoard()->Tracks() )
1192 {
1193 if( track->Type() == PCB_VIA_T )
1194 {
1195 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
1196 insertHole( via );
1197 }
1198 }
1199
1200 // Insert pads holes (vertical cylinders)
1201 for( FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
1202 {
1203 for( PAD* pad : footprint->Pads() )
1204 {
1205 if( pad->GetAttribute() != PAD_ATTRIB::NPTH )
1206 insertHole( pad );
1207 }
1208 }
1209}
1210
1211
1213 bool aSkipMaterialInformation )
1214{
1215 if( !m_boardAdapter.GetBoard() )
1216 return;
1217
1218 if( !m_boardAdapter.m_IsPreviewer
1219 && !m_boardAdapter.m_Cfg->m_Render.show_footprints_normal
1220 && !m_boardAdapter.m_Cfg->m_Render.show_footprints_insert
1221 && !m_boardAdapter.m_Cfg->m_Render.show_footprints_virtual )
1222 {
1223 return;
1224 }
1225
1226 // Go for all footprints
1227 for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() )
1228 {
1229 if( !fp->Models().empty()
1230 && m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
1231 {
1232 double zpos = m_boardAdapter.GetFootprintZPos( fp->IsFlipped() );
1233
1234 VECTOR2I pos = fp->GetPosition();
1235
1236 glm::mat4 fpMatrix = glm::mat4( 1.0f );
1237
1238 fpMatrix = glm::translate( fpMatrix,
1239 SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
1240 -pos.y * m_boardAdapter.BiuTo3dUnits(),
1241 zpos ) );
1242
1243 if( !fp->GetOrientation().IsZero() )
1244 {
1245 fpMatrix = glm::rotate( fpMatrix, (float) fp->GetOrientation().AsRadians(),
1246 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1247 }
1248
1249 if( fp->IsFlipped() )
1250 {
1251 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
1252
1253 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1254 }
1255
1256 const double modelunit_to_3d_units_factor =
1257 m_boardAdapter.BiuTo3dUnits() * UNITS3D_TO_UNITSPCB;
1258
1259 fpMatrix = glm::scale(
1260 fpMatrix, SFVEC3F( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
1261 modelunit_to_3d_units_factor ) );
1262
1263 // Get the list of model files for this model
1264 S3D_CACHE* cacheMgr = m_boardAdapter.Get3dCacheManager();
1265
1266 wxString libraryName = fp->GetFPID().GetLibNickname();
1267
1268 wxString footprintBasePath = wxEmptyString;
1269
1270 if( m_boardAdapter.GetBoard()->GetProject() )
1271 {
1272 try
1273 {
1274 // FindRow() can throw an exception
1275 const FP_LIB_TABLE_ROW* fpRow =
1276 PROJECT_PCB::PcbFootprintLibs( m_boardAdapter.GetBoard()->GetProject() )
1277 ->FindRow( libraryName, false );
1278
1279 if( fpRow )
1280 footprintBasePath = fpRow->GetFullURI( true );
1281 }
1282 catch( ... )
1283 {
1284 // Do nothing if the libraryName is not found in lib table
1285 }
1286 }
1287
1288 for( FP_3DMODEL& model : fp->Models() )
1289 {
1290 if( !model.m_Show || model.m_Filename.empty() )
1291 continue;
1292
1293 // get it from cache
1294 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
1295 embeddedFilesStack.push_back( fp->GetEmbeddedFiles() );
1296 embeddedFilesStack.push_back( m_boardAdapter.GetBoard()->GetEmbeddedFiles() );
1297
1298 const S3DMODEL* modelPtr = cacheMgr->GetModel( model.m_Filename, footprintBasePath,
1299 std::move( embeddedFilesStack ) );
1300
1301 // only add it if the return is not NULL.
1302 if( modelPtr )
1303 {
1304 glm::mat4 modelMatrix = fpMatrix;
1305
1306 modelMatrix = glm::translate( modelMatrix,
1307 SFVEC3F( model.m_Offset.x, model.m_Offset.y, model.m_Offset.z ) );
1308
1309 modelMatrix = glm::rotate( modelMatrix,
1310 (float) -( model.m_Rotation.z / 180.0f ) * glm::pi<float>(),
1311 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1312
1313 modelMatrix = glm::rotate( modelMatrix,
1314 (float) -( model.m_Rotation.y / 180.0f ) * glm::pi<float>(),
1315 SFVEC3F( 0.0f, 1.0f, 0.0f ) );
1316
1317 modelMatrix = glm::rotate( modelMatrix,
1318 (float) -( model.m_Rotation.x / 180.0f ) * glm::pi<float>(),
1319 SFVEC3F( 1.0f, 0.0f, 0.0f ) );
1320
1321 modelMatrix = glm::scale( modelMatrix,
1322 SFVEC3F( model.m_Scale.x, model.m_Scale.y, model.m_Scale.z ) );
1323
1324 addModels( aDstContainer, modelPtr, modelMatrix, (float) model.m_Opacity,
1325 aSkipMaterialInformation, fp );
1326 }
1327 }
1328 }
1329 }
1330}
1331
1332
1334{
1335 MODEL_MATERIALS* materialVector;
1336
1337 // Try find if the materials already exists in the map list
1338 if( m_modelMaterialMap.find( a3DModel ) != m_modelMaterialMap.end() )
1339 {
1340 // Found it, so get the pointer
1341 materialVector = &m_modelMaterialMap[a3DModel];
1342 }
1343 else
1344 {
1345 // Materials was not found in the map, so it will create a new for
1346 // this model.
1347
1348 m_modelMaterialMap[a3DModel] = MODEL_MATERIALS();
1349 materialVector = &m_modelMaterialMap[a3DModel];
1350
1351 materialVector->resize( a3DModel->m_MaterialsSize );
1352
1353 for( unsigned int imat = 0; imat < a3DModel->m_MaterialsSize; ++imat )
1354 {
1355 if( m_boardAdapter.m_Cfg->m_Render.material_mode == MATERIAL_MODE::NORMAL )
1356 {
1357 const SMATERIAL& material = a3DModel->m_Materials[imat];
1358
1359 // http://www.fooplot.com/#W3sidHlwZSI6MCwiZXEiOiJtaW4oc3FydCh4LTAuMzUpKjAuNDAtMC4wNSwxLjApIiwiY29sb3IiOiIjMDAwMDAwIn0seyJ0eXBlIjoxMDAwLCJ3aW5kb3ciOlsiMC4wNzA3NzM2NzMyMzY1OTAxMiIsIjEuNTY5NTcxNjI5MjI1NDY5OCIsIi0wLjI3NDYzNTMyMTc1OTkyOTMiLCIwLjY0NzcwMTg4MTkyNTUzNjIiXSwic2l6ZSI6WzY0NCwzOTRdfV0-
1360
1361 float reflectionFactor = 0.0f;
1362
1363 if( ( material.m_Shininess - 0.35f ) > FLT_EPSILON )
1364 {
1365 reflectionFactor = glm::clamp(
1366 glm::sqrt( ( material.m_Shininess - 0.35f ) ) * 0.40f - 0.05f, 0.0f,
1367 0.5f );
1368 }
1369
1370 BLINN_PHONG_MATERIAL& blinnMaterial = ( *materialVector )[imat];
1371
1372 blinnMaterial = BLINN_PHONG_MATERIAL( ConvertSRGBToLinear( material.m_Ambient ),
1373 ConvertSRGBToLinear( material.m_Emissive ),
1374 ConvertSRGBToLinear( material.m_Specular ), material.m_Shininess * 180.0f,
1375 material.m_Transparency, reflectionFactor );
1376
1377 if( m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
1378 {
1379 // Guess material type and apply a normal perturbator
1380 if( ( RGBtoGray( material.m_Diffuse ) < 0.3f )
1381 && ( material.m_Shininess < 0.36f )
1382 && ( material.m_Transparency == 0.0f )
1383 && ( ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.g ) < 0.15f )
1384 && ( glm::abs( material.m_Diffuse.b - material.m_Diffuse.g )
1385 < 0.15f )
1386 && ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.b )
1387 < 0.15f ) ) )
1388 {
1389 // This may be a black plastic..
1390 blinnMaterial.SetGenerator( &m_plasticMaterial );
1391 }
1392 else
1393 {
1394 if( ( RGBtoGray( material.m_Diffuse ) > 0.3f )
1395 && ( material.m_Shininess < 0.30f )
1396 && ( material.m_Transparency == 0.0f )
1397 && ( ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.g ) > 0.25f )
1398 || ( glm::abs( material.m_Diffuse.b - material.m_Diffuse.g ) > 0.25f )
1399 || ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.b )
1400 > 0.25f ) ) )
1401 {
1402 // This may be a color plastic ...
1403 blinnMaterial.SetGenerator( &m_shinyPlasticMaterial );
1404 }
1405 else
1406 {
1407 if( ( RGBtoGray( material.m_Diffuse ) > 0.6f )
1408 && ( material.m_Shininess > 0.35f )
1409 && ( material.m_Transparency == 0.0f )
1410 && ( ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.g )
1411 < 0.40f )
1412 && ( glm::abs( material.m_Diffuse.b - material.m_Diffuse.g )
1413 < 0.40f )
1414 && ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.b )
1415 < 0.40f ) ) )
1416 {
1417 // This may be a brushed metal
1418 blinnMaterial.SetGenerator( &m_brushedMetalMaterial );
1419 }
1420 }
1421 }
1422 }
1423 }
1424 else
1425 {
1426 ( *materialVector )[imat] = BLINN_PHONG_MATERIAL(
1427 SFVEC3F( 0.2f ), SFVEC3F( 0.0f ), SFVEC3F( 0.0f ), 0.0f, 0.0f, 0.0f );
1428 }
1429 }
1430 }
1431
1432 return materialVector;
1433}
1434
1435
1436void RENDER_3D_RAYTRACE_BASE::addModels( CONTAINER_3D& aDstContainer, const S3DMODEL* a3DModel,
1437 const glm::mat4& aModelMatrix, float aFPOpacity,
1438 bool aSkipMaterialInformation, BOARD_ITEM* aBoardItem )
1439{
1440 // Validate a3DModel pointers
1441 wxASSERT( a3DModel != nullptr );
1442
1443 if( a3DModel == nullptr )
1444 return;
1445
1446 wxASSERT( a3DModel->m_Materials != nullptr );
1447 wxASSERT( a3DModel->m_Meshes != nullptr );
1448 wxASSERT( a3DModel->m_MaterialsSize > 0 );
1449 wxASSERT( a3DModel->m_MeshesSize > 0 );
1450
1451 if( aFPOpacity > 1.0f )
1452 aFPOpacity = 1.0f;
1453
1454 if( aFPOpacity < 0.0f )
1455 aFPOpacity = 0.0f;
1456
1457 if( ( a3DModel->m_Materials != nullptr ) && ( a3DModel->m_Meshes != nullptr )
1458 && ( a3DModel->m_MaterialsSize > 0 ) && ( a3DModel->m_MeshesSize > 0 ) )
1459 {
1460 MODEL_MATERIALS* materialVector = nullptr;
1461
1462 if( !aSkipMaterialInformation )
1463 {
1464 materialVector = getModelMaterial( a3DModel );
1465 }
1466
1467 const glm::mat3 normalMatrix = glm::transpose( glm::inverse( glm::mat3( aModelMatrix ) ) );
1468
1469 for( unsigned int mesh_i = 0; mesh_i < a3DModel->m_MeshesSize; ++mesh_i )
1470 {
1471 const SMESH& mesh = a3DModel->m_Meshes[mesh_i];
1472
1473 // Validate the mesh pointers
1474 wxASSERT( mesh.m_Positions != nullptr );
1475 wxASSERT( mesh.m_FaceIdx != nullptr );
1476 wxASSERT( mesh.m_Normals != nullptr );
1477 wxASSERT( mesh.m_FaceIdxSize > 0 );
1478 wxASSERT( ( mesh.m_FaceIdxSize % 3 ) == 0 );
1479
1480
1481 if( ( mesh.m_Positions != nullptr ) && ( mesh.m_Normals != nullptr )
1482 && ( mesh.m_FaceIdx != nullptr ) && ( mesh.m_FaceIdxSize > 0 )
1483 && ( mesh.m_VertexSize > 0 ) && ( ( mesh.m_FaceIdxSize % 3 ) == 0 )
1484 && ( mesh.m_MaterialIdx < a3DModel->m_MaterialsSize ) )
1485 {
1486 float fpTransparency;
1487 const BLINN_PHONG_MATERIAL* blinn_material;
1488
1489 if( !aSkipMaterialInformation )
1490 {
1491 blinn_material = &( *materialVector )[mesh.m_MaterialIdx];
1492
1493 fpTransparency =
1494 1.0f - ( ( 1.0f - blinn_material->GetTransparency() ) * aFPOpacity );
1495 }
1496
1497 // Add all face triangles
1498 for( unsigned int faceIdx = 0; faceIdx < mesh.m_FaceIdxSize; faceIdx += 3 )
1499 {
1500 const unsigned int idx0 = mesh.m_FaceIdx[faceIdx + 0];
1501 const unsigned int idx1 = mesh.m_FaceIdx[faceIdx + 1];
1502 const unsigned int idx2 = mesh.m_FaceIdx[faceIdx + 2];
1503
1504 wxASSERT( idx0 < mesh.m_VertexSize );
1505 wxASSERT( idx1 < mesh.m_VertexSize );
1506 wxASSERT( idx2 < mesh.m_VertexSize );
1507
1508 if( ( idx0 < mesh.m_VertexSize ) && ( idx1 < mesh.m_VertexSize )
1509 && ( idx2 < mesh.m_VertexSize ) )
1510 {
1511 const SFVEC3F& v0 = mesh.m_Positions[idx0];
1512 const SFVEC3F& v1 = mesh.m_Positions[idx1];
1513 const SFVEC3F& v2 = mesh.m_Positions[idx2];
1514
1515 const SFVEC3F& n0 = mesh.m_Normals[idx0];
1516 const SFVEC3F& n1 = mesh.m_Normals[idx1];
1517 const SFVEC3F& n2 = mesh.m_Normals[idx2];
1518
1519 // Transform vertex with the model matrix
1520 const SFVEC3F vt0 = SFVEC3F( aModelMatrix * glm::vec4( v0, 1.0f ) );
1521 const SFVEC3F vt1 = SFVEC3F( aModelMatrix * glm::vec4( v1, 1.0f ) );
1522 const SFVEC3F vt2 = SFVEC3F( aModelMatrix * glm::vec4( v2, 1.0f ) );
1523
1524 const SFVEC3F nt0 = glm::normalize( SFVEC3F( normalMatrix * n0 ) );
1525 const SFVEC3F nt1 = glm::normalize( SFVEC3F( normalMatrix * n1 ) );
1526 const SFVEC3F nt2 = glm::normalize( SFVEC3F( normalMatrix * n2 ) );
1527
1528 TRIANGLE* newTriangle = new TRIANGLE( vt0, vt2, vt1, nt0, nt2, nt1 );
1529
1530 newTriangle->SetBoardItem( aBoardItem );
1531
1532 aDstContainer.Add( newTriangle );
1533
1534 if( !aSkipMaterialInformation )
1535 {
1536 newTriangle->SetMaterial( blinn_material );
1537 newTriangle->SetModelTransparency( fpTransparency );
1538
1539 if( mesh.m_Color == nullptr )
1540 {
1541 const SFVEC3F diffuseColor =
1542 a3DModel->m_Materials[mesh.m_MaterialIdx].m_Diffuse;
1543
1544 if( m_boardAdapter.m_Cfg->m_Render.material_mode == MATERIAL_MODE::CAD_MODE )
1545 newTriangle->SetColor( ConvertSRGBToLinear(
1546 MaterialDiffuseToColorCAD( diffuseColor ) ) );
1547 else
1548 newTriangle->SetColor( ConvertSRGBToLinear( diffuseColor ) );
1549 }
1550 else
1551 {
1552 if( m_boardAdapter.m_Cfg->m_Render.material_mode == MATERIAL_MODE::CAD_MODE )
1553 {
1554 newTriangle->SetColor(
1556 mesh.m_Color[idx0] ) ),
1558 mesh.m_Color[idx1] ) ),
1560 mesh.m_Color[idx2] ) ) );
1561 }
1562 else
1563 {
1564 newTriangle->SetColor(
1565 ConvertSRGBToLinear( mesh.m_Color[idx0] ),
1566 ConvertSRGBToLinear( mesh.m_Color[idx1] ),
1567 ConvertSRGBToLinear( mesh.m_Color[idx2] ) );
1568 }
1569 }
1570 }
1571 }
1572 }
1573 }
1574 }
1575 }
1576}
@ NORMAL
Use all material properties from model file.
Definition 3d_enums.h:72
@ CAD_MODE
Use a gray shading based on diffuse material.
Definition 3d_enums.h:74
Defines math related functions.
float NextFloatDown(float v)
float NextFloatUp(float v)
Defines math related functions.
float RGBtoGray(const SFVEC3F &aColor)
Definition 3d_math.h:140
SFVEC3F MaterialDiffuseToColorCAD(const SFVEC3F &aDiffuseColor)
Definition 3d_math.h:147
SFVEC3F SphericalToCartesian(float aInclination, float aAzimuth)
https://en.wikipedia.org/wiki/Spherical_coordinate_system
Definition 3d_math.h:43
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
std::map< PCB_LAYER_ID, BVH_CONTAINER_2D * > MAP_CONTAINER_2D_BASE
A type that stores a container of 2d objects for each layer id.
#define RANGE_SCALE_3D
This defines the range that all coord will have to be rendered.
This BVH implementation is based on the source code implementation from the book "Physically Based Re...
Blinn Phong based material https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model.
Definition material.h:379
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:79
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:317
Procedural generation of the shiny brushed metal.
Definition material.h:195
void GetIntersectingObjects(const BBOX_2D &aBBox, CONST_LIST_OBJECT2D &aOutList) const override
Get a list of objects that intersects a bounding box.
static const float DEFAULT_MAX_ZOOM
Definition camera.h:106
const LIST_OBJECT2D & GetList() const
void Add(OBJECT_3D *aObject)
Procedural generation of the copper normals.
Definition material.h:76
A vertical cylinder.
Definition cylinder_3d.h:38
void SetColor(SFVEC3F aObjColor)
Definition cylinder_3d.h:48
A light source based only on a directional vector.
Definition light.h:116
Hold a record identifying a library accessed by the appropriate footprint library #PLUGIN object in t...
const FP_LIB_TABLE_ROW * FindRow(const wxString &aNickName, bool aCheckIfEnabled=false)
Return an FP_LIB_TABLE_ROW if aNickName is found in this table or in any chained fall back table frag...
Make solid geometry for objects on layers.
void SetColor(SFVEC3F aObjColor)
const wxString GetFullURI(bool aSubstituted=false) const
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
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
static void SetDefaultReflectionRayCount(unsigned int aCount)
Definition material.h:247
static void SetDefaultRefractionRayCount(unsigned int aCount)
Definition material.h:242
static void SetDefaultRefractionRecursionCount(unsigned int aCount)
Definition material.h:252
void SetGenerator(const MATERIAL_GENERATOR *aGenerator)
Definition material.h:328
float GetTransparency() const
Definition material.h:273
static void SetDefaultReflectionRecursionCount(unsigned int aCount)
Definition material.h:257
static OBJECT_2D_STATS & Instance()
Definition object_2d.h:137
void ResetStats()
Definition object_2d.h:122
virtual bool Intersects(const BBOX_2D &aBBox) const =0
a.Intersects(b) ⇔ !a.Disjoint(b) ⇔ !(a ∩ b = ∅)
const BBOX_2D & GetBBox() const
Definition object_2d.h:103
const BOARD_ITEM & GetBoardItem() const
Definition object_2d.h:66
OBJECT_2D_TYPE GetObjectType() const
Definition object_2d.h:107
static OBJECT_3D_STATS & Instance()
Definition object_3d.h:132
void ResetStats()
Definition object_3d.h:115
void SetMaterial(const MATERIAL *aMaterial)
Definition object_3d.h:58
void SetModelTransparency(float aModelTransparency)
Definition object_3d.h:66
void SetBoardItem(BOARD_ITEM *aBoardItem)
Definition object_3d.h:55
Definition pad.h:54
const VECTOR2I & GetDrillSize() const
Definition pad.h:305
VECTOR2I GetPosition() const override
Definition pad.h:208
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.h:408
const VECTOR2I & GetStart() const
Definition pcb_track.h:152
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Return the 2 layers used by the via (the via actually uses all layers between these 2 layers)
Procedural generation of the plastic normals.
Definition material.h:146
Procedural generation of the shiny plastic normals.
Definition material.h:170
Point light source based on http://ogldev.atspace.co.uk/www/tutorial20/tutorial20....
Definition light.h:71
static FP_LIB_TABLE * PcbFootprintLibs(PROJECT *aProject)
Return the table of footprint libraries without Kiway.
BOARD_ADAPTER & m_boardAdapter
Settings reference in use for this render.
SILK_SCREEN_NORMAL m_silkScreenMaterial
struct RENDER_3D_RAYTRACE_BASE::@013206213056006125230376122042346155134272177300 m_materials
void Reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter, bool aOnlyLoadCopperAndShapes)
void load3DModels(CONTAINER_3D &aDstContainer, bool aSkipMaterialInformation)
void insertHole(const PCB_VIA *aVia)
BRUSHED_METAL_NORMAL m_brushedMetalMaterial
static constexpr float MIN_DISTANCE_IU
PLATED_COPPER_NORMAL m_platedCopperMaterial
void createItemsFromContainer(const BVH_CONTAINER_2D *aContainer2d, PCB_LAYER_ID aLayer_id, const MATERIAL *aMaterialLayer, const SFVEC3F &aLayerColor, float aLayerZOffset)
PLASTIC_SHINE_NORMAL m_shinyPlasticMaterial
BVH_CONTAINER_2D * m_antioutlineBoard2dObjects
CONTAINER_2D m_containerWithObjectsToDelete
Store the list of created objects special for RT that will be clear in the end.
MODEL_MATERIALS * getModelMaterial(const S3DMODEL *a3DModel)
SOLDER_MASK_NORMAL m_solderMaskMaterial
void addModels(CONTAINER_3D &aDstContainer, const S3DMODEL *a3DModel, const glm::mat4 &aModelMatrix, float aFPOpacity, bool aSkipMaterialInformation, BOARD_ITEM *aBoardItem)
MAP_MODEL_MATERIALS m_modelMaterialMap
Stores materials of the 3D models.
void createObject(CONTAINER_3D &aDstContainer, const OBJECT_2D *aObject2D, float aZMin, float aZMax, const MATERIAL *aMaterial, const SFVEC3F &aObjColor)
Create one or more 3D objects form a 2D object and Z positions.
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
void SetColor(SFVEC3F aObjColor)
Cache for storing the 3D shapes.
Definition 3d_cache.h:55
S3DMODEL * GetModel(const wxString &aModelFileName, const wxString &aBasePath, std::vector< const EMBEDDED_FILES * > aEmbeddedFilesStack)
Attempt to load the scene data for a model and to translate it into an S3D_MODEL structure for displa...
Definition 3d_cache.cpp:551
Represent a set of closed polygons.
void Fracture()
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
int OutlineCount() const
Return the number of outlines in the set.
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
Procedural generation of the solder mask.
Definition material.h:126
A triangle object.
Definition triangle_3d.h:43
void SetColor(const SFVEC3F &aColor)
A plane that is parallel to XY plane.
Definition plane_3d.h:38
void SetColor(SFVEC3F aObjColor)
Definition plane_3d.h:49
std::list< OBJECT_2D * > LIST_OBJECT2D
std::list< const OBJECT_2D * > CONST_LIST_OBJECT2D
#define _(s)
#define UNITS3D_TO_UNITSPCB
Implements a model viewer canvas.
Declaration of the eda_3d_viewer class.
FOOTPRINT_ATTR_T
The set of attributes allowed within a FOOTPRINT, using FOOTPRINT::SetAttributes() and FOOTPRINT::Get...
Definition footprint.h:80
int MapPCBLayerTo3DLayer(PCB_LAYER_ID aLayer)
Definition layer_id.cpp:332
@ LAYER_3D_USER_1
Definition layer_ids.h:564
@ LAYER_3D_SOLDERMASK_TOP
Definition layer_ids.h:557
@ LAYER_3D_SOLDERMASK_BOTTOM
Definition layer_ids.h:556
@ LAYER_3D_BOARD
Definition layer_ids.h:551
@ LAYER_3D_USER_45
Definition layer_ids.h:608
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:674
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ F_CrtYd
Definition layer_ids.h:116
@ B_Adhes
Definition layer_ids.h:103
@ Dwgs_User
Definition layer_ids.h:107
@ F_Paste
Definition layer_ids.h:104
@ Cmts_User
Definition layer_ids.h:108
@ F_Adhes
Definition layer_ids.h:102
@ B_Mask
Definition layer_ids.h:98
@ B_Cu
Definition layer_ids.h:65
@ Eco1_User
Definition layer_ids.h:109
@ F_Mask
Definition layer_ids.h:97
@ B_Paste
Definition layer_ids.h:105
@ F_Fab
Definition layer_ids.h:119
@ F_SilkS
Definition layer_ids.h:100
@ B_CrtYd
Definition layer_ids.h:115
@ Eco2_User
Definition layer_ids.h:110
@ B_SilkS
Definition layer_ids.h:101
@ F_Cu
Definition layer_ids.h:64
@ B_Fab
Definition layer_ids.h:118
#define CSGITEM_EMPTY
#define CSGITEM_FULL
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:87
void ConvertPolygonToBlocks(const SHAPE_POLY_SET &aMainPath, CONTAINER_2D_BASE &aDstContainer, float aBiuTo3dUnitsScale, float aDivFactor, const BOARD_ITEM &aBoardItem, int aPolyIndex)
Use a polygon in the format of the ClipperLib::Path and process it and create multiple 2d objects (PO...
int64_t GetRunningMicroSecs()
An alternate way to calculate an elapsed time (in microsecondes) to class PROF_COUNTER.
void buildBoardBoundingBoxPoly(const BOARD *aBoard, SHAPE_POLY_SET &aOutline)
Get the complete bounding box of the board (including all items).
static float TransparencyControl(float aGrayColorValue, float aTransparency)
Perform an interpolation step to easy control the transparency based on the gray color value and tran...
SFVEC3F ConvertSRGBToLinear(const SFVEC3F &aSRGBcolor)
std::vector< BLINN_PHONG_MATERIAL > MODEL_MATERIALS
Vector of materials.
const SFVEC2F & Min() const
Definition bbox_2d.h:175
const SFVEC2F & Max() const
Definition bbox_2d.h:180
Manage a bounding box defined by two SFVEC3F min max points.
Definition bbox_3d.h:43
SFVEC3F GetCenter() const
Return the center point of the bounding box.
Definition bbox_3d.cpp:132
const SFVEC3F & Min() const
Return the minimum vertex pointer.
Definition bbox_3d.h:192
const SFVEC3F & Max() const
Return the maximum vertex pointer.
Definition bbox_3d.h:199
bool IsInitialized() const
Check if this bounding box is already initialized.
Definition bbox_3d.cpp:88
void Scale(float aScale)
Scales a bounding box by its center.
Definition bbox_3d.cpp:182
Store the a model based on meshes and materials.
Definition c3dmodel.h:95
SMATERIAL * m_Materials
The materials list of this model.
Definition c3dmodel.h:100
unsigned int m_MeshesSize
Number of meshes in the array.
Definition c3dmodel.h:96
SMESH * m_Meshes
The meshes list of this model.
Definition c3dmodel.h:97
unsigned int m_MaterialsSize
Number of materials in the material array.
Definition c3dmodel.h:99
float m_Shininess
Definition c3dmodel.h:43
SFVEC3F m_Specular
Definition c3dmodel.h:42
SFVEC3F m_Ambient
Definition c3dmodel.h:39
float m_Transparency
1.0 is completely transparent, 0.0 completely opaque
Definition c3dmodel.h:44
SFVEC3F m_Emissive
Definition c3dmodel.h:41
SFVEC3F m_Diffuse
Default diffuse color if m_Color is NULL.
Definition c3dmodel.h:40
Per-vertex normal/color/texcoors structure.
Definition c3dmodel.h:81
unsigned int * m_FaceIdx
Triangle Face Indexes.
Definition c3dmodel.h:88
SFVEC3F * m_Normals
Vertex normals array.
Definition c3dmodel.h:84
unsigned int m_MaterialIdx
Material Index to be used in this mesh (must be < m_MaterialsSize )
Definition c3dmodel.h:89
unsigned int m_VertexSize
Number of vertex in the arrays.
Definition c3dmodel.h:82
unsigned int m_FaceIdxSize
Number of elements of the m_FaceIdx array.
Definition c3dmodel.h:87
SFVEC3F * m_Color
Vertex color array, can be NULL.
Definition c3dmodel.h:86
SFVEC3F * m_Positions
Vertex position array.
Definition c3dmodel.h:83
VECTOR3I v1(5, 5, 5)
VECTOR2I center
int radius
VECTOR2I end
VECTOR2I v2(1, 0)
VECTOR2I v4(1, 1)
VECTOR2I v5(-70, -70)
VECTOR2I v3(-2, 1)
Implement a triangle ray intersection based on article http://www.flipcode.com/archives/Raytracing_To...
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
glm::vec2 SFVEC2F
Definition xv3d_types.h:42
glm::vec3 SFVEC3F
Definition xv3d_types.h:44