66 const float aaa = aTransparency * aTransparency * aTransparency;
69 float ca = 1.0f - aTransparency;
70 ca = 1.00f - 1.05f * ca * ca * ca;
72 return glm::max( glm::min( aGrayColorValue * ca + aaa, 1.0f ), 0.0f );
78#define UNITS3D_TO_UNITSPCB ( pcbIUScale.IU_PER_MM )
89 m_boardAdapter.m_Cfg->m_Render.raytrace_recursivelevel_refractions );
91 m_boardAdapter.m_Cfg->m_Render.raytrace_recursivelevel_reflections );
109 const SFVEC3F copperSpecularLinear =
115 SFVEC3F( 0.0f ), copperSpecularLinear, 0.4f * 128.0f, 0.0f, 0.0f );
122 SFVEC3F( 0.256f, 0.137f, 0.086f ), 0.15f * 128.0f, 0.0f, 0.0f );
134 0.10f * 128.0f, 0.0f, 0.0f );
140 SFVEC3F( 0.0f ),
SFVEC3F( 0.10f ) ), 0.078125f * 128.0f, 0.0f, 0.0f );
146 const float solderMask_gray =
156 const float minSolderMaskShininess = 0.85f * 128.0f;
157 const float maxSolderMaskShininess = 512.0f;
158 const float solderMaskShininess = minSolderMaskShininess
159 + ( maxSolderMaskShininess - minSolderMaskShininess ) * ( 1.0f - solderMask_gray );
162 const float solderMaskReflection = glm::clamp( solderMask_gray * 0.3f, 0.02f, 0.16f );
167 SFVEC3F( glm::clamp( solderMask_gray * 2.0f, 0.30f, 1.0f ) ), solderMaskShininess,
168 solderMask_transparency, solderMaskReflection );
171 m_materials.m_SolderMask.SetRefractionRayCount( 1 );
192 (
SFVEC3F( 1.0f ) - bgTop ) / 3.0f,
193 0.10f * 128.0f, 1.0f, 0.50f );
195 m_materials.m_Floor.SetReflectionRecursionCount( 1 );
200 float aZMin,
float aZMax,
const MATERIAL* aMaterial,
215 aDstContainer.
Add( objPtr );
222 aDstContainer.
Add( objPtr );
234 aDstContainer.
Add( objPtr );
243 aDstContainer.
Add( objPtr );
254 float aLayerZOffset )
256 if( aContainer2d ==
nullptr )
263 if( listObject2d.size() == 0 )
266 for(
const OBJECT_2D* object2d_A : listObject2d )
274 object2d_B =
new std::vector<const OBJECT_2D*>();
284 if( layerHolesMap.find( aLayer_id ) != layerHolesMap.end() )
292 for(
const OBJECT_2D* hole2d : intersecting )
293 object2d_B->push_back( hole2d );
303 if( !throughHoleOuter.
GetList().empty() )
309 for(
const OBJECT_2D* hole2d : intersecting )
310 object2d_B->push_back( hole2d );
315 auto clipCutouts = [
this, &object2d_A, &object2d_B](
const BVH_CONTAINER_2D& cutouts )
317 if( !cutouts.GetList().empty() )
320 cutouts.GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
322 for(
const OBJECT_2D* cutout : intersecting )
323 object2d_B->push_back( cutout );
327 if( aLayer_id ==
F_Cu )
333 else if( aLayer_id ==
B_Cu )
348 for(
const OBJECT_2D* obj : intersecting )
349 object2d_B->push_back( obj );
355 && ( ( aLayer_id ==
B_SilkS && mapLayers.find(
B_Mask ) != mapLayers.end() )
356 || ( aLayer_id ==
F_SilkS && mapLayers.find(
F_Mask ) != mapLayers.end() ) ) )
364 if( containerMaskLayer2d )
367 for(
const OBJECT_2D* obj2d : intersecting )
368 object2d_B->push_back( obj2d );
371 if( object2d_B->empty() )
409 bool aOnlyLoadCopperAndShapes )
420 if( !aOnlyLoadCopperAndShapes )
425 m_camera.SetBoardLookAtPos( camera_pos );
434 if( aStatusReporter )
435 aStatusReporter->
Report(
_(
"Load Raytracing: board" ) );
444 std::bitset<LAYER_3D_END> layerFlags =
m_boardAdapter.GetVisibleLayers();
446 if( !aOnlyLoadCopperAndShapes )
448 const int outlineCount =
m_boardAdapter.GetBoardPoly().OutlineCount();
450 if( outlineCount > 0 )
452 float divFactor = 0.0f;
469 for(
int ii = 0; ii < antiboardPoly.
OutlineCount(); ii++ )
480 for(
int ii = 0; ii < boardPolyCopy.
OutlineCount(); ii++ )
491 for(
const OBJECT_2D* object2d_A : listObjects )
493 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
503 for(
const OBJECT_2D* hole : intersecting )
505 if( object2d_A->Intersects( hole->GetBBox() ) )
506 object2d_B->push_back( hole );
511 auto addCutoutsFromContainer =
514 if( !aContainer.GetList().empty() )
517 aContainer.GetIntersectingObjects( object2d_A->GetBBox(),
520 for(
const OBJECT_2D* cutout : intersecting )
522 if( object2d_A->Intersects( cutout->GetBBox() ) )
523 object2d_B->push_back( cutout );
528 addCutoutsFromContainer(
m_boardAdapter.GetFrontCounterboreCutouts() );
529 addCutoutsFromContainer(
m_boardAdapter.GetBackCounterboreCutouts() );
530 addCutoutsFromContainer(
m_boardAdapter.GetFrontCountersinkCutouts() );
531 addCutoutsFromContainer(
m_boardAdapter.GetBackCountersinkCutouts() );
536 if( layerHolesMap.find(
F_Cu ) != layerHolesMap.end() )
543 for(
const OBJECT_2D* hole2d : intersecting )
545 if( object2d_A->Intersects( hole2d->GetBBox() ) )
546 object2d_B->push_back( hole2d );
550 if( layerHolesMap.find(
B_Cu ) != layerHolesMap.end() )
557 for(
const OBJECT_2D* hole2d : intersecting )
559 if( object2d_A->Intersects( hole2d->GetBBox() ) )
560 object2d_B->push_back( hole2d );
571 for(
const OBJECT_2D* obj : intersecting )
572 object2d_B->push_back( obj );
575 if( object2d_B->empty() )
620 for(
const OBJECT_2D* hole2d : holeList )
630 if( !intersecting.empty() )
634 switch( hole2d->GetObjectType() )
638 const float radius = hole2d->GetBBox().GetExtent().x * 0.5f * 0.999f;
665 if( aStatusReporter )
666 aStatusReporter->
Report(
_(
"Load Raytracing: layers" ) );
669 for(
const std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& entry :
744 else if(
m_boardAdapter.m_Cfg->m_Render.differentiate_plated_copper )
746 layerColor =
SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f, 50.0f / 255.0f );
774 if( !aOnlyLoadCopperAndShapes )
786 for(
const std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& entry :
814 const float zLayerMin =
m_boardAdapter.GetLayerBottomZPos( layer_id );
815 const float zLayerMax =
m_boardAdapter.GetLayerTopZPos( layer_id );
820 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
830 for(
const OBJECT_2D* hole : intersecting )
832 if( object2d_A->Intersects( hole->GetBBox() ) )
833 object2d_B->push_back( hole );
839 if( !container2d->
GetList().empty() )
845 for(
const OBJECT_2D* obj : intersecting )
846 object2d_B->push_back( obj );
849 if( object2d_B->empty() )
859 materialLayer, layerColor );
873 object2d_A->GetBoardItem() );
890#ifdef PRINT_STATISTICS_3D_VIEWER
892 int64_t stats_startLoad3DmodelsTime = stats_endConvertTime;
895 if( aStatusReporter )
896 aStatusReporter->
Report(
_(
"Loading 3D models..." ) );
900#ifdef PRINT_STATISTICS_3D_VIEWER
904 if( !aOnlyLoadCopperAndShapes )
913 boardBBox.
Scale( 3.0f );
919 containerBBox.
Scale( 1.3f );
924 const float minZ = glm::min( containerBBox.
Min().z, boardBBox.
Min().z );
928 +
SFVEC3F( centerBBox.x, centerBBox.y, 0.0f );
932 +
SFVEC3F( centerBBox.x, centerBBox.y, 0.0f );
948 newTriangle1->
SetColor( floorColor );
949 newTriangle2->
SetColor( floorColor );
952 const float maxZ = glm::max( containerBBox.
Max().z, boardBBox.
Max().z );
968 newTriangle3->
SetColor( floorColor );
969 newTriangle4->
SetColor( floorColor );
983 return ( ( aSource.r < ( 1.0f / 255.0f ) ) && ( aSource.g < ( 1.0f / 255.0f ) )
984 && ( aSource.b < ( 1.0f / 255.0f ) ) );
997 if( !IsColorZero( cameraLightColor ) )
1002 if( !IsColorZero( topLightColor ) )
1009 if( !IsColorZero( bottomLightColor ) )
1013 bottomLightColor ) );
1016 for(
size_t i = 0; i <
m_boardAdapter.m_Cfg->m_Render.raytrace_lightColor.size(); ++i )
1021 if( !IsColorZero( lightColor ) )
1042 / -
m_camera.GetCameraInitPos().z );
1044 if( min_zoom > max_zoom )
1045 std::swap( min_zoom, max_zoom );
1047 float zoom_ratio = max_zoom / min_zoom;
1051 steps -=
static_cast<int>( ceil( log( zoom_ratio ) / log( 1.26f ) ) );
1052 steps = std::max( steps, 0 );
1055 float increased_zoom = pow( 1.26f, steps / 2 );
1056 max_zoom *= increased_zoom;
1057 min_zoom /= increased_zoom;
1062 min_zoom = std::min( min_zoom, 1.0f );
1072 if( aStatusReporter )
1075 double calculation_time = (double) (
GetRunningMicroSecs() - stats_startReloadTime ) / 1e6;
1077 aStatusReporter->
Report( wxString::Format(
_(
"Reload time %.3f s" ), calculation_time ) );
1084 float aInnerRadius,
float aDepth,
1085 float aSurfaceZ,
bool aIsFront )
1087 const float platingThickness =
m_boardAdapter.GetHolePlatingThickness()
1090 if( platingThickness <= 0.0f || aInnerRadius <= 0.0f || aDepth <= 0.0f )
1093 const float outerRadius = aInnerRadius + platingThickness;
1094 const float zOther = aIsFront ? ( aSurfaceZ - aDepth ) : ( aSurfaceZ + aDepth );
1095 const float zMin = std::min( aSurfaceZ, zOther );
1096 const float zMax = std::max( aSurfaceZ, zOther );
1098 RING_2D* ring =
new RING_2D( aCenter, aInnerRadius, outerRadius, aSource );
1110 float aTopInnerRadius,
1111 float aBottomInnerRadius,
1112 float aSurfaceZ,
float aDepth,
1115 const float platingThickness =
m_boardAdapter.GetHolePlatingThickness()
1118 if( platingThickness <= 0.0f || aTopInnerRadius <= 0.0f || aBottomInnerRadius <= 0.0f
1124 const float topOuterRadius = aTopInnerRadius + platingThickness;
1125 const float bottomOuterRadius = aBottomInnerRadius + platingThickness;
1127 const float zOther = aIsFront ? ( aSurfaceZ - aDepth ) : ( aSurfaceZ + aDepth );
1128 const float zTop = std::max( aSurfaceZ, zOther );
1129 const float zBot = std::min( aSurfaceZ, zOther );
1131 if( topOuterRadius <= 0.0f || bottomOuterRadius <= 0.0f )
1134 const float largestDiameter = 2.0f * std::max( aTopInnerRadius, aBottomInnerRadius );
1135 unsigned int segments = std::max( 12u,
m_boardAdapter.GetCircleSegmentCount( largestDiameter ) );
1154 auto makePoint = [&](
float radius,
float angle,
float z )
1157 aCenter.y + sinf( angle ) *
radius,
1161 const float step = 2.0f * glm::pi<float>() / (float) segments;
1163 SFVEC3F innerTopPrev = makePoint( aTopInnerRadius, 0.0f, zTop );
1164 SFVEC3F innerBotPrev = makePoint( aBottomInnerRadius, 0.0f, zBot );
1165 SFVEC3F outerTopPrev = makePoint( topOuterRadius, 0.0f, zTop );
1166 SFVEC3F outerBotPrev = makePoint( bottomOuterRadius, 0.0f, zBot );
1168 const SFVEC3F innerTopFirst = innerTopPrev;
1169 const SFVEC3F innerBotFirst = innerBotPrev;
1170 const SFVEC3F outerTopFirst = outerTopPrev;
1171 const SFVEC3F outerBotFirst = outerBotPrev;
1173 for(
unsigned int i = 1; i <= segments; ++i )
1175 const float angle = ( i == segments ) ? 0.0f : step * i;
1177 const SFVEC3F innerTopCurr = ( i == segments ) ? innerTopFirst
1178 : makePoint( aTopInnerRadius, angle, zTop );
1179 const SFVEC3F innerBotCurr = ( i == segments ) ? innerBotFirst
1180 : makePoint( aBottomInnerRadius, angle, zBot );
1181 const SFVEC3F outerTopCurr = ( i == segments ) ? outerTopFirst
1182 : makePoint( topOuterRadius, angle, zTop );
1183 const SFVEC3F outerBotCurr = ( i == segments ) ? outerBotFirst
1184 : makePoint( bottomOuterRadius, angle, zBot );
1187 addQuad( innerTopPrev, innerTopCurr, innerBotCurr, innerBotPrev );
1190 addQuad( outerTopPrev, outerBotPrev, outerBotCurr, outerTopCurr );
1193 addQuad( outerTopPrev, outerTopCurr, innerTopCurr, innerTopPrev );
1196 addQuad( outerBotPrev, innerBotPrev, innerBotCurr, outerBotCurr );
1198 innerTopPrev = innerTopCurr;
1199 innerBotPrev = innerBotCurr;
1200 outerTopPrev = outerTopCurr;
1201 outerBotPrev = outerBotCurr;
1212 const int platingThickness =
m_boardAdapter.GetHolePlatingThickness();
1213 const float platingThickness3d = platingThickness * unitScale;
1227 const float holeDiameter =
via->GetDrillValue() * unitScale;
1228 const float holeInnerRadius = holeDiameter / 2.0f;
1229 const float holeOuterRadius = holeInnerRadius + platingThickness3d;
1233 via->LayerPair( &topLayer, &bottomLayer );
1235 const float viaZTop =
m_boardAdapter.GetLayerBottomZPos( topLayer );
1236 const float viaZBot =
m_boardAdapter.GetLayerBottomZPos( bottomLayer );
1239 const auto secondaryDrillSize =
via->GetSecondaryDrillSize();
1241 if( secondaryDrillSize.has_value() && secondaryDrillSize.value() > 0 )
1243 const float backdrillRadius = secondaryDrillSize.value() * 0.5f * unitScale;
1245 if( backdrillRadius > holeOuterRadius )
1251 const float secEndZ =
m_boardAdapter.GetLayerBottomZPos( secEnd );
1253 float plugZTop, plugZBot;
1255 if( secStart ==
F_Cu )
1268 if( plugZTop > plugZBot )
1283 const auto frontMode =
via->GetFrontPostMachining();
1285 if( frontMode.has_value()
1289 const float frontRadius =
via->GetFrontPostMachiningSize() * 0.5f * unitScale;
1290 const float frontDepth =
via->GetFrontPostMachiningDepth() * unitScale;
1292 if( frontRadius > holeOuterRadius && frontDepth > 0 )
1295 const float pmBottomZ = viaZTop - frontDepth;
1296 const float plugZBot = viaZBot;
1298 if( pmBottomZ > plugZBot )
1305 if( angleRad < 0.01f )
1308 float radialDiff = frontRadius - holeOuterRadius;
1309 float innerHeight = radialDiff / tanf( angleRad );
1310 float totalHeight = pmBottomZ - plugZBot;
1312 if( innerHeight > totalHeight )
1313 innerHeight = totalHeight;
1315 float zInnerTop = plugZBot + innerHeight;
1319 holeOuterRadius, frontRadius );
1325 if( zInnerTop > plugZBot )
1351 const auto backMode =
via->GetBackPostMachining();
1353 if( backMode.has_value()
1357 const float backRadius =
via->GetBackPostMachiningSize() * 0.5f * unitScale;
1358 const float backDepth =
via->GetBackPostMachiningDepth() * unitScale;
1360 if( backRadius > holeOuterRadius && backDepth > 0 )
1363 const float plugZTop = viaZTop;
1364 const float pmTopZ = viaZBot + backDepth;
1366 if( plugZTop > pmTopZ )
1373 if( angleRad < 0.01f )
1376 float radialDiff = backRadius - holeOuterRadius;
1377 float innerHeight = radialDiff / tanf( angleRad );
1378 float totalHeight = plugZTop - pmTopZ;
1380 if( innerHeight > totalHeight )
1381 innerHeight = totalHeight;
1383 float zInnerBot = plugZTop - innerHeight;
1387 backRadius, holeOuterRadius );
1393 if( zInnerBot < plugZTop )
1422 for(
const PAD*
pad : footprint->Pads() )
1427 if( !
pad->HasHole() )
1433 const SFVEC2F padCenter(
pad->GetPosition().x * unitScale,
1434 -
pad->GetPosition().y * unitScale );
1435 const float holeInnerRadius =
pad->GetDrillSize().x * 0.5f * unitScale;
1436 const float holeOuterRadius = holeInnerRadius + platingThickness3d;
1438 const float padZTop = boardZTop;
1439 const float padZBot = boardZBot;
1442 const auto frontMode =
pad->GetFrontPostMachining();
1444 if( frontMode.has_value()
1448 const float frontRadius =
pad->GetFrontPostMachiningSize() * 0.5f * unitScale;
1449 const float frontDepth =
pad->GetFrontPostMachiningDepth() * unitScale;
1451 if( frontRadius > holeOuterRadius && frontDepth > 0 )
1453 const float pmBottomZ = padZTop - frontDepth;
1454 const float plugZBot = padZBot;
1456 if( pmBottomZ > plugZBot )
1463 if( angleRad < 0.01f )
1466 float radialDiff = frontRadius - holeOuterRadius;
1467 float innerHeight = radialDiff / tanf( angleRad );
1468 float totalHeight = pmBottomZ - plugZBot;
1470 if( innerHeight > totalHeight )
1471 innerHeight = totalHeight;
1473 float zInnerTop = plugZBot + innerHeight;
1477 holeOuterRadius, frontRadius );
1483 if( zInnerTop > plugZBot )
1509 const auto backMode =
pad->GetBackPostMachining();
1511 if( backMode.has_value()
1515 const float backRadius =
pad->GetBackPostMachiningSize() * 0.5f * unitScale;
1516 const float backDepth =
pad->GetBackPostMachiningDepth() * unitScale;
1518 if( backRadius > holeOuterRadius && backDepth > 0 )
1520 const float plugZTop = padZTop;
1521 const float pmTopZ = padZBot + backDepth;
1523 if( plugZTop > pmTopZ )
1530 if( angleRad < 0.01f )
1533 float radialDiff = backRadius - holeOuterRadius;
1534 float innerHeight = radialDiff / tanf( angleRad );
1535 float totalHeight = plugZTop - pmTopZ;
1537 if( innerHeight > totalHeight )
1538 innerHeight = totalHeight;
1540 float zInnerBot = plugZTop - innerHeight;
1544 backRadius, holeOuterRadius );
1550 if( zInnerBot < plugZTop )
1587 aVia->
LayerPair( &top_layer, &bottom_layer );
1589 float frontDepth = 0.0f;
1590 float backDepth = 0.0f;
1608 ( radiusBUI +
m_boardAdapter.GetHolePlatingThickness() ) * unitScale, *aVia );
1619 const float holeInnerRadius = radiusBUI * unitScale;
1620 const float frontSurface = topZ + frontDepth;
1621 const float backSurface = botZ - backDepth;
1627 if( frontDepth > 0.0f && frontRadius > holeInnerRadius )
1644 if( backDepth > 0.0f && backRadius > holeInnerRadius )
1668 const bool hasHole = drillsize.
x && drillsize.
y;
1670 const bool isRoundHole = drillsize.
x == drillsize.
y;
1672 float holeInnerRadius = 0.0f;
1679 float frontDepth = 0.0f;
1680 float backDepth = 0.0f;
1699 int innerRadius = drillsize.
x / 2;
1700 int outerRadius = innerRadius +
m_boardAdapter.GetHolePlatingThickness();
1701 holeInnerRadius = innerRadius * unitScale;
1703 RING_2D* ring =
new RING_2D( holeCenter, innerRadius * unitScale,
1704 outerRadius * unitScale, *aPad );
1715 antiOutlineIntersectionList );
1718 if( !antiOutlineIntersectionList.empty() )
1721 holeCenter, innerRadius * unitScale, *aPad );
1724 holeCenter, outerRadius * unitScale, *aPad );
1725 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
1726 object2d_B->push_back( innerCircle );
1735 object2d_A = itemCSG2d;
1743 if( drillsize.
x > drillsize.
y )
1745 ends_offset.
x = ( drillsize.
x - drillsize.
y ) / 2;
1746 width = drillsize.
y;
1750 ends_offset.
y = ( drillsize.
y - drillsize.
x ) / 2;
1751 width = drillsize.
x;
1761 -start.
y * unitScale ),
1763 -
end.y * unitScale ),
1764 width * unitScale, *aPad );
1768 -start.
y * unitScale ),
1770 -
end.y * unitScale ),
1772 * unitScale, *aPad );
1775 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
1776 object2d_B->push_back( innerSeg );
1784 object2d_A = itemCSG2d;
1789 antiOutlineIntersectionList );
1795 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
1805 for(
const OBJECT_2D* hole2d : intersecting )
1807 if( object2d_A->
Intersects( hole2d->GetBBox() ) )
1808 object2d_B->push_back( hole2d );
1812 for(
const OBJECT_2D* obj : antiOutlineIntersectionList )
1813 object2d_B->push_back( obj );
1815 if( object2d_B->empty() )
1845 if( object2d_A && isRoundHole )
1847 const float frontSurface = topZ + frontDepth;
1848 const float backSurface = botZ - backDepth;
1854 if( frontDepth > 0.0f && frontRadius > holeInnerRadius )
1872 if( backDepth > 0.0f && backRadius > holeInnerRadius )
1909 for(
PAD*
pad : footprint->Pads() )
1919 const glm::mat4& aFpMatrix,
bool aHasExtrudedBody )
1921 if( aHasExtrudedBody )
1928 float scaleZ = std::min( bboxW, bboxH ) * 0.5f;
1931 float offsetX = localCenter.
x /
pcbIUScale.IU_PER_MM;
1932 float offsetY = -localCenter.
y /
pcbIUScale.IU_PER_MM;
1937 SFVEC3F boxMin( offsetX - bboxW * 0.5f, offsetY - bboxH * 0.5f, 0.0f );
1938 SFVEC3F boxMax( offsetX + bboxW * 0.5f, offsetY + bboxH * 0.5f, scaleZ );
1943 for(
int i = 0; i < 8; ++i )
1945 SFVEC3F corner( ( i & 1 ) ? boxMax.x : boxMin.x, ( i & 2 ) ? boxMax.y : boxMin.y,
1946 ( i & 4 ) ? boxMax.z : boxMin.z );
1948 glm::vec4 transformed = aFpMatrix * glm::vec4( corner, 1.0f );
1957 aDstContainer.
Add( placeholder );
1970 if(
chain.PointCount() < 3 )
1977 for(
int i = 0; i <
chain.PointCount(); i++ )
1980 SFVEC2F pt( (
float) a.
x * aBiuTo3d, (
float) ( -a.
y ) * aBiuTo3d );
1982 if( ( i == 0 ) || ( fabs( prevPt.x - pt.x ) > FLT_EPSILON ) || ( fabs( prevPt.y - pt.y ) > FLT_EPSILON ) )
1988 segNormals.push_back( sn );
1993 if( segNormals.size() >= 3 )
1995 std::vector<SFVEC2F> tmpNormals( segNormals.size() );
1996 unsigned int j = segNormals.size() - 1;
1998 for(
unsigned int i = 0; i < segNormals.size(); j = i++ )
2000 SFVEC2F slope = segNormals[j].m_Start - segNormals[i].m_Start;
2001 segNormals[i].m_Precalc_slope = slope;
2002 tmpNormals[i] = glm::normalize(
SFVEC2F( slope.y, -slope.x ) );
2005 j = segNormals.size() - 1;
2007 for(
unsigned int i = 0; i < segNormals.size(); j = i++ )
2009 const SFVEC2F& nBefore = tmpNormals[j];
2010 const SFVEC2F& nCur = tmpNormals[i];
2011 const SFVEC2F& nAfter = tmpNormals[( i + 1 ) % segNormals.size()];
2013 float dotBefore = glm::dot( nBefore, nCur );
2014 float dotAfter = glm::dot( nAfter, nCur );
2016 segNormals[i].m_Normals.m_Start =
2017 ( dotBefore < 0.7f ) ? nCur : glm::normalize( nBefore * dotBefore + nCur );
2018 segNormals[i].m_Normals.m_End = ( dotAfter < 0.7f ) ? nCur : glm::normalize( nAfter * dotAfter + nCur );
2021 SEGMENTS capSegments( segNormals.size() );
2023 for(
unsigned int i = 0; i < segNormals.size(); i++ )
2024 capSegments[i].m_Start = segNormals[i].m_Start;
2026 j = capSegments.size() - 1;
2028 for(
unsigned int i = 0; i < capSegments.size(); j = i++ )
2030 capSegments[i].m_inv_JY_minus_IY = 1.0f / ( capSegments[j].m_Start.y - capSegments[i].m_Start.y );
2031 capSegments[i].m_JX_minus_IX = capSegments[j].m_Start.x - capSegments[i].m_Start.x;
2035 outersAndHoles.
m_Outers.push_back( capSegments );
2037 aObjContainer.
Add(
new POLYGON_2D( segNormals, outersAndHoles, aBoardItem ) );
2043 size_t prevSize = aObjContainer.
GetList().size();
2045 added += aObjContainer.
GetList().size() - prevSize;
2071 float standoff3d = body->
m_standoff * biuTo3d;
2079 zBot = boardSurfaceZ + standoff3d + zOffset3d;
2080 zTop = zBot + bodyThickness;
2084 zTop = boardSurfaceZ - standoff3d - zOffset3d;
2085 zBot = zTop - bodyThickness;
2099 size_t prevCount = objList.size();
2110 auto it = objList.begin();
2111 std::advance( it, prevCount );
2113 for( ; it != objList.end(); ++it )
2119 aDstContainer.
Add( layerItem );
2123 if( standoff3d > 0.0f )
2131 float oppositeSurfaceZ =
m_boardAdapter.GetFootprintZPos( !isBack );
2132 float protrusion = 1.0f *
pcbIUScale.IU_PER_MM * biuTo3d;
2133 float pinZBot, pinZTop;
2137 pinZBot = oppositeSurfaceZ - protrusion;
2138 pinZTop = boardSurfaceZ + standoff3d;
2142 pinZTop = oppositeSurfaceZ + protrusion;
2143 pinZBot = boardSurfaceZ - standoff3d;
2150 size_t prevPinCount = objList.size();
2155 auto pinIt = objList.begin();
2156 std::advance( pinIt, prevPinCount );
2158 for( ; pinIt != objList.end(); ++pinIt )
2164 aDstContainer.
Add( layerItem );
2174 bool aSkipMaterialInformation )
2190 bool hasModels = !fp->Models().empty();
2191 bool showMissing =
m_boardAdapter.m_Cfg->m_Render.show_missing_models;
2194 bool hasExtrudedBody =
false;
2196 if( fp->HasExtrudedBody() && fp->GetExtrudedBody()->m_show &&
m_boardAdapter.IsFootprintShown( fp ) )
2199 if( ( hasModels || showMissing ) &&
m_boardAdapter.IsFootprintShown( fp ) )
2201 double zpos =
m_boardAdapter.GetFootprintZPos( fp->IsFlipped() );
2205 glm::mat4 fpMatrix = glm::mat4( 1.0f );
2207 fpMatrix = glm::translate( fpMatrix,
2212 if( !fp->GetOrientation().IsZero() )
2214 fpMatrix = glm::rotate( fpMatrix, (
float) fp->GetOrientation().AsRadians(),
2215 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
2218 if( fp->IsFlipped() )
2220 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(),
SFVEC3F( 0.0f, 1.0f, 0.0f ) );
2222 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(),
SFVEC3F( 0.0f, 0.0f, 1.0f ) );
2225 const double modelunit_to_3d_units_factor =
2228 fpMatrix = glm::scale(
2229 fpMatrix,
SFVEC3F( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
2230 modelunit_to_3d_units_factor ) );
2235 wxString libraryName = fp->GetFPID().GetLibNickname();
2237 wxString footprintBasePath = wxEmptyString;
2244 std::optional<LIBRARY_TABLE_ROW*> fpRow =
2259 if( !
model.m_Show ||
model.m_Filename.empty() )
2263 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
2264 embeddedFilesStack.push_back( fp->GetEmbeddedFiles() );
2265 embeddedFilesStack.push_back(
m_boardAdapter.GetBoard()->GetEmbeddedFiles() );
2268 std::move( embeddedFilesStack ) );
2273 glm::mat4 modelMatrix = fpMatrix;
2275 modelMatrix = glm::translate( modelMatrix,
2278 modelMatrix = glm::rotate( modelMatrix,
2279 (
float) -(
model.m_Rotation.z / 180.0f ) * glm::pi<float>(),
2280 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
2282 modelMatrix = glm::rotate( modelMatrix,
2283 (
float) -(
model.m_Rotation.y / 180.0f ) * glm::pi<float>(),
2284 SFVEC3F( 0.0f, 1.0f, 0.0f ) );
2286 modelMatrix = glm::rotate( modelMatrix,
2287 (
float) -(
model.m_Rotation.x / 180.0f ) * glm::pi<float>(),
2288 SFVEC3F( 1.0f, 0.0f, 0.0f ) );
2290 modelMatrix = glm::scale( modelMatrix,
2293 addModels( aDstContainer, modelPtr, modelMatrix, (
float)
model.m_Opacity,
2294 aSkipMaterialInformation, fp );
2296 else if( showMissing )
2303 if( !hasModels && showMissing )
2332 for(
unsigned int imat = 0; imat < a3DModel->
m_MaterialsSize; ++imat )
2340 float reflectionFactor = 0.0f;
2342 if( ( material.
m_Shininess - 0.35f ) > FLT_EPSILON )
2344 reflectionFactor = glm::clamp(
2345 glm::sqrt( ( material.
m_Shininess - 0.35f ) ) * 0.40f - 0.05f, 0.0f,
2356 if(
m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
2411 return materialVector;
2416 const glm::mat4& aModelMatrix,
float aFPOpacity,
2417 bool aSkipMaterialInformation,
BOARD_ITEM* aBoardItem )
2420 wxASSERT( a3DModel !=
nullptr );
2422 if( a3DModel ==
nullptr )
2426 wxASSERT( a3DModel->
m_Meshes !=
nullptr );
2430 if( aFPOpacity > 1.0f )
2433 if( aFPOpacity < 0.0f )
2441 if( !aSkipMaterialInformation )
2446 const glm::mat3 normalMatrix = glm::transpose( glm::inverse( glm::mat3( aModelMatrix ) ) );
2448 for(
unsigned int mesh_i = 0; mesh_i < a3DModel->
m_MeshesSize; ++mesh_i )
2465 float fpTransparency;
2468 if( !aSkipMaterialInformation )
2477 for(
unsigned int faceIdx = 0; faceIdx < mesh.
m_FaceIdxSize; faceIdx += 3 )
2479 const unsigned int idx0 = mesh.
m_FaceIdx[faceIdx + 0];
2480 const unsigned int idx1 = mesh.
m_FaceIdx[faceIdx + 1];
2481 const unsigned int idx2 = mesh.
m_FaceIdx[faceIdx + 2];
2499 const SFVEC3F vt0 =
SFVEC3F( aModelMatrix * glm::vec4( v0, 1.0f ) );
2503 const SFVEC3F nt0 = glm::normalize(
SFVEC3F( normalMatrix * n0 ) );
2504 const SFVEC3F nt1 = glm::normalize(
SFVEC3F( normalMatrix * n1 ) );
2505 const SFVEC3F nt2 = glm::normalize(
SFVEC3F( normalMatrix * n2 ) );
2511 aDstContainer.
Add( newTriangle );
2513 if( !aSkipMaterialInformation )
@ NORMAL
Use all material properties from model file.
@ CAD_MODE
Use a gray shading based on diffuse material.
Defines math related functions.
float NextFloatDown(float v)
float NextFloatUp(float v)
Defines math related functions.
float RGBtoGray(const SFVEC3F &aColor)
SFVEC3F MaterialDiffuseToColorCAD(const SFVEC3F &aDiffuseColor)
SFVEC3F SphericalToCartesian(float aInclination, float aAzimuth)
https://en.wikipedia.org/wiki/Spherical_coordinate_system
void ApplyExtrusionTransform(SHAPE_POLY_SET &aOutline, const EXTRUDED_3D_BODY *aBody, const VECTOR2I &aFpPos)
Apply 2D extrusion transforms (rotation, scale, offset) to an outline.
EXTRUSION_MATERIAL_PROPS GetMaterialProps(EXTRUSION_MATERIAL aMaterial, const SFVEC3F &aDiffuse)
bool GetExtrusionPinOutline(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aPinPoly)
Get the pin outline polygons for extruded THT pin rendering.
bool GetExtrusionOutline(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aOutline, PCB_LAYER_ID aLayerOverride)
Get the extrusion outline polygon for a footprint in board coordinates.
BOX2I CalcPlaceholderLocalBox(const FOOTPRINT *aFootprint)
Calculate a local space bounding box for a placeholder 3D model.
constexpr EDA_IU_SCALE pcbIUScale
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.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Information pertinent to a Pcbnew printed circuit board.
constexpr size_type GetWidth() const
constexpr const Vec GetCenter() const
constexpr size_type GetHeight() const
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
void Add(OBJECT_2D *aObject)
const LIST_OBJECT2D & GetList() const
void Add(OBJECT_3D *aObject)
Procedural generation of the copper normals.
void SetColor(SFVEC3F aObjColor)
A light source based only on a directional vector.
A dummy block is used to fill the polygons.
void SetColor(SFVEC3F aObjColor)
static KIGFX::COLOR4D GetDefaultColor(EXTRUSION_MATERIAL aMaterial)
EXTRUSION_MATERIAL m_material
A color representation with 4 components: red, green, blue, alpha.
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Make solid geometry for objects on layers.
void SetColor(SFVEC3F aObjColor)
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
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.
Base material class that can be used to derive other material implementations.
static void SetDefaultReflectionRayCount(unsigned int aCount)
static void SetDefaultRefractionRayCount(unsigned int aCount)
static void SetDefaultRefractionRecursionCount(unsigned int aCount)
void SetGenerator(const MATERIAL_GENERATOR *aGenerator)
float GetTransparency() const
static void SetDefaultReflectionRecursionCount(unsigned int aCount)
static OBJECT_2D_STATS & Instance()
virtual bool Intersects(const BBOX_2D &aBBox) const =0
a.Intersects(b) ⇔ !a.Disjoint(b) ⇔ !(a ∩ b = ∅)
const BBOX_2D & GetBBox() const
const BOARD_ITEM & GetBoardItem() const
OBJECT_2D_TYPE GetObjectType() const
static OBJECT_3D_STATS & Instance()
void SetMaterial(const MATERIAL *aMaterial)
void SetModelTransparency(float aModelTransparency)
void SetBoardItem(BOARD_ITEM *aBoardItem)
POST_MACHINING_PROPS & FrontPostMachining()
POST_MACHINING_PROPS & BackPostMachining()
int GetBackPostMachiningSize() const
const VECTOR2I & GetDrillSize() const
VECTOR2I GetPosition() const override
int GetFrontPostMachiningSize() const
int GetFrontPostMachiningDepth() const
std::optional< PAD_DRILL_POST_MACHINING_MODE > GetFrontPostMachining() const
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
std::optional< PAD_DRILL_POST_MACHINING_MODE > GetBackPostMachining() const
int GetBackPostMachiningDepth() const
const VECTOR2I & GetStart() const
int GetFrontPostMachiningSize() const
const PADSTACK & Padstack() const
std::optional< PAD_DRILL_POST_MACHINING_MODE > GetFrontPostMachining() const
int GetBackPostMachiningSize() const
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
std::optional< PAD_DRILL_POST_MACHINING_MODE > GetBackPostMachining() const
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.
Procedural generation of the shiny plastic normals.
Point light source based on http://ogldev.atspace.co.uk/www/tutorial20/tutorial20....
Represent a sub polygon block.
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
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 addCountersinkPlating(const SFVEC2F &aCenter, float aTopInnerRadius, float aBottomInnerRadius, float aSurfaceZ, float aDepth, bool aIsFront)
BOARD_NORMAL m_boardMaterial
void addPlaceholderToRaytracer(CONTAINER_3D &aDstContainer, const FOOTPRINT *aFootprint, const glm::mat4 &aFpMatrix, bool aHasExtrudedBody=false)
CONTAINER_3D m_objectContainer
std::vector< std::unique_ptr< BLINN_PHONG_MATERIAL > > m_extrusionMaterials
COPPER_NORMAL m_copperMaterial
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
PLASTIC_NORMAL m_plasticMaterial
ACCELERATOR_3D * m_accelerator
void createItemsFromContainer(const BVH_CONTAINER_2D *aContainer2d, PCB_LAYER_ID aLayer_id, const MATERIAL *aMaterialLayer, const SFVEC3F &aLayerColor, float aLayerZOffset)
DIRECTIONAL_LIGHT * m_cameraLight
PLASTIC_SHINE_NORMAL m_shinyPlasticMaterial
unsigned int m_convertedDummyBlockCount
bool addExtrudedBodyToRaytracer(CONTAINER_3D &aDstContainer, const FOOTPRINT *aFootprint)
void backfillPostMachine()
void addCounterborePlating(const BOARD_ITEM &aSource, const SFVEC2F &aCenter, float aInnerRadius, float aDepth, float aSurfaceZ, bool aIsFront)
CONTAINER_2D * m_outlineBoard2dObjects
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)
std::list< LIGHT * > m_lights
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.
unsigned int m_converted2dRoundSegmentCount
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
void SetColor(SFVEC3F aObjColor)
Cache for storing the 3D shapes.
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...
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
int OutlineCount() const
Return the number of outlines in the set.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Procedural generation of the solder mask.
void SetColor(const SFVEC3F &aColor)
A vertical truncated cone with different radii at top and bottom.
void SetColor(SFVEC3F aObjColor)
A plane that is parallel to XY plane.
void SetColor(SFVEC3F aObjColor)
std::list< OBJECT_2D * > LIST_OBJECT2D
std::list< const OBJECT_2D * > CONST_LIST_OBJECT2D
#define UNITS3D_TO_UNITSPCB
Implements a model viewer canvas.
Declaration of the eda_3d_viewer class.
A truncated cone for raytracing, used for countersink visualization.
int MapPCBLayerTo3DLayer(PCB_LAYER_ID aLayer)
@ LAYER_3D_SOLDERMASK_TOP
@ LAYER_3D_SOLDERMASK_BOTTOM
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
PAD_DRILL_POST_MACHINING_MODE
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
static wxColor copperColor(220, 180, 30)
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...
std::vector< SEGMENT_WITH_NORMALS > SEGMENTS_WIDTH_NORMALS
List used to test ray2d intersections.
std::vector< POLYSEGMENT > SEGMENTS
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 size_t addOutlineToRaytracerObjects(CONTAINER_2D &aObjContainer, const SHAPE_POLY_SET &aOutline, float aBiuTo3d, const BOARD_ITEM &aBoardItem)
static float TransparencyControl(float aGrayColorValue, float aTransparency)
Perform an interpolation step to easy control the transparency based on the gray color value and tran...
static float TransparencyControl(float aGrayColorValue, float aTransparency)
Attempt to control the transparency based on the gray value of the color.
SFVEC3F ConvertSRGBToLinear(const SFVEC3F &aSRGBcolor)
std::vector< BLINN_PHONG_MATERIAL > MODEL_MATERIALS
Vector of materials.
const SFVEC2F & Min() const
const SFVEC2F & Max() const
Manage a bounding box defined by two SFVEC3F min max points.
void Union(const SFVEC3F &aPoint)
Recalculate the bounding box adding a point.
SFVEC3F GetCenter() const
Return the center point of the bounding box.
const SFVEC3F & Min() const
Return the minimum vertex pointer.
const SFVEC3F & Max() const
Return the maximum vertex pointer.
void Reset()
Reset the bounding box to zero and de-initialize it.
bool IsInitialized() const
Check if this bounding box is already initialized.
void Scale(float aScale)
Scales a bounding box by its center.
bool clip_silk_on_via_annuli
bool subtract_mask_from_silk
Handle a subset of a polygon.
std::vector< SEGMENTS > m_Outers
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
Store the a model based on meshes and materials.
SMATERIAL * m_Materials
The materials list of this model.
unsigned int m_MeshesSize
Number of meshes in the array.
SMESH * m_Meshes
The meshes list of this model.
unsigned int m_MaterialsSize
Number of materials in the material array.
float m_Transparency
1.0 is completely transparent, 0.0 completely opaque
SFVEC3F m_Diffuse
Default diffuse color if m_Color is NULL.
Per-vertex normal/color/texcoors structure.
unsigned int * m_FaceIdx
Triangle Face Indexes.
SFVEC3F * m_Normals
Vertex normals array.
unsigned int m_MaterialIdx
Material Index to be used in this mesh (must be < m_MaterialsSize )
unsigned int m_VertexSize
Number of vertex in the arrays.
unsigned int m_FaceIdxSize
Number of elements of the m_FaceIdx array.
SFVEC3F * m_Color
Vertex color array, can be NULL.
SFVEC3F * m_Positions
Vertex position array.
const SHAPE_LINE_CHAIN chain
void ConvertPolygonToTriangles(const SHAPE_POLY_SET &aPolyList, CONTAINER_2D_BASE &aDstContainer, float aBiuTo3dUnitsScale, const BOARD_ITEM &aBoardItem)
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.
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
VECTOR2< int32_t > VECTOR2I