KiCad PCB EDA Suite
3d_render_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-2016 Mario Luzeiro <mrluzeiro@ua.pt>
5  * Copyright (C) 2015-2020 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 
30 #include "render_3d_raytrace.h"
31 #include "shapes3D/plane_3d.h"
33 #include "shapes3D/layer_item_3d.h"
34 #include "shapes3D/cylinder_3d.h"
35 #include "shapes3D/triangle_3d.h"
36 #include "shapes2D/layer_item_2d.h"
37 #include "shapes2D/ring_2d.h"
38 #include "shapes2D/polygon_2d.h"
41 #include "accelerators/bvh_pbrt.h"
42 #include "3d_fastmath.h"
43 #include "3d_math.h"
44 
45 #include <board.h>
46 #include <footprint.h>
47 
48 #include <base_units.h>
49 #include <profile.h> // To use GetRunningMicroSecs or another profiling utility
50 
59 static float TransparencyControl( float aGrayColorValue, float aTransparency )
60 {
61  const float aaa = aTransparency * aTransparency * aTransparency;
62 
63  // 1.00-1.05*(1.0-x)^3
64  float ca = 1.0f - aTransparency;
65  ca = 1.00f - 1.05f * ca * ca * ca;
66 
67  return glm::max( glm::min( aGrayColorValue * ca + aaa, 1.0f ), 0.0f );
68 }
69 
73 #define UNITS3D_TO_UNITSPCB ( IU_PER_MM )
74 
75 
77 {
80 
83 
84  double mmTo3Dunits = IU_PER_MM * m_boardAdapter.BiuTo3dUnits();
85 
87  {
88  m_boardMaterial = BOARD_NORMAL( 0.40f * mmTo3Dunits );
89 
90  m_copperMaterial = COPPER_NORMAL( 4.0f * mmTo3Dunits, &m_boardMaterial );
91 
92  m_platedCopperMaterial = PLATED_COPPER_NORMAL( 0.5f * mmTo3Dunits );
93 
95 
96  m_plasticMaterial = PLASTIC_NORMAL( 0.05f * mmTo3Dunits );
97 
98  m_shinyPlasticMaterial = PLASTIC_SHINE_NORMAL( 0.1f * mmTo3Dunits );
99 
100  m_brushedMetalMaterial = BRUSHED_METAL_NORMAL( 0.05f * mmTo3Dunits );
101 
102  m_silkScreenMaterial = SILK_SCREEN_NORMAL( 0.25f * mmTo3Dunits );
103  }
104 
105  // http://devernay.free.fr/cours/opengl/materials.html
106  // Copper
107  const SFVEC3F copperSpecularLinear =
108  ConvertSRGBToLinear( glm::clamp( (SFVEC3F) m_boardAdapter.m_CopperColor * 0.5f + 0.25f,
109  SFVEC3F( 0.0f ), SFVEC3F( 1.0f ) ) );
110 
113  SFVEC3F( 0.0f ), copperSpecularLinear, 0.4f * 128.0f, 0.0f, 0.0f );
114 
116  m_materials.m_Copper.SetGenerator( &m_platedCopperMaterial );
117 
118  m_materials.m_NonPlatedCopper = BLINN_PHONG_MATERIAL(
119  ConvertSRGBToLinear( SFVEC3F( 0.191f, 0.073f, 0.022f ) ), SFVEC3F( 0.0f, 0.0f, 0.0f ),
120  SFVEC3F( 0.256f, 0.137f, 0.086f ), 0.15f * 128.0f, 0.0f, 0.0f );
121 
123  m_materials.m_NonPlatedCopper.SetGenerator( &m_copperMaterial );
124 
128  SFVEC3F( 0.0f, 0.0f, 0.0f ),
132  0.10f * 128.0f, 0.0f, 0.0f );
133 
135  SFVEC3F( 0.0f, 0.0f, 0.0f ),
136  glm::clamp( ( ( SFVEC3F )( 1.0f ) - ConvertSRGBToLinear(
138  SFVEC3F( 0.0f ), SFVEC3F( 0.10f ) ), 0.078125f * 128.0f, 0.0f, 0.0f );
139 
141  m_materials.m_SilkS.SetGenerator( &m_silkScreenMaterial );
142 
143  // Assume that SolderMaskTop == SolderMaskBot
144  const float solderMask_gray =
147  / 3.0f;
148 
149  const float solderMask_transparency = TransparencyControl( solderMask_gray,
151 
152  m_materials.m_SolderMask = BLINN_PHONG_MATERIAL(
154  SFVEC3F( 0.0f, 0.0f, 0.0f ),
155  SFVEC3F( glm::clamp( solderMask_gray * 2.0f, 0.25f, 1.0f ) ), 0.85f * 128.0f,
156  solderMask_transparency, 0.16f );
157 
158  m_materials.m_SolderMask.SetCastShadows( true );
159  m_materials.m_SolderMask.SetRefractionRayCount( 1 );
160 
162  m_materials.m_SolderMask.SetGenerator( &m_solderMaskMaterial );
163 
164  m_materials.m_EpoxyBoard =
165  BLINN_PHONG_MATERIAL( ConvertSRGBToLinear( SFVEC3F( 16.0f / 255.0f, 14.0f / 255.0f,
166  10.0f / 255.0f ) ),
167  SFVEC3F( 0.0f, 0.0f, 0.0f ),
168  ConvertSRGBToLinear( SFVEC3F( 10.0f / 255.0f, 8.0f / 255.0f,
169  10.0f / 255.0f ) ),
170  0.1f * 128.0f, 1.0f - m_boardAdapter.m_BoardBodyColor.a, 0.0f );
171 
172  m_materials.m_EpoxyBoard.SetAbsorvance( 10.0f );
173 
175  m_materials.m_EpoxyBoard.SetGenerator( &m_boardMaterial );
176 
178 
179  m_materials.m_Floor = BLINN_PHONG_MATERIAL( bgTop * 0.125f, SFVEC3F( 0.0f, 0.0f, 0.0f ),
180  ( SFVEC3F( 1.0f ) - bgTop ) / 3.0f,
181  0.10f * 128.0f, 0.0f, 0.50f );
182  m_materials.m_Floor.SetCastShadows( false );
183  m_materials.m_Floor.SetReflectionRecursionCount( 1 );
184 }
185 
186 
187 void RENDER_3D_RAYTRACE::createObject( CONTAINER_3D& aDstContainer, const OBJECT_2D* aObject2D,
188  float aZMin, float aZMax, const MATERIAL* aMaterial,
189  const SFVEC3F& aObjColor )
190 {
191  switch( aObject2D->GetObjectType() )
192  {
194  {
196 
197  XY_PLANE* objPtr;
198  objPtr = new XY_PLANE( BBOX_3D(
199  SFVEC3F( aObject2D->GetBBox().Min().x, aObject2D->GetBBox().Min().y, aZMin ),
200  SFVEC3F( aObject2D->GetBBox().Max().x, aObject2D->GetBBox().Max().y, aZMin ) ) );
201  objPtr->SetMaterial( aMaterial );
202  objPtr->SetColor( ConvertSRGBToLinear( aObjColor ) );
203  aDstContainer.Add( objPtr );
204 
205  objPtr = new XY_PLANE( BBOX_3D(
206  SFVEC3F( aObject2D->GetBBox().Min().x, aObject2D->GetBBox().Min().y, aZMax ),
207  SFVEC3F( aObject2D->GetBBox().Max().x, aObject2D->GetBBox().Max().y, aZMax ) ) );
208  objPtr->SetMaterial( aMaterial );
209  objPtr->SetColor( ConvertSRGBToLinear( aObjColor ) );
210  aDstContainer.Add( objPtr );
211  break;
212  }
213 
215  {
217 
218  const ROUND_SEGMENT_2D* aRoundSeg2D = static_cast<const ROUND_SEGMENT_2D*>( aObject2D );
219  ROUND_SEGMENT* objPtr = new ROUND_SEGMENT( *aRoundSeg2D, aZMin, aZMax );
220  objPtr->SetMaterial( aMaterial );
221  objPtr->SetColor( ConvertSRGBToLinear( aObjColor ) );
222  aDstContainer.Add( objPtr );
223  break;
224  }
225 
226  default:
227  {
228  LAYER_ITEM* objPtr = new LAYER_ITEM( aObject2D, aZMin, aZMax );
229  objPtr->SetMaterial( aMaterial );
230  objPtr->SetColor( ConvertSRGBToLinear( aObjColor ) );
231  aDstContainer.Add( objPtr );
232  break;
233  }
234  }
235 }
236 
237 
239  PCB_LAYER_ID aLayer_id, const MATERIAL* aMaterialLayer, const SFVEC3F& aLayerColor,
240  float aLayerZOffset )
241 {
242  if( aContainer2d == nullptr )
243  return;
244 
245  const LIST_OBJECT2D& listObject2d = aContainer2d->GetList();
246 
247  if( listObject2d.size() == 0 )
248  return;
249 
250  for( LIST_OBJECT2D::const_iterator itemOnLayer = listObject2d.begin();
251  itemOnLayer != listObject2d.end(); ++itemOnLayer )
252  {
253  const OBJECT_2D* object2d_A = static_cast<const OBJECT_2D*>( *itemOnLayer );
254 
255  // not yet used / implemented (can be used in future to clip the objects in the
256  // board borders
257  OBJECT_2D* object2d_C = CSGITEM_FULL;
258 
259  std::vector<const OBJECT_2D*>* object2d_B = CSGITEM_EMPTY;
260 
261  object2d_B = new std::vector<const OBJECT_2D*>();
262 
263  // Subtract holes but not in SolderPaste
264  // (can be added as an option in future)
265  if( !( ( aLayer_id == B_Paste ) || ( aLayer_id == F_Paste ) ) )
266  {
267  // Check if there are any layerhole that intersects this object
268  // Eg: a segment is cut by a via hole or THT hole.
269  const MAP_CONTAINER_2D_BASE& layerHolesMap = m_boardAdapter.GetLayerHoleMap();
270 
271  if( layerHolesMap.find( aLayer_id ) != layerHolesMap.end() )
272  {
273  MAP_CONTAINER_2D_BASE::const_iterator ii_hole = layerHolesMap.find( aLayer_id );
274 
275  const BVH_CONTAINER_2D* containerLayerHoles2d =
276  static_cast<const BVH_CONTAINER_2D*>( ii_hole->second );
277 
278  CONST_LIST_OBJECT2D intersectionList;
279  containerLayerHoles2d->GetListObjectsIntersects( object2d_A->GetBBox(),
280  intersectionList );
281 
282  if( !intersectionList.empty() )
283  {
284  for( CONST_LIST_OBJECT2D::const_iterator holeOnLayer = intersectionList.begin();
285  holeOnLayer != intersectionList.end(); ++holeOnLayer )
286  {
287  const OBJECT_2D* hole2d = static_cast<const OBJECT_2D*>( *holeOnLayer );
288 
289  //if( object2d_A->Intersects( hole2d->GetBBox() ) )
290  //if( object2d_A->GetBBox().Intersects( hole2d->GetBBox() ) )
291  object2d_B->push_back( hole2d );
292  }
293  }
294  }
295 
296  // Check if there are any THT that intersects this object
297  // If we're processing a silk screen layer and the flag is set, then
298  // clip the silk screening at the outer edge of the annular ring, rather
299  // than the at the outer edge of the copper plating.
300  const BVH_CONTAINER_2D& throughHoleOuter =
303  && ( ( aLayer_id == B_SilkS ) || ( aLayer_id == F_SilkS ) ) ) ?
306 
307  if( !throughHoleOuter.GetList().empty() )
308  {
309  CONST_LIST_OBJECT2D intersectionList;
310 
311  throughHoleOuter.GetListObjectsIntersects( object2d_A->GetBBox(),
312  intersectionList );
313 
314  if( !intersectionList.empty() )
315  {
316  for( CONST_LIST_OBJECT2D::const_iterator hole = intersectionList.begin();
317  hole != intersectionList.end(); ++hole )
318  {
319  const OBJECT_2D* hole2d = static_cast<const OBJECT_2D*>( *hole );
320 
321  //if( object2d_A->Intersects( hole2d->GetBBox() ) )
322  //if( object2d_A->GetBBox().Intersects( hole2d->GetBBox() ) )
323  object2d_B->push_back( hole2d );
324  }
325  }
326  }
327  }
328 
329  if( !m_antioutlineBoard2dObjects->GetList().empty() )
330  {
331  CONST_LIST_OBJECT2D intersectionList;
332 
334  intersectionList );
335 
336  if( !intersectionList.empty() )
337  {
338  for( const OBJECT_2D* obj : intersectionList )
339  {
340  object2d_B->push_back( obj );
341  }
342  }
343  }
344 
345  const MAP_CONTAINER_2D_BASE& mapLayers = m_boardAdapter.GetLayerMap();
346 
349  && ( ( ( aLayer_id == B_SilkS ) && ( mapLayers.find( B_Mask ) != mapLayers.end() ) )
350  || ( ( aLayer_id == F_SilkS )
351  && ( mapLayers.find( F_Mask ) != mapLayers.end() ) ) ) )
352  {
353  const PCB_LAYER_ID layerMask_id = ( aLayer_id == B_SilkS ) ? B_Mask : F_Mask;
354 
355  const BVH_CONTAINER_2D* containerMaskLayer2d =
356  static_cast<const BVH_CONTAINER_2D*>( mapLayers.at( layerMask_id ) );
357 
358  CONST_LIST_OBJECT2D intersectionList;
359 
360  if( containerMaskLayer2d ) // can be null if B_Mask or F_Mask is not shown
361  containerMaskLayer2d->GetListObjectsIntersects( object2d_A->GetBBox(),
362  intersectionList );
363 
364  if( !intersectionList.empty() )
365  {
366  for( CONST_LIST_OBJECT2D::const_iterator objOnLayer = intersectionList.begin();
367  objOnLayer != intersectionList.end(); ++objOnLayer )
368  {
369  const OBJECT_2D* obj2d = static_cast<const OBJECT_2D*>( *objOnLayer );
370 
371  object2d_B->push_back( obj2d );
372  }
373  }
374  }
375 
376  if( object2d_B->empty() )
377  {
378  delete object2d_B;
379  object2d_B = CSGITEM_EMPTY;
380  }
381 
382  if( ( object2d_B == CSGITEM_EMPTY ) && ( object2d_C == CSGITEM_FULL ) )
383  {
384  LAYER_ITEM* objPtr = new LAYER_ITEM( object2d_A,
385  m_boardAdapter.GetLayerBottomZPos( aLayer_id ) - aLayerZOffset,
386  m_boardAdapter.GetLayerTopZPos( aLayer_id ) + aLayerZOffset );
387  objPtr->SetMaterial( aMaterialLayer );
388  objPtr->SetColor( ConvertSRGBToLinear( aLayerColor ) );
389  m_objectContainer.Add( objPtr );
390  }
391  else
392  {
393  LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( object2d_A, object2d_B, object2d_C,
394  object2d_A->GetBoardItem() );
395  m_containerWithObjectsToDelete.Add( itemCSG2d );
396 
397  LAYER_ITEM* objPtr = new LAYER_ITEM( itemCSG2d,
398  m_boardAdapter.GetLayerBottomZPos( aLayer_id ) - aLayerZOffset,
399  m_boardAdapter.GetLayerTopZPos( aLayer_id ) + aLayerZOffset );
400 
401  objPtr->SetMaterial( aMaterialLayer );
402  objPtr->SetColor( ConvertSRGBToLinear( aLayerColor ) );
403 
404  m_objectContainer.Add( objPtr );
405  }
406  }
407 }
408 
409 
410 extern void buildBoardBoundingBoxPoly( const BOARD* aBoard, SHAPE_POLY_SET& aOutline );
411 
412 
413 void RENDER_3D_RAYTRACE::Reload( REPORTER* aStatusReporter, REPORTER* aWarningReporter,
414  bool aOnlyLoadCopperAndShapes )
415 {
416  m_reloadRequested = false;
417 
418  m_modelMaterialMap.clear();
419 
422 
423  unsigned stats_startReloadTime = GetRunningMicroSecs();
424 
425  if( !aOnlyLoadCopperAndShapes )
426  {
427  m_boardAdapter.InitSettings( aStatusReporter, aWarningReporter );
428 
429  SFVEC3F camera_pos = m_boardAdapter.GetBoardCenter();
430  m_camera.SetBoardLookAtPos( camera_pos );
431  }
432 
435 
436  setupMaterials();
437 
438  if( aStatusReporter )
439  aStatusReporter->Report( _( "Load Raytracing: board" ) );
440 
441  // Create and add the outline board
444 
447 
448  if( !aOnlyLoadCopperAndShapes )
449  {
450  const int outlineCount = m_boardAdapter.GetBoardPoly().OutlineCount();
451 
452  if( outlineCount > 0 )
453  {
454  float divFactor = 0.0f;
455 
457  divFactor = m_boardAdapter.GetAverageViaHoleDiameter() * 18.0f;
458  else if( m_boardAdapter.GetHoleCount() )
459  divFactor = m_boardAdapter.GetAverageHoleDiameter() * 8.0f;
460 
461  SHAPE_POLY_SET boardPolyCopy = m_boardAdapter.GetBoardPoly();
462 
463  // Calculate an antiboard outline
464  SHAPE_POLY_SET antiboardPoly;
465 
467 
468  antiboardPoly.BooleanSubtract( boardPolyCopy, SHAPE_POLY_SET::PM_FAST );
469  antiboardPoly.Fracture( SHAPE_POLY_SET::PM_FAST );
470 
471  for( int iOutlinePolyIdx = 0; iOutlinePolyIdx < antiboardPoly.OutlineCount();
472  iOutlinePolyIdx++ )
473  {
474  CovertPolygonToBlocks( antiboardPoly,
476  *dynamic_cast<const BOARD_ITEM*>( m_boardAdapter.GetBoard() ),
477  iOutlinePolyIdx );
478  }
479 
481 
482  boardPolyCopy.Fracture( SHAPE_POLY_SET::PM_FAST );
483 
484  for( int iOutlinePolyIdx = 0; iOutlinePolyIdx < outlineCount; iOutlinePolyIdx++ )
485  {
487  m_boardAdapter.BiuTo3dUnits(), divFactor,
488  *dynamic_cast<const BOARD_ITEM*>( m_boardAdapter.GetBoard() ),
489  iOutlinePolyIdx );
490  }
491 
493  {
494  const LIST_OBJECT2D& listObjects = m_outlineBoard2dObjects->GetList();
495 
496  for( LIST_OBJECT2D::const_iterator object2d_iterator = listObjects.begin();
497  object2d_iterator != listObjects.end(); ++object2d_iterator )
498  {
499  const OBJECT_2D* object2d_A =
500  static_cast<const OBJECT_2D*>( *object2d_iterator );
501 
502  std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
503 
504  // Check if there are any THT that intersects this outline object part
505  if( !m_boardAdapter.GetThroughHoleOds().GetList().empty() )
506  {
507  CONST_LIST_OBJECT2D intersectionList;
509  object2d_A->GetBBox(), intersectionList );
510 
511  if( !intersectionList.empty() )
512  {
513  for( CONST_LIST_OBJECT2D::const_iterator hole =
514  intersectionList.begin();
515  hole != intersectionList.end(); ++hole )
516  {
517  const OBJECT_2D* hole2d = static_cast<const OBJECT_2D*>( *hole );
518 
519  if( object2d_A->Intersects( hole2d->GetBBox() ) )
520  //if( object2d_A->GetBBox().Intersects( hole2d->GetBBox() ) )
521  object2d_B->push_back( hole2d );
522  }
523  }
524  }
525 
526  if( !m_antioutlineBoard2dObjects->GetList().empty() )
527  {
528  CONST_LIST_OBJECT2D intersectionList;
529 
531  object2d_A->GetBBox(), intersectionList );
532 
533  if( !intersectionList.empty() )
534  {
535  for( const OBJECT_2D* obj : intersectionList )
536  {
537  object2d_B->push_back( obj );
538  }
539  }
540  }
541 
542  if( object2d_B->empty() )
543  {
544  delete object2d_B;
545  object2d_B = CSGITEM_EMPTY;
546  }
547 
548  if( object2d_B == CSGITEM_EMPTY )
549  {
550  LAYER_ITEM* objPtr = new LAYER_ITEM( object2d_A,
553 
554  objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
555  objPtr->SetColor(
557  m_objectContainer.Add( objPtr );
558  }
559  else
560  {
561 
562  LAYER_ITEM_2D* itemCSG2d =
563  new LAYER_ITEM_2D( object2d_A, object2d_B, CSGITEM_FULL,
564  (const BOARD_ITEM&) *m_boardAdapter.GetBoard() );
565 
566  m_containerWithObjectsToDelete.Add( itemCSG2d );
567 
568  LAYER_ITEM* objPtr = new LAYER_ITEM( itemCSG2d,
571 
572  objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
573  objPtr->SetColor(
575  m_objectContainer.Add( objPtr );
576  }
577  }
578 
579  // Add cylinders of the board body to container
580  // Note: This is actually a workaround for the holes in the board.
581  // The issue is because if a hole is in a border of a divided polygon ( ex
582  // a polygon or dummy block) it will cut also the render of the hole.
583  // So this will add a full hole.
584  // In fact, that is not need if the hole have copper.
585  if( !m_boardAdapter.GetThroughHoleOds().GetList().empty() )
586  {
588 
589  for( LIST_OBJECT2D::const_iterator hole = holeList.begin();
590  hole != holeList.end(); ++hole )
591  {
592  const OBJECT_2D* hole2d = static_cast<const OBJECT_2D*>( *hole );
593 
594  if( !m_antioutlineBoard2dObjects->GetList().empty() )
595  {
596  CONST_LIST_OBJECT2D intersectionList;
597 
599  hole2d->GetBBox(), intersectionList );
600 
601  if( !intersectionList.empty() )
602  {
603  // Do not add cylinder if it intersects the edge of the board
604 
605  continue;
606  }
607  }
608 
609  switch( hole2d->GetObjectType() )
610  {
612  {
613  const float radius = hole2d->GetBBox().GetExtent().x * 0.5f * 0.999f;
614 
615  CYLINDER* objPtr = new CYLINDER( hole2d->GetCentroid(),
618  radius );
619 
620  objPtr->SetMaterial( &m_materials.m_EpoxyBoard );
621  objPtr->SetColor( ConvertSRGBToLinear(
623 
624  m_objectContainer.Add( objPtr );
625  }
626  break;
627 
628  default:
629  break;
630  }
631  }
632  }
633  }
634  }
635  }
636 
637  if( aStatusReporter )
638  aStatusReporter->Report( _( "Load Raytracing: layers" ) );
639 
640  // Add layers maps (except B_Mask and F_Mask)
641  for( MAP_CONTAINER_2D_BASE::const_iterator ii = m_boardAdapter.GetLayerMap().begin();
642  ii != m_boardAdapter.GetLayerMap().end(); ++ii )
643  {
644  PCB_LAYER_ID layer_id = static_cast<PCB_LAYER_ID>( ii->first );
645 
646  if( aOnlyLoadCopperAndShapes && !IsCopperLayer( layer_id ) )
647  continue;
648 
649  // Mask layers are not processed here because they are a special case
650  if( ( layer_id == B_Mask ) || ( layer_id == F_Mask ) )
651  continue;
652 
653  MATERIAL* materialLayer = &m_materials.m_SilkS;
654  SFVEC3F layerColor = SFVEC3F( 0.0f, 0.0f, 0.0f );
655 
656  switch( layer_id )
657  {
658  case B_Adhes:
659  case F_Adhes:
660  break;
661 
662  case B_Paste:
663  case F_Paste:
664  materialLayer = &m_materials.m_Paste;
665 
667  layerColor = m_boardAdapter.m_SolderPasteColor;
668  else
669  layerColor = m_boardAdapter.GetLayerColor( layer_id );
670  break;
671 
672  case B_SilkS:
673  materialLayer = &m_materials.m_SilkS;
674 
677  else
678  layerColor = m_boardAdapter.GetLayerColor( layer_id );
679  break;
680  case F_SilkS:
681  materialLayer = &m_materials.m_SilkS;
682 
685  else
686  layerColor = m_boardAdapter.GetLayerColor( layer_id );
687  break;
688 
689  case Dwgs_User:
690  case Cmts_User:
691  case Eco1_User:
692  case Eco2_User:
693  case Edge_Cuts:
694  case Margin:
695  break;
696 
697  case B_CrtYd:
698  case F_CrtYd:
699  break;
700 
701  case B_Fab:
702  case F_Fab:
703  break;
704 
705  default:
707  {
709  layerColor = SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f, 50.0f / 255.0f );
710  else
711  layerColor = m_boardAdapter.m_CopperColor;
712  }
713  else
714  layerColor = m_boardAdapter.GetLayerColor( layer_id );
715 
716  materialLayer = &m_materials.m_NonPlatedCopper;
717  break;
718  }
719 
720  const BVH_CONTAINER_2D* container2d = static_cast<const BVH_CONTAINER_2D*>( ii->second );
721 
722  createItemsFromContainer( container2d, layer_id, materialLayer, layerColor, 0.0f );
723  } // for each layer on map
724 
725  // Create plated copper
728  {
732 
736  }
737 
738  if( !aOnlyLoadCopperAndShapes )
739  {
740  // Add Mask layer
741  // Solder mask layers are "negative" layers so the elements that we have
742  // (in the container) should remove the board outline.
743  // We will check for all objects in the outline if it intersects any object
744  // in the layer container and also any hole.
746  && ( m_outlineBoard2dObjects->GetList().size() >= 1 ) )
747  {
748  const MATERIAL* materialLayer = &m_materials.m_SolderMask;
749 
750  for( MAP_CONTAINER_2D_BASE::const_iterator ii = m_boardAdapter.GetLayerMap().begin();
751  ii != m_boardAdapter.GetLayerMap().end(); ++ii )
752  {
753  PCB_LAYER_ID layer_id = static_cast<PCB_LAYER_ID>( ii->first );
754 
755  const BVH_CONTAINER_2D* containerLayer2d =
756  static_cast<const BVH_CONTAINER_2D*>( ii->second );
757 
758  // Only get the Solder mask layers
759  if( !( layer_id == B_Mask || layer_id == F_Mask ) )
760  continue;
761 
762  SFVEC3F layerColor;
763 
765  {
766  if( layer_id == B_Mask )
768  else
770  }
771  else
772  {
773  layerColor = m_boardAdapter.GetLayerColor( layer_id );
774  }
775 
776  const float zLayerMin = m_boardAdapter.GetLayerBottomZPos( layer_id );
777  const float zLayerMax = m_boardAdapter.GetLayerTopZPos( layer_id );
778 
779  // Get the outline board objects
780  const LIST_OBJECT2D& listObjects = m_outlineBoard2dObjects->GetList();
781 
782  for( LIST_OBJECT2D::const_iterator object2d_iterator = listObjects.begin();
783  object2d_iterator != listObjects.end(); ++object2d_iterator )
784  {
785  const OBJECT_2D* object2d_A =
786  static_cast<const OBJECT_2D*>( *object2d_iterator );
787 
788  std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
789 
790  // Check if there are any THT that intersects this outline object part
791  if( !m_boardAdapter.GetThroughHoleOds().GetList().empty() )
792  {
793 
794  CONST_LIST_OBJECT2D intersectionList;
795 
797  object2d_A->GetBBox(), intersectionList );
798 
799  if( !intersectionList.empty() )
800  {
801  for( CONST_LIST_OBJECT2D::const_iterator hole =
802  intersectionList.begin();
803  hole != intersectionList.end(); ++hole )
804  {
805  const OBJECT_2D* hole2d = static_cast<const OBJECT_2D*>( *hole );
806 
807  if( object2d_A->Intersects( hole2d->GetBBox() ) )
808  object2d_B->push_back( hole2d );
809  }
810  }
811  }
812 
813  // Check if there are any objects in the layer to subtract with the
814  // current object
815  if( !containerLayer2d->GetList().empty() )
816  {
817  CONST_LIST_OBJECT2D intersectionList;
818 
819  containerLayer2d->GetListObjectsIntersects(
820  object2d_A->GetBBox(), intersectionList );
821 
822  if( !intersectionList.empty() )
823  {
824  for( CONST_LIST_OBJECT2D::const_iterator obj = intersectionList.begin();
825  obj != intersectionList.end(); ++obj )
826  {
827  const OBJECT_2D* obj2d = static_cast<const OBJECT_2D*>( *obj );
828 
829  object2d_B->push_back( obj2d );
830  }
831  }
832  }
833 
834  if( object2d_B->empty() )
835  {
836  delete object2d_B;
837  object2d_B = CSGITEM_EMPTY;
838  }
839 
840  if( object2d_B == CSGITEM_EMPTY )
841  {
842 #if 0
843  createObject( m_objectContainer, object2d_A, zLayerMin, zLayerMax,
844  materialLayer, layerColor );
845 #else
846  LAYER_ITEM* objPtr = new LAYER_ITEM( object2d_A, zLayerMin, zLayerMax );
847 
848  objPtr->SetMaterial( materialLayer );
849  objPtr->SetColor( ConvertSRGBToLinear( layerColor ) );
850 
851  m_objectContainer.Add( objPtr );
852 #endif
853  }
854  else
855  {
856  LAYER_ITEM_2D* itemCSG2d =
857  new LAYER_ITEM_2D( object2d_A, object2d_B, CSGITEM_FULL,
858  object2d_A->GetBoardItem() );
859 
860  m_containerWithObjectsToDelete.Add( itemCSG2d );
861 
862  LAYER_ITEM* objPtr = new LAYER_ITEM( itemCSG2d, zLayerMin, zLayerMax );
863  objPtr->SetMaterial( materialLayer );
864  objPtr->SetColor( ConvertSRGBToLinear( layerColor ) );
865 
866  m_objectContainer.Add( objPtr );
867  }
868  }
869  }
870  }
871 
872  addPadsAndVias();
873  }
874 
875 #ifdef PRINT_STATISTICS_3D_VIEWER
876  unsigned stats_endConvertTime = GetRunningMicroSecs();
877  unsigned stats_startLoad3DmodelsTime = stats_endConvertTime;
878 #endif
879 
880  if( aStatusReporter )
881  aStatusReporter->Report( _( "Loading 3D models" ) );
882 
883  loadModels( m_objectContainer, aOnlyLoadCopperAndShapes );
884 
885 #ifdef PRINT_STATISTICS_3D_VIEWER
886  unsigned stats_endLoad3DmodelsTime = GetRunningMicroSecs();
887 #endif
888 
889  if( !aOnlyLoadCopperAndShapes )
890  {
891  // Add floor
893  {
894  BBOX_3D boardBBox = m_boardAdapter.GetBBox();
895 
896  if( boardBBox.IsInitialized() )
897  {
898  boardBBox.Scale( 3.0f );
899 
900  if( m_objectContainer.GetList().size() > 0 )
901  {
902  BBOX_3D containerBBox = m_objectContainer.GetBBox();
903 
904  containerBBox.Scale( 1.3f );
905 
906  const SFVEC3F centerBBox = containerBBox.GetCenter();
907 
908  // Floor triangles
909  const float minZ = glm::min( containerBBox.Min().z, boardBBox.Min().z );
910 
911  const SFVEC3F v1 =
912  SFVEC3F( -RANGE_SCALE_3D * 4.0f, -RANGE_SCALE_3D * 4.0f, minZ )
913  + SFVEC3F( centerBBox.x, centerBBox.y, 0.0f );
914 
915  const SFVEC3F v3 =
916  SFVEC3F( +RANGE_SCALE_3D * 4.0f, +RANGE_SCALE_3D * 4.0f, minZ )
917  + SFVEC3F( centerBBox.x, centerBBox.y, 0.0f );
918 
919  const SFVEC3F v2 = SFVEC3F( v1.x, v3.y, v1.z );
920  const SFVEC3F v4 = SFVEC3F( v3.x, v1.y, v1.z );
921 
922  SFVEC3F backgroundColor = ConvertSRGBToLinear(
923  static_cast<SFVEC3F>( m_boardAdapter.m_BgColorTop ) );
924 
925  TRIANGLE* newTriangle1 = new TRIANGLE( v1, v2, v3 );
926  TRIANGLE* newTriangle2 = new TRIANGLE( v3, v4, v1 );
927 
928  m_objectContainer.Add( newTriangle1 );
929  m_objectContainer.Add( newTriangle2 );
930 
931  newTriangle1->SetMaterial( (const MATERIAL*) &m_materials.m_Floor );
932  newTriangle2->SetMaterial( (const MATERIAL*) &m_materials.m_Floor );
933 
934  newTriangle1->SetColor( backgroundColor );
935  newTriangle2->SetColor( backgroundColor );
936 
937  // Ceiling triangles
938  const float maxZ = glm::max( containerBBox.Max().z, boardBBox.Max().z );
939 
940  const SFVEC3F v5 = SFVEC3F( v1.x, v1.y, maxZ );
941  const SFVEC3F v6 = SFVEC3F( v2.x, v2.y, maxZ );
942  const SFVEC3F v7 = SFVEC3F( v3.x, v3.y, maxZ );
943  const SFVEC3F v8 = SFVEC3F( v4.x, v4.y, maxZ );
944 
945  TRIANGLE* newTriangle3 = new TRIANGLE( v7, v6, v5 );
946  TRIANGLE* newTriangle4 = new TRIANGLE( v5, v8, v7 );
947 
948  m_objectContainer.Add( newTriangle3 );
949  m_objectContainer.Add( newTriangle4 );
950 
951  newTriangle3->SetMaterial( (const MATERIAL*) &m_materials.m_Floor );
952  newTriangle4->SetMaterial( (const MATERIAL*) &m_materials.m_Floor );
953 
954  newTriangle3->SetColor( backgroundColor );
955  newTriangle4->SetColor( backgroundColor );
956  }
957  }
958  }
959 
960  // Init initial lights
961  m_lights.Clear();
962 
963  auto IsColorZero =
964  []( const SFVEC3F& aSource )
965  {
966  return ( ( aSource.r < ( 1.0f / 255.0f ) ) && ( aSource.g < ( 1.0f / 255.0f ) )
967  && ( aSource.b < ( 1.0f / 255.0f ) ) );
968  };
969 
970  m_cameraLight = new DIRECTIONAL_LIGHT( SFVEC3F( 0.0f, 0.0f, 0.0f ),
972  m_cameraLight->SetCastShadows( false );
973 
974  if( !IsColorZero( m_boardAdapter.m_RtCameraLightColor ) )
976 
977  const SFVEC3F& boardCenter = m_boardAdapter.GetBBox().GetCenter();
978 
979  if( !IsColorZero( m_boardAdapter.m_RtLightColorTop ) )
980  m_lights.Add( new POINT_LIGHT( SFVEC3F( boardCenter.x, boardCenter.y,
981  +RANGE_SCALE_3D * 2.0f ),
983 
984  if( !IsColorZero( m_boardAdapter.m_RtLightColorBottom ) )
985  m_lights.Add( new POINT_LIGHT( SFVEC3F( boardCenter.x, boardCenter.y,
986  -RANGE_SCALE_3D * 2.0f ),
988 
989  wxASSERT( m_boardAdapter.m_RtLightColor.size()
991 
992  for( size_t i = 0; i < m_boardAdapter.m_RtLightColor.size(); ++i )
993  {
994  if( !IsColorZero( m_boardAdapter.m_RtLightColor[i] ) )
995  {
997 
999  SphericalToCartesian( glm::pi<float>() * sc.x, glm::pi<float>() * sc.y ),
1001  }
1002  }
1003  }
1004 
1005  // Create an accelerator
1006  if( m_accelerator )
1007  {
1008  delete m_accelerator;
1009  }
1010 
1011  m_accelerator = 0;
1012 
1014 
1015  if( aStatusReporter )
1016  {
1017  // Calculation time in seconds
1018  const double calculation_time =
1019  (double) ( GetRunningMicroSecs() - stats_startReloadTime ) / 1e6;
1020 
1021  aStatusReporter->Report( wxString::Format( _( "Reload time %.3f s" ), calculation_time ) );
1022  }
1023 }
1024 
1025 
1027 {
1028  PCB_LAYER_ID top_layer, bottom_layer;
1029  int radiusBUI = ( aVia->GetDrillValue() / 2 );
1030 
1031  aVia->LayerPair( &top_layer, &bottom_layer );
1032 
1033  float topZ = m_boardAdapter.GetLayerBottomZPos( top_layer )
1035 
1036  float botZ = m_boardAdapter.GetLayerBottomZPos( bottom_layer )
1038 
1039  const SFVEC2F center = SFVEC2F( aVia->GetStart().x * m_boardAdapter.BiuTo3dUnits(),
1040  -aVia->GetStart().y * m_boardAdapter.BiuTo3dUnits() );
1041 
1042  RING_2D* ring = new RING_2D( center, radiusBUI * m_boardAdapter.BiuTo3dUnits(),
1043  ( radiusBUI + m_boardAdapter.GetHolePlatingThickness() )
1044  * m_boardAdapter.BiuTo3dUnits(), *aVia );
1045 
1047 
1048  LAYER_ITEM* objPtr = new LAYER_ITEM( ring, topZ, botZ );
1049 
1050  objPtr->SetMaterial( &m_materials.m_Copper );
1051 
1054  else
1056  LAYER_VIAS + static_cast<int>( aVia->GetViaType() ) ) ) );
1057 
1058  m_objectContainer.Add( objPtr );
1059 }
1060 
1061 
1063 {
1064  const OBJECT_2D* object2d_A = nullptr;
1065 
1066  SFVEC3F objColor;
1067 
1069  objColor = (SFVEC3F) m_boardAdapter.m_CopperColor;
1070  else
1072 
1073  const wxSize drillsize = aPad->GetDrillSize();
1074  const bool hasHole = drillsize.x && drillsize.y;
1075 
1076  if( !hasHole )
1077  return;
1078 
1079  CONST_LIST_OBJECT2D antiOutlineIntersectionList;
1080 
1081  const float topZ = m_boardAdapter.GetLayerBottomZPos( F_Cu )
1082  + m_boardAdapter.GetCopperThickness() * 0.99f;
1083 
1084  const float botZ = m_boardAdapter.GetLayerBottomZPos( B_Cu )
1085  - m_boardAdapter.GetCopperThickness() * 0.99f;
1086 
1087  if( drillsize.x == drillsize.y ) // usual round hole
1088  {
1089  SFVEC2F center = SFVEC2F( aPad->GetPosition().x * m_boardAdapter.BiuTo3dUnits(),
1090  -aPad->GetPosition().y * m_boardAdapter.BiuTo3dUnits() );
1091 
1092  int innerRadius = drillsize.x / 2;
1093  int outerRadius = innerRadius + m_boardAdapter.GetHolePlatingThickness();
1094 
1095  RING_2D* ring = new RING_2D( center, innerRadius * m_boardAdapter.BiuTo3dUnits(),
1096  outerRadius * m_boardAdapter.BiuTo3dUnits(), *aPad );
1097 
1099 
1100  object2d_A = ring;
1101 
1102  // If the object (ring) is intersected by an antioutline board,
1103  // it will use instead a CSG of two circles.
1104  if( object2d_A && !m_antioutlineBoard2dObjects->GetList().empty() )
1105  {
1107  antiOutlineIntersectionList );
1108  }
1109 
1110  if( !antiOutlineIntersectionList.empty() )
1111  {
1112  FILLED_CIRCLE_2D* innerCircle = new FILLED_CIRCLE_2D(
1113  center, innerRadius * m_boardAdapter.BiuTo3dUnits(), *aPad );
1114 
1115  FILLED_CIRCLE_2D* outterCircle = new FILLED_CIRCLE_2D(
1116  center, outerRadius * m_boardAdapter.BiuTo3dUnits(), *aPad );
1117  std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
1118  object2d_B->push_back( innerCircle );
1119 
1120  LAYER_ITEM_2D* itemCSG2d =
1121  new LAYER_ITEM_2D( outterCircle, object2d_B, CSGITEM_FULL, *aPad );
1122 
1123  m_containerWithObjectsToDelete.Add( itemCSG2d );
1124  m_containerWithObjectsToDelete.Add( innerCircle );
1125  m_containerWithObjectsToDelete.Add( outterCircle );
1126 
1127  object2d_A = itemCSG2d;
1128  }
1129  }
1130  else // Oblong hole
1131  {
1132  wxPoint ends_offset;
1133  int width;
1134 
1135  if( drillsize.x > drillsize.y ) // Horizontal oval
1136  {
1137  ends_offset.x = ( drillsize.x - drillsize.y ) / 2;
1138  width = drillsize.y;
1139  }
1140  else // Vertical oval
1141  {
1142  ends_offset.y = ( drillsize.y - drillsize.x ) / 2;
1143  width = drillsize.x;
1144  }
1145 
1146  RotatePoint( &ends_offset, aPad->GetOrientation() );
1147 
1148  wxPoint start = aPad->GetPosition() + ends_offset;
1149  wxPoint end = aPad->GetPosition() - ends_offset;
1150 
1151  ROUND_SEGMENT_2D* innerSeg =
1153  -start.y * m_boardAdapter.BiuTo3dUnits() ),
1154  SFVEC2F( end.x * m_boardAdapter.BiuTo3dUnits(),
1155  -end.y * m_boardAdapter.BiuTo3dUnits() ),
1156  width * m_boardAdapter.BiuTo3dUnits(), *aPad );
1157 
1158  ROUND_SEGMENT_2D* outerSeg =
1160  -start.y * m_boardAdapter.BiuTo3dUnits() ),
1161  SFVEC2F( end.x * m_boardAdapter.BiuTo3dUnits(),
1162  -end.y * m_boardAdapter.BiuTo3dUnits() ),
1163  ( width + m_boardAdapter.GetHolePlatingThickness() * 2 )
1164  * m_boardAdapter.BiuTo3dUnits(), *aPad );
1165 
1166  // NOTE: the round segment width is the "diameter", so we double the thickness
1167  std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
1168  object2d_B->push_back( innerSeg );
1169 
1170  LAYER_ITEM_2D* itemCSG2d =
1171  new LAYER_ITEM_2D( outerSeg, object2d_B, CSGITEM_FULL, *aPad );
1172 
1173  m_containerWithObjectsToDelete.Add( itemCSG2d );
1174  m_containerWithObjectsToDelete.Add( innerSeg );
1175  m_containerWithObjectsToDelete.Add( outerSeg );
1176 
1177  object2d_A = itemCSG2d;
1178 
1179  if( object2d_A && !m_antioutlineBoard2dObjects->GetList().empty() )
1180  {
1181 
1183  antiOutlineIntersectionList );
1184  }
1185  }
1186 
1187  if( object2d_A )
1188  {
1189  std::vector<const OBJECT_2D*>* object2d_B = new std::vector<const OBJECT_2D*>();
1190 
1191  // Check if there are any other THT that intersects this hole
1192  // It will use the non inflated holes
1193  if( !m_boardAdapter.GetThroughHoleIds().GetList().empty() )
1194  {
1195  CONST_LIST_OBJECT2D intersectionList;
1197  object2d_A->GetBBox(), intersectionList );
1198 
1199  if( !intersectionList.empty() )
1200  {
1201  for( CONST_LIST_OBJECT2D::const_iterator hole = intersectionList.begin();
1202  hole != intersectionList.end(); ++hole )
1203  {
1204  const OBJECT_2D* hole2d = static_cast<const OBJECT_2D*>( *hole );
1205 
1206  if( object2d_A->Intersects( hole2d->GetBBox() ) )
1207  object2d_B->push_back( hole2d );
1208  }
1209  }
1210  }
1211 
1212  if( !antiOutlineIntersectionList.empty() )
1213  {
1214  for( const OBJECT_2D* obj : antiOutlineIntersectionList )
1215  {
1216  object2d_B->push_back( obj );
1217  }
1218  }
1219 
1220  if( object2d_B->empty() )
1221  {
1222  delete object2d_B;
1223  object2d_B = CSGITEM_EMPTY;
1224  }
1225 
1226  if( object2d_B == CSGITEM_EMPTY )
1227  {
1228  LAYER_ITEM* objPtr = new LAYER_ITEM( object2d_A, topZ, botZ );
1229 
1230  objPtr->SetMaterial( &m_materials.m_Copper );
1231  objPtr->SetColor( ConvertSRGBToLinear( objColor ) );
1232  m_objectContainer.Add( objPtr );
1233  }
1234  else
1235  {
1236  LAYER_ITEM_2D* itemCSG2d = new LAYER_ITEM_2D( object2d_A, object2d_B, CSGITEM_FULL,
1237  (const BOARD_ITEM&) *aPad );
1238 
1239  m_containerWithObjectsToDelete.Add( itemCSG2d );
1240 
1241  LAYER_ITEM* objPtr = new LAYER_ITEM( itemCSG2d, topZ, botZ );
1242 
1243  objPtr->SetMaterial( &m_materials.m_Copper );
1244  objPtr->SetColor( ConvertSRGBToLinear( objColor ) );
1245 
1246  m_objectContainer.Add( objPtr );
1247  }
1248  }
1249 }
1250 
1251 
1253 {
1254  // Insert plated vertical holes inside the board
1255 
1256  // Insert vias holes (vertical cylinders)
1257  for( TRACK* track : m_boardAdapter.GetBoard()->Tracks() )
1258  {
1259  if( track->Type() == PCB_VIA_T )
1260  {
1261  const VIA* via = static_cast<const VIA*>( track );
1262  insertHole( via );
1263  }
1264  }
1265 
1266  // Insert pads holes (vertical cylinders)
1267  for( FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
1268  {
1269  for( PAD* pad : footprint->Pads() )
1270  {
1271  if( pad->GetAttribute() != PAD_ATTRIB_NPTH )
1272  {
1273  insertHole( pad );
1274  }
1275  }
1276  }
1277 }
1278 
1279 
1280 void RENDER_3D_RAYTRACE::loadModels( CONTAINER_3D& aDstContainer, bool aSkipMaterialInformation )
1281 {
1282  // Go for all footprints
1283  for( FOOTPRINT* fp : m_boardAdapter.GetBoard()->Footprints() )
1284  {
1285  if( !fp->Models().empty()
1286  && m_boardAdapter.IsFootprintShown( (FOOTPRINT_ATTR_T) fp->GetAttributes() ) )
1287  {
1288  double zpos = m_boardAdapter.GetFootprintZPos( fp->IsFlipped() );
1289 
1290  wxPoint pos = fp->GetPosition();
1291 
1292  glm::mat4 fpMatrix = glm::mat4( 1.0f );
1293 
1294  fpMatrix = glm::translate( fpMatrix,
1295  SFVEC3F( pos.x * m_boardAdapter.BiuTo3dUnits(),
1296  -pos.y * m_boardAdapter.BiuTo3dUnits(),
1297  zpos ) );
1298 
1299  if( fp->GetOrientation() )
1300  {
1301  fpMatrix = glm::rotate( fpMatrix,
1302  ( (float) ( fp->GetOrientation() / 10.0f ) / 180.0f ) * glm::pi<float>(),
1303  SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1304  }
1305 
1306  if( fp->IsFlipped() )
1307  {
1308  fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 1.0f, 0.0f ) );
1309 
1310  fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(), SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1311  }
1312 
1313  const double modelunit_to_3d_units_factor =
1315 
1316  fpMatrix = glm::scale(
1317  fpMatrix, SFVEC3F( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
1318  modelunit_to_3d_units_factor ) );
1319 
1320  BOARD_ITEM* boardItem = dynamic_cast<BOARD_ITEM*>( fp );
1321 
1322  // Get the list of model files for this model
1324  auto sM = fp->Models().begin();
1325  auto eM = fp->Models().end();
1326 
1327  while( sM != eM )
1328  {
1329  if( ( static_cast<float>( sM->m_Opacity ) > FLT_EPSILON )
1330  && ( sM->m_Show && !sM->m_Filename.empty() ) )
1331  {
1332  // get it from cache
1333  const S3DMODEL* modelPtr = cacheMgr->GetModel( sM->m_Filename );
1334 
1335  // only add it if the return is not NULL.
1336  if( modelPtr )
1337  {
1338  glm::mat4 modelMatrix = fpMatrix;
1339 
1340  modelMatrix = glm::translate( modelMatrix,
1341  SFVEC3F( sM->m_Offset.x, sM->m_Offset.y, sM->m_Offset.z ) );
1342 
1343  modelMatrix = glm::rotate( modelMatrix,
1344  (float) -( sM->m_Rotation.z / 180.0f ) * glm::pi<float>(),
1345  SFVEC3F( 0.0f, 0.0f, 1.0f ) );
1346 
1347  modelMatrix = glm::rotate( modelMatrix,
1348  (float) -( sM->m_Rotation.y / 180.0f ) * glm::pi<float>(),
1349  SFVEC3F( 0.0f, 1.0f, 0.0f ) );
1350 
1351  modelMatrix = glm::rotate( modelMatrix,
1352  (float) -( sM->m_Rotation.x / 180.0f ) * glm::pi<float>(),
1353  SFVEC3F( 1.0f, 0.0f, 0.0f ) );
1354 
1355  modelMatrix = glm::scale( modelMatrix,
1356  SFVEC3F( sM->m_Scale.x, sM->m_Scale.y, sM->m_Scale.z ) );
1357 
1358  addModels( aDstContainer, modelPtr, modelMatrix, (float) sM->m_Opacity,
1359  aSkipMaterialInformation, boardItem );
1360  }
1361  }
1362 
1363  ++sM;
1364  }
1365  }
1366  }
1367 }
1368 
1369 
1371 {
1372  MODEL_MATERIALS* materialVector;
1373 
1374  // Try find if the materials already exists in the map list
1375  if( m_modelMaterialMap.find( a3DModel ) != m_modelMaterialMap.end() )
1376  {
1377  // Found it, so get the pointer
1378  materialVector = &m_modelMaterialMap[a3DModel];
1379  }
1380  else
1381  {
1382  // Materials was not found in the map, so it will create a new for
1383  // this model.
1384 
1385  m_modelMaterialMap[a3DModel] = MODEL_MATERIALS();
1386  materialVector = &m_modelMaterialMap[a3DModel];
1387 
1388  materialVector->resize( a3DModel->m_MaterialsSize );
1389 
1390  for( unsigned int imat = 0; imat < a3DModel->m_MaterialsSize; ++imat )
1391  {
1393  {
1394  const SMATERIAL& material = a3DModel->m_Materials[imat];
1395 
1396  // http://www.fooplot.com/#W3sidHlwZSI6MCwiZXEiOiJtaW4oc3FydCh4LTAuMzUpKjAuNDAtMC4wNSwxLjApIiwiY29sb3IiOiIjMDAwMDAwIn0seyJ0eXBlIjoxMDAwLCJ3aW5kb3ciOlsiMC4wNzA3NzM2NzMyMzY1OTAxMiIsIjEuNTY5NTcxNjI5MjI1NDY5OCIsIi0wLjI3NDYzNTMyMTc1OTkyOTMiLCIwLjY0NzcwMTg4MTkyNTUzNjIiXSwic2l6ZSI6WzY0NCwzOTRdfV0-
1397 
1398  float reflectionFactor = 0.0f;
1399 
1400  if( ( material.m_Shininess - 0.35f ) > FLT_EPSILON )
1401  {
1402  reflectionFactor = glm::clamp(
1403  glm::sqrt( ( material.m_Shininess - 0.35f ) ) * 0.40f - 0.05f, 0.0f,
1404  0.5f );
1405  }
1406 
1407  BLINN_PHONG_MATERIAL& blinnMaterial = ( *materialVector )[imat];
1408 
1409  blinnMaterial = BLINN_PHONG_MATERIAL( ConvertSRGBToLinear( material.m_Ambient ),
1410  ConvertSRGBToLinear( material.m_Emissive ),
1411  ConvertSRGBToLinear( material.m_Specular ), material.m_Shininess * 180.0f,
1412  material.m_Transparency, reflectionFactor );
1413 
1415  {
1416  // Guess material type and apply a normal perturbator
1417  if( ( RGBtoGray( material.m_Diffuse ) < 0.3f )
1418  && ( material.m_Shininess < 0.36f )
1419  && ( material.m_Transparency == 0.0f )
1420  && ( ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.g ) < 0.15f )
1421  && ( glm::abs( material.m_Diffuse.b - material.m_Diffuse.g )
1422  < 0.15f )
1423  && ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.b )
1424  < 0.15f ) ) )
1425  {
1426  // This may be a black plastic..
1427  blinnMaterial.SetGenerator( &m_plasticMaterial );
1428  }
1429  else
1430  {
1431  if( ( RGBtoGray( material.m_Diffuse ) > 0.3f )
1432  && ( material.m_Shininess < 0.30f )
1433  && ( material.m_Transparency == 0.0f )
1434  && ( ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.g ) > 0.25f )
1435  || ( glm::abs( material.m_Diffuse.b - material.m_Diffuse.g ) > 0.25f )
1436  || ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.b )
1437  > 0.25f ) ) )
1438  {
1439  // This may be a color plastic ...
1440  blinnMaterial.SetGenerator( &m_shinyPlasticMaterial );
1441  }
1442  else
1443  {
1444  if( ( RGBtoGray( material.m_Diffuse ) > 0.6f )
1445  && ( material.m_Shininess > 0.35f )
1446  && ( material.m_Transparency == 0.0f )
1447  && ( ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.g )
1448  < 0.40f )
1449  && ( glm::abs( material.m_Diffuse.b - material.m_Diffuse.g )
1450  < 0.40f )
1451  && ( glm::abs( material.m_Diffuse.r - material.m_Diffuse.b )
1452  < 0.40f ) ) )
1453  {
1454  // This may be a brushed metal
1455  blinnMaterial.SetGenerator( &m_brushedMetalMaterial );
1456  }
1457  }
1458  }
1459  }
1460  }
1461  else
1462  {
1463  ( *materialVector )[imat] = BLINN_PHONG_MATERIAL(
1464  SFVEC3F( 0.2f ), SFVEC3F( 0.0f ), SFVEC3F( 0.0f ), 0.0f, 0.0f, 0.0f );
1465  }
1466  }
1467  }
1468 
1469  return materialVector;
1470 }
1471 
1472 
1473 void RENDER_3D_RAYTRACE::addModels( CONTAINER_3D& aDstContainer, const S3DMODEL* a3DModel,
1474  const glm::mat4& aModelMatrix, float aFPOpacity,
1475  bool aSkipMaterialInformation, BOARD_ITEM* aBoardItem )
1476 {
1477  // Validate a3DModel pointers
1478  wxASSERT( a3DModel != nullptr );
1479 
1480  if( a3DModel == nullptr )
1481  return;
1482 
1483  wxASSERT( a3DModel->m_Materials != nullptr );
1484  wxASSERT( a3DModel->m_Meshes != nullptr );
1485  wxASSERT( a3DModel->m_MaterialsSize > 0 );
1486  wxASSERT( a3DModel->m_MeshesSize > 0 );
1487  wxASSERT( aFPOpacity > 0.0f );
1488  wxASSERT( aFPOpacity <= 1.0f );
1489 
1490  if( aFPOpacity > 1.0f )
1491  {
1492  aFPOpacity = 1.0f;
1493  }
1494 
1495  if( ( a3DModel->m_Materials != nullptr ) && ( a3DModel->m_Meshes != nullptr )
1496  && ( a3DModel->m_MaterialsSize > 0 ) && ( a3DModel->m_MeshesSize > 0 ) )
1497  {
1498  MODEL_MATERIALS* materialVector = nullptr;
1499 
1500  if( !aSkipMaterialInformation )
1501  {
1502  materialVector = getModelMaterial( a3DModel );
1503  }
1504 
1505  const glm::mat3 normalMatrix = glm::transpose( glm::inverse( glm::mat3( aModelMatrix ) ) );
1506 
1507  for( unsigned int mesh_i = 0; mesh_i < a3DModel->m_MeshesSize; ++mesh_i )
1508  {
1509  const SMESH& mesh = a3DModel->m_Meshes[mesh_i];
1510 
1511  // Validate the mesh pointers
1512  wxASSERT( mesh.m_Positions != nullptr );
1513  wxASSERT( mesh.m_FaceIdx != nullptr );
1514  wxASSERT( mesh.m_Normals != nullptr );
1515  wxASSERT( mesh.m_FaceIdxSize > 0 );
1516  wxASSERT( ( mesh.m_FaceIdxSize % 3 ) == 0 );
1517 
1518 
1519  if( ( mesh.m_Positions != nullptr ) && ( mesh.m_Normals != nullptr )
1520  && ( mesh.m_FaceIdx != nullptr ) && ( mesh.m_FaceIdxSize > 0 )
1521  && ( mesh.m_VertexSize > 0 ) && ( ( mesh.m_FaceIdxSize % 3 ) == 0 )
1522  && ( mesh.m_MaterialIdx < a3DModel->m_MaterialsSize ) )
1523  {
1524  float fpTransparency;
1525  const BLINN_PHONG_MATERIAL* blinn_material;
1526 
1527  if( !aSkipMaterialInformation )
1528  {
1529  blinn_material = &( *materialVector )[mesh.m_MaterialIdx];
1530 
1531  fpTransparency =
1532  1.0f - ( ( 1.0f - blinn_material->GetTransparency() ) * aFPOpacity );
1533  }
1534 
1535  // Add all face triangles
1536  for( unsigned int faceIdx = 0; faceIdx < mesh.m_FaceIdxSize; faceIdx += 3 )
1537  {
1538  const unsigned int idx0 = mesh.m_FaceIdx[faceIdx + 0];
1539  const unsigned int idx1 = mesh.m_FaceIdx[faceIdx + 1];
1540  const unsigned int idx2 = mesh.m_FaceIdx[faceIdx + 2];
1541 
1542  wxASSERT( idx0 < mesh.m_VertexSize );
1543  wxASSERT( idx1 < mesh.m_VertexSize );
1544  wxASSERT( idx2 < mesh.m_VertexSize );
1545 
1546  if( ( idx0 < mesh.m_VertexSize ) && ( idx1 < mesh.m_VertexSize )
1547  && ( idx2 < mesh.m_VertexSize ) )
1548  {
1549  const SFVEC3F& v0 = mesh.m_Positions[idx0];
1550  const SFVEC3F& v1 = mesh.m_Positions[idx1];
1551  const SFVEC3F& v2 = mesh.m_Positions[idx2];
1552 
1553  const SFVEC3F& n0 = mesh.m_Normals[idx0];
1554  const SFVEC3F& n1 = mesh.m_Normals[idx1];
1555  const SFVEC3F& n2 = mesh.m_Normals[idx2];
1556 
1557  // Transform vertex with the model matrix
1558  const SFVEC3F vt0 = SFVEC3F( aModelMatrix * glm::vec4( v0, 1.0f ) );
1559  const SFVEC3F vt1 = SFVEC3F( aModelMatrix * glm::vec4( v1, 1.0f ) );
1560  const SFVEC3F vt2 = SFVEC3F( aModelMatrix * glm::vec4( v2, 1.0f ) );
1561 
1562  const SFVEC3F nt0 = glm::normalize( SFVEC3F( normalMatrix * n0 ) );
1563  const SFVEC3F nt1 = glm::normalize( SFVEC3F( normalMatrix * n1 ) );
1564  const SFVEC3F nt2 = glm::normalize( SFVEC3F( normalMatrix * n2 ) );
1565 
1566  TRIANGLE* newTriangle = new TRIANGLE( vt0, vt2, vt1, nt0, nt2, nt1 );
1567 
1568  newTriangle->SetBoardItem( aBoardItem );
1569 
1570  aDstContainer.Add( newTriangle );
1571 
1572  if( !aSkipMaterialInformation )
1573  {
1574  newTriangle->SetMaterial( blinn_material );
1575  newTriangle->SetModelTransparency( fpTransparency );
1576 
1577  if( mesh.m_Color == nullptr )
1578  {
1579  const SFVEC3F diffuseColor =
1580  a3DModel->m_Materials[mesh.m_MaterialIdx].m_Diffuse;
1581 
1583  newTriangle->SetColor( ConvertSRGBToLinear(
1584  MaterialDiffuseToColorCAD( diffuseColor ) ) );
1585  else
1586  newTriangle->SetColor( ConvertSRGBToLinear( diffuseColor ) );
1587  }
1588  else
1589  {
1591  newTriangle->SetColor(
1593  mesh.m_Color[idx0] ) ),
1595  mesh.m_Color[idx1] ) ),
1597  mesh.m_Color[idx2] ) ) );
1598  else
1599  newTriangle->SetColor(
1600  ConvertSRGBToLinear( mesh.m_Color[idx0] ),
1601  ConvertSRGBToLinear( mesh.m_Color[idx1] ),
1602  ConvertSRGBToLinear( mesh.m_Color[idx2] ) );
1603  }
1604  }
1605  }
1606  }
1607  }
1608  }
1609  }
1610 }
Use a gray shading based on diffuse material.
Implement a triangle ray intersection based on article http://www.flipcode.com/archives/Raytracing_To...
SFVEC3F * m_Normals
Vertex normals array.
Definition: c3dmodel.h:80
float GetTransparency() const
Definition: material.h:277
void SetColor(SFVEC3F aObjColor)
Definition: plane_3d.h:49
bool GetFlag(DISPLAY3D_FLG aFlag) const
Get a configuration status of a flag.
void SetBoardLookAtPos(const SFVEC3F &aBoardPos)
Definition: camera.h:114
BOARD_ADAPTER & m_boardAdapter
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Function LayerPair Return the 2 layers used by the via (the via actually uses all layers between thes...
Definition: track.cpp:435
Definition: track.h:343
std::list< const OBJECT_2D * > CONST_LIST_OBJECT2D
Definition: container_2d.h:39
float RGBtoGray(const SFVEC3F &aColor)
Definition: 3d_math.h:140
SFVEC3F m_Ambient
Definition: c3dmodel.h:39
VECTOR2I v2(1, 0)
Test suite for KiCad math code.
Procedural generation of the copper normals.
Definition: material.h:79
Defines math related functions.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
SFVEC4F m_SilkScreenColorBot
in realistic mode: SilkScreen color ( bot )
SFVEC2F GetExtent() const
Definition: bbox_2d.cpp:125
SOLDER_MASK_NORMAL m_solderMaskMaterial
MAP_MODEL_MATERIALS m_modelMaterialMap
Stores materials of the 3D models.
void SetColor(SFVEC3F aObjColor)
Definition: cylinder_3d.h:48
void SetModelTransparency(float aModelTransparency)
Definition: object_3d.h:66
#define UNITS3D_TO_UNITSPCB
Scale conversion from 3d model units to pcb units.
static void SetDefaultReflectionRecursionCount(unsigned int aCount)
Definition: material.h:261
const SFVEC3F & Max() const
Return the maximum vertex pointer.
Definition: bbox_3d.h:203
const SFVEC2F & GetCentroid() const
Definition: object_2d.h:105
multilayer pads, usually with holes
bool IsFootprintShown(FOOTPRINT_ATTR_T aFPAttributes) const
Test if footprint should be displayed in relation to attributes and the flags.
static void SetDefaultRefractionRecursionCount(unsigned int aCount)
Definition: material.h:256
Implementation of conversion functions that require both schematic and board internal units.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
unsigned int m_convertedDummyBlockCount
MODEL_MATERIALS * getModelMaterial(const S3DMODEL *a3DModel)
COPPER_NORMAL m_copperMaterial
Manage a bounding box defined by two SFVEC3F min max points.
Definition: bbox_3d.h:41
const wxPoint & GetStart() const
Definition: track.h:116
static constexpr double IU_PER_MM
Mock up a conversion function.
const BVH_CONTAINER_2D & GetThroughHoleAnnularRings() const noexcept
Get the through hole annular rings container.
PLATED_COPPER_NORMAL m_platedCopperMaterial
SFVEC4F m_SolderMaskColorTop
in realistic mode: solder mask color ( top )
const MAP_CONTAINER_2D_BASE & GetLayerMap() const noexcept
Get the map of containers that have the objects per layer.
float GetAverageHoleDiameter() const noexcept
Average diameter of through holes.
void SetGenerator(const MATERIAL_GENERATOR *aGenerator)
Definition: material.h:332
void InitSettings(REPORTER *aStatusReporter, REPORTER *aWarningReporter)
Function to be called by the render when it need to reload the settings for the board.
std::vector< SFVEC2F > m_RtLightSphericalCoords
const LIST_OBJECT & GetList() const
Definition: container_3d.h:59
SFVEC4F m_BoardBodyColor
in realistic mode: FR4 board color
SFVEC4F m_SolderPasteColor
in realistic mode: solder paste color
Procedural generation of the plastic normals.
Definition: material.h:149
std::vector< BLINN_PHONG_MATERIAL > MODEL_MATERIALS
Vector of materials.
SFVEC4F m_SolderMaskColorBot
in realistic mode: solder mask color ( bot )
float m_Transparency
1.0 is completely transparent, 0.0 completely opaque
Definition: c3dmodel.h:44
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:228
This BVH implementation is based on the source code implementation from the book "Physically Based Re...
Cache for storing the 3D shapes.
Definition: 3d_cache.h:52
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
Blinn Phong based material https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model.
Definition: material.h:382
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:64
SFVEC3F * m_Positions
Vertex position array.
Definition: c3dmodel.h:79
Point light source based on http://ogldev.atspace.co.uk/www/tutorial20/tutorial20....
Definition: light.h:70
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
Per-vertex normal/color/texcoors structure.
Definition: c3dmodel.h:76
SFVEC3F m_RtCameraLightColor
SMESH * m_Meshes
The meshes list of this model.
Definition: c3dmodel.h:93
FOOTPRINT_ATTR_T
The set of attributes allowed within a FOOTPRINT, using FOOTPRINT::SetAttributes() and FOOTPRINT::Get...
Definition: footprint.h:66
#define CSGITEM_FULL
Definition: layer_item_2d.h:39
const SFVEC3F & Min() const
Return the minimum vertex pointer.
Definition: bbox_3d.h:196
CONTAINER_2D m_containerWithObjectsToDelete
A vertical cylinder.
Definition: cylinder_3d.h:37
const LIST_OBJECT2D & GetList() const
Definition: container_2d.h:66
S3DMODEL * GetModel(const wxString &aModelFileName)
Attempt to load the scene data for a model and to translate it into an S3D_MODEL structure for displa...
Definition: 3d_cache.cpp:651
const BVH_CONTAINER_2D & GetThroughHoleIds() const noexcept
Get the through hole inner diameter container.
Base material class that can be used to derive other material implementations.
Definition: material.h:243
void Add(OBJECT_2D *aObject)
Definition: container_2d.h:49
unsigned int m_FaceIdxSize
Number of elements of the m_FaceIdx array.
Definition: c3dmodel.h:83
static float TransparencyControl(float aGrayColorValue, float aTransparency)
Perform an interpolation step to easy control the transparency based on the gray color value and tran...
const SFVEC2F & Max() const
Definition: bbox_2d.h:172
void SetColor(const SFVEC3F &aColor)
static void SetDefaultReflectionRayCount(unsigned int aCount)
Definition: material.h:251
SFVEC3F GetCenter() const
Return the center point of the bounding box.
Definition: bbox_3d.cpp:132
void GetListObjectsIntersects(const BBOX_2D &aBBox, CONST_LIST_OBJECT2D &aOutList) const override
Get a list of objects that intersects a bounding box.
const wxSize & GetDrillSize() const
Definition: pad.h:242
void addModels(CONTAINER_3D &aDstContainer, const S3DMODEL *a3DModel, const glm::mat4 &aModelMatrix, float aFPOpacity, bool aSkipMaterialInformation, BOARD_ITEM *aBoardItem)
void Scale(float aScale)
Scales a bounding box by its center.
Definition: bbox_3d.cpp:191
unsigned int m_VertexSize
Number of vertex in the arrays.
Definition: c3dmodel.h:78
PCB_LAYER_ID
A quick note on layer IDs:
unsigned int m_converted2dRoundSegmentCount
const BVH_CONTAINER_2D * GetPlatedPadsBack() const noexcept
int m_RtRecursiveReflectionCount
SFVEC4F m_BgColorTop
background top color
glm::vec2 SFVEC2F
Definition: xv3d_types.h:42
double GetOrientation() const
Return the rotation angle of the pad in a variety of units (the basic call returns tenths of degrees)...
Definition: pad.h:341
void SetMaterial(const MATERIAL *aMaterial)
Definition: object_3d.h:58
float NextFloatDown(float v)
Definition: 3d_fastmath.h:157
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
Definition: track.cpp:173
S3D_CACHE * Get3dCacheManager() const noexcept
Return the 3D cache manager pointer.
Definition: board_adapter.h:87
#define CSGITEM_EMPTY
Definition: layer_item_2d.h:38
Represent a set of closed polygons.
float GetLayerTopZPos(PCB_LAYER_ID aLayerId) const noexcept
Get the top z position.
Use all material properties from model file.
const BBOX_2D & GetBBox() const
Definition: object_2d.h:103
const void SetBoardItem(BOARD_ITEM *aBoardItem)
Definition: object_3d.h:55
FOOTPRINTS & Footprints()
Definition: board.h:296
float GetLayerBottomZPos(PCB_LAYER_ID aLayerId) const noexcept
Get the bottom z position.
MATERIAL_MODE GetMaterialMode() const noexcept
void Clear()
Remove all lights from the container.
Definition: light.h:168
SFVEC3F m_RtLightColorTop
static OBJECT_2D_STATS & Instance()
Definition: object_2d.h:139
SFVEC3F * m_Color
Vertex color array, can be NULL.
Definition: c3dmodel.h:82
double BiuTo3dUnits() const noexcept
Board integer units To 3D units.
static OBJECT_3D_STATS & Instance()
Definition: object_3d.h:132
const BOARD_ITEM & GetBoardItem() const
Definition: object_2d.h:66
void Reload(REPORTER *aStatusReporter, REPORTER *aWarningReporter, bool aOnlyLoadCopperAndShapes)
const BOARD * GetBoard() const noexcept
Get current board to be rendered.
const BVH_CONTAINER_2D & GetThroughHoleOds() const noexcept
Get the inflated through hole outside diameters container.
int m_RtRecursiveRefractionCount
std::vector< SFVEC3F > m_RtLightColor
OBJECT_2D_TYPE GetObjectType() const
Definition: object_2d.h:107
float m_Shininess
Definition: c3dmodel.h:43
const SHAPE_POLY_SET & GetBoardPoly() const noexcept
Get the current polygon of the epoxy board.
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.
Definition: board_adapter.h:50
unsigned int m_MaterialsSize
Number of materials in the material array.
Definition: c3dmodel.h:95
bool IsInitialized() const
Check if this bounding box is already initialized.
Definition: bbox_3d.cpp:88
int m_RtRefractionSampleCount
SFVEC4F GetItemColor(int aItemId) const
Get the technical color of a layer.
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.
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
BRUSHED_METAL_NORMAL m_brushedMetalMaterial
void SetCastShadows(bool aCastShadow)
Definition: light.h:59
PLASTIC_SHINE_NORMAL m_shinyPlasticMaterial
float GetFootprintZPos(bool aIsFlipped) const
Get the position of the footprint in 3d integer units considering if it is flipped or not.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
void ResetStats()
Definition: object_3d.h:115
bool m_reloadRequested
The window size that this camera is working.
Procedural generation of the shiny brushed metal.
Definition: material.h:198
const BBOX_3D & GetBBox() const noexcept
Get the board outling bounding box.
unsigned int GetViaCount() const noexcept
Get number of vias in this board.
A triangle object.
Definition: triangle_3d.h:42
DIRECTIONAL_LIGHT * m_cameraLight
const SFVEC2F & Min() const
Definition: bbox_2d.h:167
const BBOX_3D & GetBBox() const
Definition: container_3d.h:63
A light source based only on a directional vector.
Definition: light.h:115
void CovertPolygonToBlocks(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...
Definition: polygon_2d.cpp:378
unsigned int GetHoleCount() const noexcept
Get number of holes in this board.
SFVEC4F GetLayerColor(PCB_LAYER_ID aLayerId) const
Get the technical color of a layer.
const int scale
Meta control for all vias opacity/visibility.
const BVH_CONTAINER_2D * GetPlatedPadsFront() const noexcept
Make solid geometry for objects on layers.
Definition: layer_item_2d.h:79
wxPoint GetPosition() const override
Definition: pad.h:177
SFVEC3F MaterialDiffuseToColorCAD(const SFVEC3F &aDiffuseColor)
Definition: 3d_math.h:147
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:189
BOARD_NORMAL m_boardMaterial
#define _(s)
Definition: 3d_actions.cpp:33
unsigned GetRunningMicroSecs()
An alternate way to calculate an elapset time (in microsecondes) to class PROF_COUNTER.
SFVEC3F m_Emissive
Definition: c3dmodel.h:41
glm::vec3 SFVEC3F
Definition: xv3d_types.h:44
void loadModels(CONTAINER_3D &aDstContainer, bool aSkipMaterialInformation)
void SetColor(SFVEC3F aObjColor)
Definition: layer_item_3d.h:41
unsigned int m_MaterialIdx
Material Index to be used in this mesh (must be < m_MaterialsSize )
Definition: c3dmodel.h:85
void createItemsFromContainer(const BVH_CONTAINER_2D *aContainer2d, PCB_LAYER_ID aLayer_id, const MATERIAL *aMaterialLayer, const SFVEC3F &aLayerColor, float aLayerZOffset)
SFVEC4F m_CopperColor
in realistic mode: copper color
float NextFloatUp(float v)
Definition: 3d_fastmath.h:136
SMATERIAL * m_Materials
The materials list of this model.
Definition: c3dmodel.h:96
const SFVEC3F & GetBoardCenter() const noexcept
The board center position in 3D units.
Procedural generation of the shiny plastic normals.
Definition: material.h:173
SFVEC3F SphericalToCartesian(float aInclination, float aAzimuth)
https://en.wikipedia.org/wiki/Spherical_coordinate_system
Definition: 3d_math.h:43
void buildBoardBoundingBoxPoly(const BOARD *aBoard, SHAPE_POLY_SET &aOutline)
Get the complete bounding box of the board (including all items).
VIATYPE GetViaType() const
Definition: track.h:373
float GetAverageViaHoleDiameter() const noexcept
Thee average diameter of the via holes.
void SetColor(SFVEC3F aObjColor)
CAMERA & m_camera
Flag if the opengl specific for this render was already initialized.
Defines math related functions.
SFVEC3F m_Diffuse
Default diffuse color if m_Color is NULL.
Definition: c3dmodel.h:40
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
std::list< OBJECT_2D * > LIST_OBJECT2D
Definition: container_2d.h:36
SFVEC4F m_SilkScreenColorTop
in realistic mode: SilkScreen color ( top )
float GetCopperThickness() const noexcept
Get the current copper layer thickness.
A plane that is parallel to XY plane.
Definition: plane_3d.h:37
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
void Add(OBJECT_3D *aObject)
Definition: container_3d.h:48
Store the a model based on meshes and materials.
Definition: c3dmodel.h:90
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
void ResetStats()
Definition: object_2d.h:122
static void SetDefaultRefractionRayCount(unsigned int aCount)
Definition: material.h:246
unsigned int * m_FaceIdx
Triangle Face Indexes.
Definition: c3dmodel.h:84
Definition: pad.h:60
Procedural generation of the solder mask.
Definition: material.h:129
SFVEC3F m_RtLightColorBottom
const MAP_CONTAINER_2D_BASE & GetLayerHoleMap() const noexcept
Get the map of container that have the holes per layer.
virtual bool Intersects(const BBOX_2D &aBBox) const =0
a.Intersects(b) ⇔ !a.Disjoint(b) ⇔ !(a ∩ b = ∅)
PLASTIC_NORMAL m_plasticMaterial
struct RENDER_3D_RAYTRACE::@2 m_materials
unsigned int m_MeshesSize
Number of meshes in the array.
Definition: c3dmodel.h:92
ACCELERATOR_3D * m_accelerator
SFVEC3F ConvertSRGBToLinear(const SFVEC3F &aSRGBcolor)
CONTAINER_2D * m_outlineBoard2dObjects
#define RANGE_SCALE_3D
This defines the range that all coord will have to be rendered.
Definition: board_adapter.h:61
void Add(LIGHT *aLight)
Add a light source to the container.
Definition: light.h:185
int m_RtReflectionSampleCount
TRACKS & Tracks()
Definition: board.h:293
BVH_CONTAINER_2D * m_antioutlineBoard2dObjects
Definition: track.h:83
SFVEC3F m_Specular
Definition: c3dmodel.h:42
virtual void Clear()
CONTAINER_3D m_objectContainer
Store the list of created objects special for RT that will be clear in the end.
int GetHolePlatingThickness() const noexcept
Get the current copper layer thickness.
SILK_SCREEN_NORMAL m_silkScreenMaterial