62 const float aaa = aTransparency * aTransparency * aTransparency;
65 float ca = 1.0f - aTransparency;
66 ca = 1.00f - 1.05f * ca * ca * ca;
68 return glm::max( glm::min( aGrayColorValue * ca + aaa, 1.0f ), 0.0f );
74#define UNITS3D_TO_UNITSPCB ( pcbIUScale.IU_PER_MM )
85 m_boardAdapter.m_Cfg->m_Render.raytrace_recursivelevel_refractions );
87 m_boardAdapter.m_Cfg->m_Render.raytrace_recursivelevel_reflections );
105 const SFVEC3F copperSpecularLinear =
111 SFVEC3F( 0.0f ), copperSpecularLinear, 0.4f * 128.0f, 0.0f, 0.0f );
118 SFVEC3F( 0.256f, 0.137f, 0.086f ), 0.15f * 128.0f, 0.0f, 0.0f );
130 0.10f * 128.0f, 0.0f, 0.0f );
136 SFVEC3F( 0.0f ),
SFVEC3F( 0.10f ) ), 0.078125f * 128.0f, 0.0f, 0.0f );
142 const float solderMask_gray =
152 const float minSolderMaskShininess = 0.85f * 128.0f;
153 const float maxSolderMaskShininess = 512.0f;
154 const float solderMaskShininess = minSolderMaskShininess
155 + ( maxSolderMaskShininess - minSolderMaskShininess ) * ( 1.0f - solderMask_gray );
158 const float solderMaskReflection = glm::clamp( solderMask_gray * 0.3f, 0.02f, 0.16f );
163 SFVEC3F( glm::clamp( solderMask_gray * 2.0f, 0.30f, 1.0f ) ), solderMaskShininess,
164 solderMask_transparency, solderMaskReflection );
167 m_materials.m_SolderMask.SetRefractionRayCount( 1 );
188 (
SFVEC3F( 1.0f ) - bgTop ) / 3.0f,
189 0.10f * 128.0f, 1.0f, 0.50f );
191 m_materials.m_Floor.SetReflectionRecursionCount( 1 );
196 float aZMin,
float aZMax,
const MATERIAL* aMaterial,
211 aDstContainer.
Add( objPtr );
218 aDstContainer.
Add( objPtr );
230 aDstContainer.
Add( objPtr );
239 aDstContainer.
Add( objPtr );
250 float aLayerZOffset )
252 if( aContainer2d ==
nullptr )
259 if( listObject2d.size() == 0 )
262 for(
const OBJECT_2D* object2d_A : listObject2d )
270 object2d_B =
new std::vector<const OBJECT_2D*>();
280 if( layerHolesMap.find( aLayer_id ) != layerHolesMap.end() )
288 for(
const OBJECT_2D* hole2d : intersecting )
289 object2d_B->push_back( hole2d );
299 if( !throughHoleOuter.
GetList().empty() )
305 for(
const OBJECT_2D* hole2d : intersecting )
306 object2d_B->push_back( hole2d );
311 auto clipCutouts = [
this, &object2d_A, &object2d_B](
const BVH_CONTAINER_2D& cutouts )
313 if( !cutouts.GetList().empty() )
316 cutouts.GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
318 for(
const OBJECT_2D* cutout : intersecting )
319 object2d_B->push_back( cutout );
323 if( aLayer_id ==
F_Cu )
329 else if( aLayer_id ==
B_Cu )
344 for(
const OBJECT_2D* obj : intersecting )
345 object2d_B->push_back( obj );
351 && ( ( aLayer_id ==
B_SilkS && mapLayers.find(
B_Mask ) != mapLayers.end() )
352 || ( aLayer_id ==
F_SilkS && mapLayers.find(
F_Mask ) != mapLayers.end() ) ) )
360 if( containerMaskLayer2d )
363 for(
const OBJECT_2D* obj2d : intersecting )
364 object2d_B->push_back( obj2d );
367 if( object2d_B->empty() )
405 bool aOnlyLoadCopperAndShapes )
416 if( !aOnlyLoadCopperAndShapes )
421 m_camera.SetBoardLookAtPos( camera_pos );
430 if( aStatusReporter )
431 aStatusReporter->
Report(
_(
"Load Raytracing: board" ) );
440 std::bitset<LAYER_3D_END> layerFlags =
m_boardAdapter.GetVisibleLayers();
442 if( !aOnlyLoadCopperAndShapes )
444 const int outlineCount =
m_boardAdapter.GetBoardPoly().OutlineCount();
446 if( outlineCount > 0 )
448 float divFactor = 0.0f;
465 for(
int ii = 0; ii < antiboardPoly.
OutlineCount(); ii++ )
476 for(
int ii = 0; ii < boardPolyCopy.
OutlineCount(); ii++ )
487 for(
const OBJECT_2D* object2d_A : listObjects )
489 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
499 for(
const OBJECT_2D* hole : intersecting )
501 if( object2d_A->Intersects( hole->GetBBox() ) )
502 object2d_B->push_back( hole );
507 auto addCutoutsFromContainer =
510 if( !aContainer.GetList().empty() )
513 aContainer.GetIntersectingObjects( object2d_A->GetBBox(),
516 for(
const OBJECT_2D* cutout : intersecting )
518 if( object2d_A->Intersects( cutout->GetBBox() ) )
519 object2d_B->push_back( cutout );
524 addCutoutsFromContainer(
m_boardAdapter.GetFrontCounterboreCutouts() );
525 addCutoutsFromContainer(
m_boardAdapter.GetBackCounterboreCutouts() );
526 addCutoutsFromContainer(
m_boardAdapter.GetFrontCountersinkCutouts() );
527 addCutoutsFromContainer(
m_boardAdapter.GetBackCountersinkCutouts() );
532 if( layerHolesMap.find(
F_Cu ) != layerHolesMap.end() )
539 for(
const OBJECT_2D* hole2d : intersecting )
541 if( object2d_A->Intersects( hole2d->GetBBox() ) )
542 object2d_B->push_back( hole2d );
546 if( layerHolesMap.find(
B_Cu ) != layerHolesMap.end() )
553 for(
const OBJECT_2D* hole2d : intersecting )
555 if( object2d_A->Intersects( hole2d->GetBBox() ) )
556 object2d_B->push_back( hole2d );
567 for(
const OBJECT_2D* obj : intersecting )
568 object2d_B->push_back( obj );
571 if( object2d_B->empty() )
616 for(
const OBJECT_2D* hole2d : holeList )
626 if( !intersecting.empty() )
630 switch( hole2d->GetObjectType() )
634 const float radius = hole2d->GetBBox().GetExtent().x * 0.5f * 0.999f;
661 if( aStatusReporter )
662 aStatusReporter->
Report(
_(
"Load Raytracing: layers" ) );
665 for(
const std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& entry :
740 else if(
m_boardAdapter.m_Cfg->m_Render.differentiate_plated_copper )
742 layerColor =
SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f, 50.0f / 255.0f );
770 if( !aOnlyLoadCopperAndShapes )
782 for(
const std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& entry :
810 const float zLayerMin =
m_boardAdapter.GetLayerBottomZPos( layer_id );
811 const float zLayerMax =
m_boardAdapter.GetLayerTopZPos( layer_id );
816 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
826 for(
const OBJECT_2D* hole : intersecting )
828 if( object2d_A->Intersects( hole->GetBBox() ) )
829 object2d_B->push_back( hole );
835 if( !container2d->
GetList().empty() )
841 for(
const OBJECT_2D* obj : intersecting )
842 object2d_B->push_back( obj );
845 if( object2d_B->empty() )
855 materialLayer, layerColor );
869 object2d_A->GetBoardItem() );
886#ifdef PRINT_STATISTICS_3D_VIEWER
888 int64_t stats_startLoad3DmodelsTime = stats_endConvertTime;
891 if( aStatusReporter )
892 aStatusReporter->
Report(
_(
"Loading 3D models..." ) );
896#ifdef PRINT_STATISTICS_3D_VIEWER
900 if( !aOnlyLoadCopperAndShapes )
909 boardBBox.
Scale( 3.0f );
915 containerBBox.
Scale( 1.3f );
920 const float minZ = glm::min( containerBBox.
Min().z, boardBBox.
Min().z );
924 +
SFVEC3F( centerBBox.x, centerBBox.y, 0.0f );
928 +
SFVEC3F( centerBBox.x, centerBBox.y, 0.0f );
944 newTriangle1->
SetColor( floorColor );
945 newTriangle2->
SetColor( floorColor );
948 const float maxZ = glm::max( containerBBox.
Max().z, boardBBox.
Max().z );
964 newTriangle3->
SetColor( floorColor );
965 newTriangle4->
SetColor( floorColor );
979 return ( ( aSource.r < ( 1.0f / 255.0f ) ) && ( aSource.g < ( 1.0f / 255.0f ) )
980 && ( aSource.b < ( 1.0f / 255.0f ) ) );
993 if( !IsColorZero( cameraLightColor ) )
998 if( !IsColorZero( topLightColor ) )
1005 if( !IsColorZero( bottomLightColor ) )
1009 bottomLightColor ) );
1012 for(
size_t i = 0; i <
m_boardAdapter.m_Cfg->m_Render.raytrace_lightColor.size(); ++i )
1017 if( !IsColorZero( lightColor ) )
1038 / -
m_camera.GetCameraInitPos().z );
1040 if( min_zoom > max_zoom )
1041 std::swap( min_zoom, max_zoom );
1043 float zoom_ratio = max_zoom / min_zoom;
1047 steps -=
static_cast<int>( ceil( log( zoom_ratio ) / log( 1.26f ) ) );
1048 steps = std::max( steps, 0 );
1051 float increased_zoom = pow( 1.26f, steps / 2 );
1052 max_zoom *= increased_zoom;
1053 min_zoom /= increased_zoom;
1058 min_zoom = std::min( min_zoom, 1.0f );
1068 if( aStatusReporter )
1071 double calculation_time = (double) (
GetRunningMicroSecs() - stats_startReloadTime ) / 1e6;
1073 aStatusReporter->
Report( wxString::Format(
_(
"Reload time %.3f s" ), calculation_time ) );
1080 float aInnerRadius,
float aDepth,
1081 float aSurfaceZ,
bool aIsFront )
1083 const float platingThickness =
m_boardAdapter.GetHolePlatingThickness()
1086 if( platingThickness <= 0.0f || aInnerRadius <= 0.0f || aDepth <= 0.0f )
1089 const float outerRadius = aInnerRadius + platingThickness;
1090 const float zOther = aIsFront ? ( aSurfaceZ - aDepth ) : ( aSurfaceZ + aDepth );
1091 const float zMin = std::min( aSurfaceZ, zOther );
1092 const float zMax = std::max( aSurfaceZ, zOther );
1094 RING_2D* ring =
new RING_2D( aCenter, aInnerRadius, outerRadius, aSource );
1106 float aTopInnerRadius,
1107 float aBottomInnerRadius,
1108 float aSurfaceZ,
float aDepth,
1111 const float platingThickness =
m_boardAdapter.GetHolePlatingThickness()
1114 if( platingThickness <= 0.0f || aTopInnerRadius <= 0.0f || aBottomInnerRadius <= 0.0f
1120 const float topOuterRadius = aTopInnerRadius + platingThickness;
1121 const float bottomOuterRadius = aBottomInnerRadius + platingThickness;
1123 const float zOther = aIsFront ? ( aSurfaceZ - aDepth ) : ( aSurfaceZ + aDepth );
1124 const float zTop = std::max( aSurfaceZ, zOther );
1125 const float zBot = std::min( aSurfaceZ, zOther );
1127 if( topOuterRadius <= 0.0f || bottomOuterRadius <= 0.0f )
1130 const float largestDiameter = 2.0f * std::max( aTopInnerRadius, aBottomInnerRadius );
1131 unsigned int segments = std::max( 12u,
m_boardAdapter.GetCircleSegmentCount( largestDiameter ) );
1150 auto makePoint = [&](
float radius,
float angle,
float z )
1153 aCenter.y + sinf( angle ) *
radius,
1157 const float step = 2.0f * glm::pi<float>() / (float) segments;
1159 SFVEC3F innerTopPrev = makePoint( aTopInnerRadius, 0.0f, zTop );
1160 SFVEC3F innerBotPrev = makePoint( aBottomInnerRadius, 0.0f, zBot );
1161 SFVEC3F outerTopPrev = makePoint( topOuterRadius, 0.0f, zTop );
1162 SFVEC3F outerBotPrev = makePoint( bottomOuterRadius, 0.0f, zBot );
1164 const SFVEC3F innerTopFirst = innerTopPrev;
1165 const SFVEC3F innerBotFirst = innerBotPrev;
1166 const SFVEC3F outerTopFirst = outerTopPrev;
1167 const SFVEC3F outerBotFirst = outerBotPrev;
1169 for(
unsigned int i = 1; i <= segments; ++i )
1171 const float angle = ( i == segments ) ? 0.0f : step * i;
1173 const SFVEC3F innerTopCurr = ( i == segments ) ? innerTopFirst
1174 : makePoint( aTopInnerRadius, angle, zTop );
1175 const SFVEC3F innerBotCurr = ( i == segments ) ? innerBotFirst
1176 : makePoint( aBottomInnerRadius, angle, zBot );
1177 const SFVEC3F outerTopCurr = ( i == segments ) ? outerTopFirst
1178 : makePoint( topOuterRadius, angle, zTop );
1179 const SFVEC3F outerBotCurr = ( i == segments ) ? outerBotFirst
1180 : makePoint( bottomOuterRadius, angle, zBot );
1183 addQuad( innerTopPrev, innerTopCurr, innerBotCurr, innerBotPrev );
1186 addQuad( outerTopPrev, outerBotPrev, outerBotCurr, outerTopCurr );
1189 addQuad( outerTopPrev, outerTopCurr, innerTopCurr, innerTopPrev );
1192 addQuad( outerBotPrev, innerBotPrev, innerBotCurr, outerBotCurr );
1194 innerTopPrev = innerTopCurr;
1195 innerBotPrev = innerBotCurr;
1196 outerTopPrev = outerTopCurr;
1197 outerBotPrev = outerBotCurr;
1208 const int platingThickness =
m_boardAdapter.GetHolePlatingThickness();
1209 const float platingThickness3d = platingThickness * unitScale;
1223 const float holeDiameter =
via->GetDrillValue() * unitScale;
1224 const float holeInnerRadius = holeDiameter / 2.0f;
1225 const float holeOuterRadius = holeInnerRadius + platingThickness3d;
1229 via->LayerPair( &topLayer, &bottomLayer );
1231 const float viaZTop =
m_boardAdapter.GetLayerBottomZPos( topLayer );
1232 const float viaZBot =
m_boardAdapter.GetLayerBottomZPos( bottomLayer );
1235 const auto secondaryDrillSize =
via->GetSecondaryDrillSize();
1237 if( secondaryDrillSize.has_value() && secondaryDrillSize.value() > 0 )
1239 const float backdrillRadius = secondaryDrillSize.value() * 0.5f * unitScale;
1241 if( backdrillRadius > holeOuterRadius )
1247 const float secEndZ =
m_boardAdapter.GetLayerBottomZPos( secEnd );
1249 float plugZTop, plugZBot;
1251 if( secStart ==
F_Cu )
1264 if( plugZTop > plugZBot )
1279 const auto frontMode =
via->GetFrontPostMachining();
1281 if( frontMode.has_value()
1285 const float frontRadius =
via->GetFrontPostMachiningSize() * 0.5f * unitScale;
1286 const float frontDepth =
via->GetFrontPostMachiningDepth() * unitScale;
1288 if( frontRadius > holeOuterRadius && frontDepth > 0 )
1291 const float pmBottomZ = viaZTop - frontDepth;
1292 const float plugZBot = viaZBot;
1294 if( pmBottomZ > plugZBot )
1301 if( angleRad < 0.01f )
1304 float radialDiff = frontRadius - holeOuterRadius;
1305 float innerHeight = radialDiff / tanf( angleRad );
1306 float totalHeight = pmBottomZ - plugZBot;
1308 if( innerHeight > totalHeight )
1309 innerHeight = totalHeight;
1311 float zInnerTop = plugZBot + innerHeight;
1315 holeOuterRadius, frontRadius );
1321 if( zInnerTop > plugZBot )
1347 const auto backMode =
via->GetBackPostMachining();
1349 if( backMode.has_value()
1353 const float backRadius =
via->GetBackPostMachiningSize() * 0.5f * unitScale;
1354 const float backDepth =
via->GetBackPostMachiningDepth() * unitScale;
1356 if( backRadius > holeOuterRadius && backDepth > 0 )
1359 const float plugZTop = viaZTop;
1360 const float pmTopZ = viaZBot + backDepth;
1362 if( plugZTop > pmTopZ )
1369 if( angleRad < 0.01f )
1372 float radialDiff = backRadius - holeOuterRadius;
1373 float innerHeight = radialDiff / tanf( angleRad );
1374 float totalHeight = plugZTop - pmTopZ;
1376 if( innerHeight > totalHeight )
1377 innerHeight = totalHeight;
1379 float zInnerBot = plugZTop - innerHeight;
1383 backRadius, holeOuterRadius );
1389 if( zInnerBot < plugZTop )
1418 for(
const PAD*
pad : footprint->Pads() )
1423 if( !
pad->HasHole() )
1429 const SFVEC2F padCenter(
pad->GetPosition().x * unitScale,
1430 -
pad->GetPosition().y * unitScale );
1431 const float holeInnerRadius =
pad->GetDrillSize().x * 0.5f * unitScale;
1432 const float holeOuterRadius = holeInnerRadius + platingThickness3d;
1434 const float padZTop = boardZTop;
1435 const float padZBot = boardZBot;
1438 const auto frontMode =
pad->GetFrontPostMachining();
1440 if( frontMode.has_value()
1444 const float frontRadius =
pad->GetFrontPostMachiningSize() * 0.5f * unitScale;
1445 const float frontDepth =
pad->GetFrontPostMachiningDepth() * unitScale;
1447 if( frontRadius > holeOuterRadius && frontDepth > 0 )
1449 const float pmBottomZ = padZTop - frontDepth;
1450 const float plugZBot = padZBot;
1452 if( pmBottomZ > plugZBot )
1459 if( angleRad < 0.01f )
1462 float radialDiff = frontRadius - holeOuterRadius;
1463 float innerHeight = radialDiff / tanf( angleRad );
1464 float totalHeight = pmBottomZ - plugZBot;
1466 if( innerHeight > totalHeight )
1467 innerHeight = totalHeight;
1469 float zInnerTop = plugZBot + innerHeight;
1473 holeOuterRadius, frontRadius );
1479 if( zInnerTop > plugZBot )
1505 const auto backMode =
pad->GetBackPostMachining();
1507 if( backMode.has_value()
1511 const float backRadius =
pad->GetBackPostMachiningSize() * 0.5f * unitScale;
1512 const float backDepth =
pad->GetBackPostMachiningDepth() * unitScale;
1514 if( backRadius > holeOuterRadius && backDepth > 0 )
1516 const float plugZTop = padZTop;
1517 const float pmTopZ = padZBot + backDepth;
1519 if( plugZTop > pmTopZ )
1526 if( angleRad < 0.01f )
1529 float radialDiff = backRadius - holeOuterRadius;
1530 float innerHeight = radialDiff / tanf( angleRad );
1531 float totalHeight = plugZTop - pmTopZ;
1533 if( innerHeight > totalHeight )
1534 innerHeight = totalHeight;
1536 float zInnerBot = plugZTop - innerHeight;
1540 backRadius, holeOuterRadius );
1546 if( zInnerBot < plugZTop )
1583 aVia->
LayerPair( &top_layer, &bottom_layer );
1585 float frontDepth = 0.0f;
1586 float backDepth = 0.0f;
1604 ( radiusBUI +
m_boardAdapter.GetHolePlatingThickness() ) * unitScale, *aVia );
1615 const float holeInnerRadius = radiusBUI * unitScale;
1616 const float frontSurface = topZ + frontDepth;
1617 const float backSurface = botZ - backDepth;
1623 if( frontDepth > 0.0f && frontRadius > holeInnerRadius )
1640 if( backDepth > 0.0f && backRadius > holeInnerRadius )
1664 const bool hasHole = drillsize.
x && drillsize.
y;
1666 const bool isRoundHole = drillsize.
x == drillsize.
y;
1668 float holeInnerRadius = 0.0f;
1675 float frontDepth = 0.0f;
1676 float backDepth = 0.0f;
1695 int innerRadius = drillsize.
x / 2;
1696 int outerRadius = innerRadius +
m_boardAdapter.GetHolePlatingThickness();
1697 holeInnerRadius = innerRadius * unitScale;
1699 RING_2D* ring =
new RING_2D( holeCenter, innerRadius * unitScale,
1700 outerRadius * unitScale, *aPad );
1711 antiOutlineIntersectionList );
1714 if( !antiOutlineIntersectionList.empty() )
1717 holeCenter, innerRadius * unitScale, *aPad );
1720 holeCenter, outerRadius * unitScale, *aPad );
1721 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
1722 object2d_B->push_back( innerCircle );
1731 object2d_A = itemCSG2d;
1739 if( drillsize.
x > drillsize.
y )
1741 ends_offset.
x = ( drillsize.
x - drillsize.
y ) / 2;
1742 width = drillsize.
y;
1746 ends_offset.
y = ( drillsize.
y - drillsize.
x ) / 2;
1747 width = drillsize.
x;
1757 -start.
y * unitScale ),
1759 -
end.y * unitScale ),
1760 width * unitScale, *aPad );
1764 -start.
y * unitScale ),
1766 -
end.y * unitScale ),
1768 * unitScale, *aPad );
1771 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
1772 object2d_B->push_back( innerSeg );
1780 object2d_A = itemCSG2d;
1785 antiOutlineIntersectionList );
1791 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
1801 for(
const OBJECT_2D* hole2d : intersecting )
1803 if( object2d_A->
Intersects( hole2d->GetBBox() ) )
1804 object2d_B->push_back( hole2d );
1808 for(
const OBJECT_2D* obj : antiOutlineIntersectionList )
1809 object2d_B->push_back( obj );
1811 if( object2d_B->empty() )
1841 if( object2d_A && isRoundHole )
1843 const float frontSurface = topZ + frontDepth;
1844 const float backSurface = botZ - backDepth;
1850 if( frontDepth > 0.0f && frontRadius > holeInnerRadius )
1868 if( backDepth > 0.0f && backRadius > holeInnerRadius )
1905 for(
PAD*
pad : footprint->Pads() )
1915 const glm::mat4& aFpMatrix,
bool aHasExtrudedBody )
1917 if( aHasExtrudedBody )
1924 float scaleZ = std::min( bboxW, bboxH ) * 0.5f;
1927 float offsetX = localCenter.
x /
pcbIUScale.IU_PER_MM;
1928 float offsetY = -localCenter.
y /
pcbIUScale.IU_PER_MM;
1933 SFVEC3F boxMin( offsetX - bboxW * 0.5f, offsetY - bboxH * 0.5f, 0.0f );
1934 SFVEC3F boxMax( offsetX + bboxW * 0.5f, offsetY + bboxH * 0.5f, scaleZ );
1939 for(
int i = 0; i < 8; ++i )
1941 SFVEC3F corner( ( i & 1 ) ? boxMax.x : boxMin.x, ( i & 2 ) ? boxMax.y : boxMin.y,
1942 ( i & 4 ) ? boxMax.z : boxMin.z );
1944 glm::vec4 transformed = aFpMatrix * glm::vec4( corner, 1.0f );
1953 aDstContainer.
Add( placeholder );
1966 if(
chain.PointCount() < 3 )
1973 for(
int i = 0; i <
chain.PointCount(); i++ )
1976 SFVEC2F pt( (
float) a.
x * aBiuTo3d, (
float) ( -a.
y ) * aBiuTo3d );
1978 if( ( i == 0 ) || ( fabs( prevPt.x - pt.x ) > FLT_EPSILON ) || ( fabs( prevPt.y - pt.y ) > FLT_EPSILON ) )
1984 segNormals.push_back( sn );
1989 if( segNormals.size() >= 3 )
1991 std::vector<SFVEC2F> tmpNormals( segNormals.size() );
1992 unsigned int j = segNormals.size() - 1;
1994 for(
unsigned int i = 0; i < segNormals.size(); j = i++ )
1996 SFVEC2F slope = segNormals[j].m_Start - segNormals[i].m_Start;
1997 segNormals[i].m_Precalc_slope = slope;
1998 tmpNormals[i] = glm::normalize(
SFVEC2F( slope.y, -slope.x ) );
2001 j = segNormals.size() - 1;
2003 for(
unsigned int i = 0; i < segNormals.size(); j = i++ )
2005 const SFVEC2F& nBefore = tmpNormals[j];
2006 const SFVEC2F& nCur = tmpNormals[i];
2007 const SFVEC2F& nAfter = tmpNormals[( i + 1 ) % segNormals.size()];
2009 float dotBefore = glm::dot( nBefore, nCur );
2010 float dotAfter = glm::dot( nAfter, nCur );
2012 segNormals[i].m_Normals.m_Start =
2013 ( dotBefore < 0.7f ) ? nCur : glm::normalize( nBefore * dotBefore + nCur );
2014 segNormals[i].m_Normals.m_End = ( dotAfter < 0.7f ) ? nCur : glm::normalize( nAfter * dotAfter + nCur );
2017 SEGMENTS capSegments( segNormals.size() );
2019 for(
unsigned int i = 0; i < segNormals.size(); i++ )
2020 capSegments[i].m_Start = segNormals[i].m_Start;
2022 j = capSegments.size() - 1;
2024 for(
unsigned int i = 0; i < capSegments.size(); j = i++ )
2026 capSegments[i].m_inv_JY_minus_IY = 1.0f / ( capSegments[j].m_Start.y - capSegments[i].m_Start.y );
2027 capSegments[i].m_JX_minus_IX = capSegments[j].m_Start.x - capSegments[i].m_Start.x;
2031 outersAndHoles.
m_Outers.push_back( capSegments );
2033 aObjContainer.
Add(
new POLYGON_2D( segNormals, outersAndHoles, aBoardItem ) );
2039 size_t prevSize = aObjContainer.
GetList().size();
2041 added += aObjContainer.
GetList().size() - prevSize;
2067 float standoff3d = body->
m_standoff * biuTo3d;
2075 zBot = boardSurfaceZ + standoff3d + zOffset3d;
2076 zTop = zBot + bodyThickness;
2080 zTop = boardSurfaceZ - standoff3d - zOffset3d;
2081 zBot = zTop - bodyThickness;
2095 size_t prevCount = objList.size();
2106 auto it = objList.begin();
2107 std::advance( it, prevCount );
2109 for( ; it != objList.end(); ++it )
2115 aDstContainer.
Add( layerItem );
2119 if( standoff3d > 0.0f )
2127 float oppositeSurfaceZ =
m_boardAdapter.GetFootprintZPos( !isBack );
2128 float protrusion = 1.0f *
pcbIUScale.IU_PER_MM * biuTo3d;
2129 float pinZBot, pinZTop;
2133 pinZBot = oppositeSurfaceZ - protrusion;
2134 pinZTop = boardSurfaceZ + standoff3d;
2138 pinZTop = oppositeSurfaceZ + protrusion;
2139 pinZBot = boardSurfaceZ - standoff3d;
2146 size_t prevPinCount = objList.size();
2151 auto pinIt = objList.begin();
2152 std::advance( pinIt, prevPinCount );
2154 for( ; pinIt != objList.end(); ++pinIt )
2160 aDstContainer.
Add( layerItem );
2170 bool aSkipMaterialInformation )
2186 bool hasModels = !fp->Models().empty();
2187 bool showMissing =
m_boardAdapter.m_Cfg->m_Render.show_missing_models;
2190 bool hasExtrudedBody =
false;
2192 if( fp->HasExtrudedBody() && fp->GetExtrudedBody()->m_show &&
m_boardAdapter.IsFootprintShown( fp ) )
2195 if( ( hasModels || showMissing ) &&
m_boardAdapter.IsFootprintShown( fp ) )
2197 double zpos =
m_boardAdapter.GetFootprintZPos( fp->IsFlipped() );
2201 glm::mat4 fpMatrix = glm::mat4( 1.0f );
2203 fpMatrix = glm::translate( fpMatrix,
2208 if( !fp->GetOrientation().IsZero() )
2210 fpMatrix = glm::rotate( fpMatrix, (
float) fp->GetOrientation().AsRadians(),
2211 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
2214 if( fp->IsFlipped() )
2216 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(),
SFVEC3F( 0.0f, 1.0f, 0.0f ) );
2218 fpMatrix = glm::rotate( fpMatrix, glm::pi<float>(),
SFVEC3F( 0.0f, 0.0f, 1.0f ) );
2221 const double modelunit_to_3d_units_factor =
2224 fpMatrix = glm::scale(
2225 fpMatrix,
SFVEC3F( modelunit_to_3d_units_factor, modelunit_to_3d_units_factor,
2226 modelunit_to_3d_units_factor ) );
2231 wxString libraryName = fp->GetFPID().GetLibNickname();
2233 wxString footprintBasePath = wxEmptyString;
2240 std::optional<LIBRARY_TABLE_ROW*> fpRow =
2255 if( !
model.m_Show ||
model.m_Filename.empty() )
2259 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
2260 embeddedFilesStack.push_back( fp->GetEmbeddedFiles() );
2261 embeddedFilesStack.push_back(
m_boardAdapter.GetBoard()->GetEmbeddedFiles() );
2264 std::move( embeddedFilesStack ) );
2269 glm::mat4 modelMatrix = fpMatrix;
2271 modelMatrix = glm::translate( modelMatrix,
2274 modelMatrix = glm::rotate( modelMatrix,
2275 (
float) -(
model.m_Rotation.z / 180.0f ) * glm::pi<float>(),
2276 SFVEC3F( 0.0f, 0.0f, 1.0f ) );
2278 modelMatrix = glm::rotate( modelMatrix,
2279 (
float) -(
model.m_Rotation.y / 180.0f ) * glm::pi<float>(),
2280 SFVEC3F( 0.0f, 1.0f, 0.0f ) );
2282 modelMatrix = glm::rotate( modelMatrix,
2283 (
float) -(
model.m_Rotation.x / 180.0f ) * glm::pi<float>(),
2284 SFVEC3F( 1.0f, 0.0f, 0.0f ) );
2286 modelMatrix = glm::scale( modelMatrix,
2289 addModels( aDstContainer, modelPtr, modelMatrix, (
float)
model.m_Opacity,
2290 aSkipMaterialInformation, fp );
2292 else if( showMissing )
2299 if( !hasModels && showMissing )
2328 for(
unsigned int imat = 0; imat < a3DModel->
m_MaterialsSize; ++imat )
2336 float reflectionFactor = 0.0f;
2338 if( ( material.
m_Shininess - 0.35f ) > FLT_EPSILON )
2340 reflectionFactor = glm::clamp(
2341 glm::sqrt( ( material.
m_Shininess - 0.35f ) ) * 0.40f - 0.05f, 0.0f,
2352 if(
m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
2407 return materialVector;
2412 const glm::mat4& aModelMatrix,
float aFPOpacity,
2413 bool aSkipMaterialInformation,
BOARD_ITEM* aBoardItem )
2416 wxASSERT( a3DModel !=
nullptr );
2418 if( a3DModel ==
nullptr )
2422 wxASSERT( a3DModel->
m_Meshes !=
nullptr );
2426 if( aFPOpacity > 1.0f )
2429 if( aFPOpacity < 0.0f )
2437 if( !aSkipMaterialInformation )
2442 const glm::mat3 normalMatrix = glm::transpose( glm::inverse( glm::mat3( aModelMatrix ) ) );
2444 for(
unsigned int mesh_i = 0; mesh_i < a3DModel->
m_MeshesSize; ++mesh_i )
2461 float fpTransparency;
2464 if( !aSkipMaterialInformation )
2473 for(
unsigned int faceIdx = 0; faceIdx < mesh.
m_FaceIdxSize; faceIdx += 3 )
2475 const unsigned int idx0 = mesh.
m_FaceIdx[faceIdx + 0];
2476 const unsigned int idx1 = mesh.
m_FaceIdx[faceIdx + 1];
2477 const unsigned int idx2 = mesh.
m_FaceIdx[faceIdx + 2];
2495 const SFVEC3F vt0 =
SFVEC3F( aModelMatrix * glm::vec4( v0, 1.0f ) );
2499 const SFVEC3F nt0 = glm::normalize(
SFVEC3F( normalMatrix * n0 ) );
2500 const SFVEC3F nt1 = glm::normalize(
SFVEC3F( normalMatrix * n1 ) );
2501 const SFVEC3F nt2 = glm::normalize(
SFVEC3F( normalMatrix * n2 ) );
2507 aDstContainer.
Add( newTriangle );
2509 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
VECTOR2I GetPosition() const override
VECTOR2I GetDrillSize() const
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...
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