61 const float aaa = aTransparency * aTransparency * aTransparency;
64 float ca = 1.0f - aTransparency;
65 ca = 1.00f - 1.05f * ca * ca * ca;
67 return glm::max( glm::min( aGrayColorValue * ca + aaa, 1.0f ), 0.0f );
80 m_boardAdapter.m_Cfg->m_Render.raytrace_recursivelevel_refractions );
82 m_boardAdapter.m_Cfg->m_Render.raytrace_recursivelevel_reflections );
100 const SFVEC3F copperSpecularLinear =
106 SFVEC3F( 0.0f ), copperSpecularLinear, 0.4f * 128.0f, 0.0f, 0.0f );
113 SFVEC3F( 0.256f, 0.137f, 0.086f ), 0.15f * 128.0f, 0.0f, 0.0f );
125 0.10f * 128.0f, 0.0f, 0.0f );
131 SFVEC3F( 0.0f ),
SFVEC3F( 0.10f ) ), 0.078125f * 128.0f, 0.0f, 0.0f );
137 const float solderMask_gray =
147 const float minSolderMaskShininess = 0.85f * 128.0f;
148 const float maxSolderMaskShininess = 512.0f;
149 const float solderMaskShininess = minSolderMaskShininess
150 + ( maxSolderMaskShininess - minSolderMaskShininess ) * ( 1.0f - solderMask_gray );
153 const float solderMaskReflection = glm::clamp( solderMask_gray * 0.3f, 0.02f, 0.16f );
158 SFVEC3F( glm::clamp( solderMask_gray * 2.0f, 0.30f, 1.0f ) ), solderMaskShininess,
159 solderMask_transparency, solderMaskReflection );
162 m_materials.m_SolderMask.SetRefractionRayCount( 1 );
183 (
SFVEC3F( 1.0f ) - bgTop ) / 3.0f,
184 0.10f * 128.0f, 1.0f, 0.50f );
186 m_materials.m_Floor.SetReflectionRecursionCount( 1 );
191 float aZMin,
float aZMax,
const MATERIAL* aMaterial,
206 aDstContainer.
Add( objPtr );
213 aDstContainer.
Add( objPtr );
225 aDstContainer.
Add( objPtr );
234 aDstContainer.
Add( objPtr );
245 float aLayerZOffset )
247 if( aContainer2d ==
nullptr )
254 if( listObject2d.size() == 0 )
257 for(
const OBJECT_2D* object2d_A : listObject2d )
265 object2d_B =
new std::vector<const OBJECT_2D*>();
275 if( layerHolesMap.find( aLayer_id ) != layerHolesMap.end() )
283 for(
const OBJECT_2D* hole2d : intersecting )
284 object2d_B->push_back( hole2d );
294 if( !throughHoleOuter.
GetList().empty() )
300 for(
const OBJECT_2D* hole2d : intersecting )
301 object2d_B->push_back( hole2d );
306 auto clipCutouts = [
this, &object2d_A, &object2d_B](
const BVH_CONTAINER_2D& cutouts )
308 if( !cutouts.GetList().empty() )
311 cutouts.GetIntersectingObjects( object2d_A->GetBBox(), intersecting );
313 for(
const OBJECT_2D* cutout : intersecting )
314 object2d_B->push_back( cutout );
318 if( aLayer_id ==
F_Cu )
324 else if( aLayer_id ==
B_Cu )
339 for(
const OBJECT_2D* obj : intersecting )
340 object2d_B->push_back( obj );
346 && ( ( aLayer_id ==
B_SilkS && mapLayers.find(
B_Mask ) != mapLayers.end() )
347 || ( aLayer_id ==
F_SilkS && mapLayers.find(
F_Mask ) != mapLayers.end() ) ) )
355 if( containerMaskLayer2d )
358 for(
const OBJECT_2D* obj2d : intersecting )
359 object2d_B->push_back( obj2d );
362 if( object2d_B->empty() )
410 if( !aOnlyLoadCopperAndShapes )
416 m_camera.SetBoardLookAtPos( camera_pos );
431 if( aStop.stop_requested() )
436 if( aOnlyLoadCopperAndShapes )
449 std::bitset<LAYER_3D_END> layerFlags =
m_boardAdapter.GetVisibleLayers();
451 if( !aOnlyLoadCopperAndShapes )
453 const int outlineCount =
m_boardAdapter.GetBoardPoly().OutlineCount();
455 if( outlineCount > 0 )
457 float divFactor = 0.0f;
474 for(
int ii = 0; ii < antiboardPoly.
OutlineCount(); ii++ )
485 for(
int ii = 0; ii < boardPolyCopy.
OutlineCount(); ii++ )
496 for(
const OBJECT_2D* object2d_A : listObjects )
498 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
508 for(
const OBJECT_2D* hole : intersecting )
510 if( object2d_A->Intersects( hole->GetBBox() ) )
511 object2d_B->push_back( hole );
516 auto addCutoutsFromContainer =
519 if( !aContainer.GetList().empty() )
522 aContainer.GetIntersectingObjects( object2d_A->GetBBox(),
525 for(
const OBJECT_2D* cutout : intersecting )
527 if( object2d_A->Intersects( cutout->GetBBox() ) )
528 object2d_B->push_back( cutout );
533 addCutoutsFromContainer(
m_boardAdapter.GetFrontCounterboreCutouts() );
534 addCutoutsFromContainer(
m_boardAdapter.GetBackCounterboreCutouts() );
535 addCutoutsFromContainer(
m_boardAdapter.GetFrontCountersinkCutouts() );
536 addCutoutsFromContainer(
m_boardAdapter.GetBackCountersinkCutouts() );
541 if( layerHolesMap.find(
F_Cu ) != layerHolesMap.end() )
548 for(
const OBJECT_2D* hole2d : intersecting )
550 if( object2d_A->Intersects( hole2d->GetBBox() ) )
551 object2d_B->push_back( hole2d );
555 if( layerHolesMap.find(
B_Cu ) != layerHolesMap.end() )
562 for(
const OBJECT_2D* hole2d : intersecting )
564 if( object2d_A->Intersects( hole2d->GetBBox() ) )
565 object2d_B->push_back( hole2d );
576 for(
const OBJECT_2D* obj : intersecting )
577 object2d_B->push_back( obj );
580 if( object2d_B->empty() )
625 for(
const OBJECT_2D* hole2d : holeList )
635 if( !intersecting.empty() )
639 switch( hole2d->GetObjectType() )
643 const float radius = hole2d->GetBBox().GetExtent().x * 0.5f * 0.999f;
672 if( aOnlyLoadCopperAndShapes )
679 for(
const std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& entry :
762 else if(
m_boardAdapter.m_Cfg->m_Render.differentiate_plated_copper )
764 layerColor =
SFVEC3F( 184.0f / 255.0f, 115.0f / 255.0f, 50.0f / 255.0f );
779 if( aStop.stop_requested() )
795 if( !aOnlyLoadCopperAndShapes )
807 for(
const std::pair<const PCB_LAYER_ID, BVH_CONTAINER_2D*>& entry :
835 const float zLayerMin =
m_boardAdapter.GetLayerBottomZPos( layer_id );
836 const float zLayerMax =
m_boardAdapter.GetLayerTopZPos( layer_id );
841 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
851 for(
const OBJECT_2D* hole : intersecting )
853 if( object2d_A->Intersects( hole->GetBBox() ) )
854 object2d_B->push_back( hole );
860 if( !container2d->
GetList().empty() )
866 for(
const OBJECT_2D* obj : intersecting )
867 object2d_B->push_back( obj );
870 if( object2d_B->empty() )
880 materialLayer, layerColor );
894 object2d_A->GetBoardItem() );
911#ifdef PRINT_STATISTICS_3D_VIEWER
913 int64_t stats_startLoad3DmodelsTime = stats_endConvertTime;
918 if( aOnlyLoadCopperAndShapes )
926 if( aStop.stop_requested() )
929#ifdef PRINT_STATISTICS_3D_VIEWER
933 if( !aOnlyLoadCopperAndShapes )
942 boardBBox.
Scale( 3.0f );
948 containerBBox.
Scale( 1.3f );
953 const float minZ = glm::min( containerBBox.
Min().z, boardBBox.
Min().z );
957 +
SFVEC3F( centerBBox.x, centerBBox.y, 0.0f );
961 +
SFVEC3F( centerBBox.x, centerBBox.y, 0.0f );
977 newTriangle1->
SetColor( floorColor );
978 newTriangle2->
SetColor( floorColor );
981 const float maxZ = glm::max( containerBBox.
Max().z, boardBBox.
Max().z );
997 newTriangle3->
SetColor( floorColor );
998 newTriangle4->
SetColor( floorColor );
1012 return ( ( aSource.r < ( 1.0f / 255.0f ) ) && ( aSource.g < ( 1.0f / 255.0f ) )
1013 && ( aSource.b < ( 1.0f / 255.0f ) ) );
1026 if( !IsColorZero( cameraLightColor ) )
1031 if( !IsColorZero( topLightColor ) )
1038 if( !IsColorZero( bottomLightColor ) )
1042 bottomLightColor ) );
1045 for(
size_t i = 0; i <
m_boardAdapter.m_Cfg->m_Render.raytrace_lightColor.size(); ++i )
1050 if( !IsColorZero( lightColor ) )
1071 / -
m_camera.GetCameraInitPos().z );
1073 if( min_zoom > max_zoom )
1074 std::swap( min_zoom, max_zoom );
1076 float zoom_ratio = max_zoom / min_zoom;
1080 steps -=
static_cast<int>( ceil( log( zoom_ratio ) / log( 1.26f ) ) );
1081 steps = std::max( steps, 0 );
1084 float increased_zoom = pow( 1.26f, steps / 2 );
1085 max_zoom *= increased_zoom;
1086 min_zoom /= increased_zoom;
1091 min_zoom = std::min( min_zoom, 1.0f );
1097 if( aStop.stop_requested() )
1101 std::unique_ptr<ACCELERATOR_3D> accelerator =
1112 double calculation_time = (double) (
GetRunningMicroSecs() - stats_startReloadTime ) / 1e6;
1114 if( aOnlyLoadCopperAndShapes )
1116 m_activityReporter->Report( wxString::Format(
_(
"Hit-test scene ready in %.3f s" ), calculation_time ) );
1120 m_activityReporter->Report( wxString::Format(
_(
"Reload time %.3f s" ), calculation_time ) );
1128 float aInnerRadius,
float aDepth,
1129 float aSurfaceZ,
bool aIsFront )
1131 const float platingThickness =
m_boardAdapter.GetHolePlatingThickness()
1134 if( platingThickness <= 0.0f || aInnerRadius <= 0.0f || aDepth <= 0.0f )
1137 const float outerRadius = aInnerRadius + platingThickness;
1138 const float zOther = aIsFront ? ( aSurfaceZ - aDepth ) : ( aSurfaceZ + aDepth );
1139 const float zMin = std::min( aSurfaceZ, zOther );
1140 const float zMax = std::max( aSurfaceZ, zOther );
1142 RING_2D* ring =
new RING_2D( aCenter, aInnerRadius, outerRadius, aSource );
1154 float aTopInnerRadius,
1155 float aBottomInnerRadius,
1156 float aSurfaceZ,
float aDepth,
1159 const float platingThickness =
m_boardAdapter.GetHolePlatingThickness()
1162 if( platingThickness <= 0.0f || aTopInnerRadius <= 0.0f || aBottomInnerRadius <= 0.0f
1168 const float topOuterRadius = aTopInnerRadius + platingThickness;
1169 const float bottomOuterRadius = aBottomInnerRadius + platingThickness;
1171 const float zOther = aIsFront ? ( aSurfaceZ - aDepth ) : ( aSurfaceZ + aDepth );
1172 const float zTop = std::max( aSurfaceZ, zOther );
1173 const float zBot = std::min( aSurfaceZ, zOther );
1175 if( topOuterRadius <= 0.0f || bottomOuterRadius <= 0.0f )
1178 const float largestDiameter = 2.0f * std::max( aTopInnerRadius, aBottomInnerRadius );
1179 unsigned int segments = std::max( 12u,
m_boardAdapter.GetCircleSegmentCount( largestDiameter ) );
1198 auto makePoint = [&](
float radius,
float angle,
float z )
1201 aCenter.y + sinf( angle ) *
radius,
1205 const float step = 2.0f * glm::pi<float>() / (float) segments;
1207 SFVEC3F innerTopPrev = makePoint( aTopInnerRadius, 0.0f, zTop );
1208 SFVEC3F innerBotPrev = makePoint( aBottomInnerRadius, 0.0f, zBot );
1209 SFVEC3F outerTopPrev = makePoint( topOuterRadius, 0.0f, zTop );
1210 SFVEC3F outerBotPrev = makePoint( bottomOuterRadius, 0.0f, zBot );
1212 const SFVEC3F innerTopFirst = innerTopPrev;
1213 const SFVEC3F innerBotFirst = innerBotPrev;
1214 const SFVEC3F outerTopFirst = outerTopPrev;
1215 const SFVEC3F outerBotFirst = outerBotPrev;
1217 for(
unsigned int i = 1; i <= segments; ++i )
1219 const float angle = ( i == segments ) ? 0.0f : step * i;
1221 const SFVEC3F innerTopCurr = ( i == segments ) ? innerTopFirst
1222 : makePoint( aTopInnerRadius, angle, zTop );
1223 const SFVEC3F innerBotCurr = ( i == segments ) ? innerBotFirst
1224 : makePoint( aBottomInnerRadius, angle, zBot );
1225 const SFVEC3F outerTopCurr = ( i == segments ) ? outerTopFirst
1226 : makePoint( topOuterRadius, angle, zTop );
1227 const SFVEC3F outerBotCurr = ( i == segments ) ? outerBotFirst
1228 : makePoint( bottomOuterRadius, angle, zBot );
1231 addQuad( innerTopPrev, innerTopCurr, innerBotCurr, innerBotPrev );
1234 addQuad( outerTopPrev, outerBotPrev, outerBotCurr, outerTopCurr );
1237 addQuad( outerTopPrev, outerTopCurr, innerTopCurr, innerTopPrev );
1240 addQuad( outerBotPrev, innerBotPrev, innerBotCurr, outerBotCurr );
1242 innerTopPrev = innerTopCurr;
1243 innerBotPrev = innerBotCurr;
1244 outerTopPrev = outerTopCurr;
1245 outerBotPrev = outerBotCurr;
1256 const int platingThickness =
m_boardAdapter.GetHolePlatingThickness();
1257 const float platingThickness3d = platingThickness * unitScale;
1271 const float holeDiameter =
via->GetDrillValue() * unitScale;
1272 const float holeInnerRadius = holeDiameter / 2.0f;
1273 const float holeOuterRadius = holeInnerRadius + platingThickness3d;
1277 via->LayerPair( &topLayer, &bottomLayer );
1279 const float viaZTop =
m_boardAdapter.GetLayerBottomZPos( topLayer );
1280 const float viaZBot =
m_boardAdapter.GetLayerBottomZPos( bottomLayer );
1283 const auto secondaryDrillSize =
via->GetSecondaryDrillSize();
1285 if( secondaryDrillSize.has_value() && secondaryDrillSize.value() > 0 )
1287 const float backdrillRadius = secondaryDrillSize.value() * 0.5f * unitScale;
1289 if( backdrillRadius > holeOuterRadius )
1295 const float secEndZ =
m_boardAdapter.GetLayerBottomZPos( secEnd );
1297 float plugZTop, plugZBot;
1299 if( secStart ==
F_Cu )
1312 if( plugZTop > plugZBot )
1327 const auto frontMode =
via->GetFrontPostMachining();
1329 if( frontMode.has_value()
1333 const float frontRadius =
via->GetFrontPostMachiningSize() * 0.5f * unitScale;
1334 const float frontDepth =
via->GetFrontPostMachiningDepth() * unitScale;
1336 if( frontRadius > holeOuterRadius && frontDepth > 0 )
1339 const float pmBottomZ = viaZTop - frontDepth;
1340 const float plugZBot = viaZBot;
1342 if( pmBottomZ > plugZBot )
1349 if( angleRad < 0.01f )
1352 float radialDiff = frontRadius - holeOuterRadius;
1353 float innerHeight = radialDiff / tanf( angleRad );
1354 float totalHeight = pmBottomZ - plugZBot;
1356 if( innerHeight > totalHeight )
1357 innerHeight = totalHeight;
1359 float zInnerTop = plugZBot + innerHeight;
1363 holeOuterRadius, frontRadius );
1369 if( zInnerTop > plugZBot )
1395 const auto backMode =
via->GetBackPostMachining();
1397 if( backMode.has_value()
1401 const float backRadius =
via->GetBackPostMachiningSize() * 0.5f * unitScale;
1402 const float backDepth =
via->GetBackPostMachiningDepth() * unitScale;
1404 if( backRadius > holeOuterRadius && backDepth > 0 )
1407 const float plugZTop = viaZTop;
1408 const float pmTopZ = viaZBot + backDepth;
1410 if( plugZTop > pmTopZ )
1417 if( angleRad < 0.01f )
1420 float radialDiff = backRadius - holeOuterRadius;
1421 float innerHeight = radialDiff / tanf( angleRad );
1422 float totalHeight = plugZTop - pmTopZ;
1424 if( innerHeight > totalHeight )
1425 innerHeight = totalHeight;
1427 float zInnerBot = plugZTop - innerHeight;
1431 backRadius, holeOuterRadius );
1437 if( zInnerBot < plugZTop )
1466 for(
const PAD*
pad : footprint->Pads() )
1471 if( !
pad->HasHole() )
1477 const SFVEC2F padCenter(
pad->GetPosition().x * unitScale,
1478 -
pad->GetPosition().y * unitScale );
1479 const float holeInnerRadius =
pad->GetDrillSize().x * 0.5f * unitScale;
1480 const float holeOuterRadius = holeInnerRadius + platingThickness3d;
1482 const float padZTop = boardZTop;
1483 const float padZBot = boardZBot;
1486 const auto frontMode =
pad->GetFrontPostMachining();
1488 if( frontMode.has_value()
1492 const float frontRadius =
pad->GetFrontPostMachiningSize() * 0.5f * unitScale;
1493 const float frontDepth =
pad->GetFrontPostMachiningDepth() * unitScale;
1495 if( frontRadius > holeOuterRadius && frontDepth > 0 )
1497 const float pmBottomZ = padZTop - frontDepth;
1498 const float plugZBot = padZBot;
1500 if( pmBottomZ > plugZBot )
1507 if( angleRad < 0.01f )
1510 float radialDiff = frontRadius - holeOuterRadius;
1511 float innerHeight = radialDiff / tanf( angleRad );
1512 float totalHeight = pmBottomZ - plugZBot;
1514 if( innerHeight > totalHeight )
1515 innerHeight = totalHeight;
1517 float zInnerTop = plugZBot + innerHeight;
1521 holeOuterRadius, frontRadius );
1527 if( zInnerTop > plugZBot )
1553 const auto backMode =
pad->GetBackPostMachining();
1555 if( backMode.has_value()
1559 const float backRadius =
pad->GetBackPostMachiningSize() * 0.5f * unitScale;
1560 const float backDepth =
pad->GetBackPostMachiningDepth() * unitScale;
1562 if( backRadius > holeOuterRadius && backDepth > 0 )
1564 const float plugZTop = padZTop;
1565 const float pmTopZ = padZBot + backDepth;
1567 if( plugZTop > pmTopZ )
1574 if( angleRad < 0.01f )
1577 float radialDiff = backRadius - holeOuterRadius;
1578 float innerHeight = radialDiff / tanf( angleRad );
1579 float totalHeight = plugZTop - pmTopZ;
1581 if( innerHeight > totalHeight )
1582 innerHeight = totalHeight;
1584 float zInnerBot = plugZTop - innerHeight;
1588 backRadius, holeOuterRadius );
1594 if( zInnerBot < plugZTop )
1631 aVia->
LayerPair( &top_layer, &bottom_layer );
1633 float frontDepth = 0.0f;
1634 float backDepth = 0.0f;
1652 ( radiusBUI +
m_boardAdapter.GetHolePlatingThickness() ) * unitScale, *aVia );
1663 const float holeInnerRadius = radiusBUI * unitScale;
1664 const float frontSurface = topZ + frontDepth;
1665 const float backSurface = botZ - backDepth;
1671 if( frontDepth > 0.0f && frontRadius > holeInnerRadius )
1688 if( backDepth > 0.0f && backRadius > holeInnerRadius )
1712 const bool hasHole = drillsize.
x && drillsize.
y;
1714 const bool isRoundHole = drillsize.
x == drillsize.
y;
1716 float holeInnerRadius = 0.0f;
1723 float frontDepth = 0.0f;
1724 float backDepth = 0.0f;
1743 int innerRadius = drillsize.
x / 2;
1744 int outerRadius = innerRadius +
m_boardAdapter.GetHolePlatingThickness();
1745 holeInnerRadius = innerRadius * unitScale;
1747 RING_2D* ring =
new RING_2D( holeCenter, innerRadius * unitScale,
1748 outerRadius * unitScale, *aPad );
1759 antiOutlineIntersectionList );
1762 if( !antiOutlineIntersectionList.empty() )
1765 holeCenter, innerRadius * unitScale, *aPad );
1768 holeCenter, outerRadius * unitScale, *aPad );
1769 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
1770 object2d_B->push_back( innerCircle );
1779 object2d_A = itemCSG2d;
1787 if( drillsize.
x > drillsize.
y )
1789 ends_offset.
x = ( drillsize.
x - drillsize.
y ) / 2;
1790 width = drillsize.
y;
1794 ends_offset.
y = ( drillsize.
y - drillsize.
x ) / 2;
1795 width = drillsize.
x;
1805 -start.
y * unitScale ),
1807 -
end.y * unitScale ),
1808 width * unitScale, *aPad );
1812 -start.
y * unitScale ),
1814 -
end.y * unitScale ),
1816 * unitScale, *aPad );
1819 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
1820 object2d_B->push_back( innerSeg );
1828 object2d_A = itemCSG2d;
1833 antiOutlineIntersectionList );
1839 std::vector<const OBJECT_2D*>* object2d_B =
new std::vector<const OBJECT_2D*>();
1849 for(
const OBJECT_2D* hole2d : intersecting )
1851 if( object2d_A->
Intersects( hole2d->GetBBox() ) )
1852 object2d_B->push_back( hole2d );
1856 for(
const OBJECT_2D* obj : antiOutlineIntersectionList )
1857 object2d_B->push_back( obj );
1859 if( object2d_B->empty() )
1889 if( object2d_A && isRoundHole )
1891 const float frontSurface = topZ + frontDepth;
1892 const float backSurface = botZ - backDepth;
1898 if( frontDepth > 0.0f && frontRadius > holeInnerRadius )
1916 if( backDepth > 0.0f && backRadius > holeInnerRadius )
1953 for(
PAD*
pad : footprint->Pads() )
1963 const glm::mat4& aFpMatrix,
bool aHasExtrudedBody,
1966 if( aHasExtrudedBody )
1973 float scaleZ = std::min( bboxW, bboxH ) * 0.5f;
1976 float offsetX = localCenter.
x /
pcbIUScale.IU_PER_MM;
1977 float offsetY = -localCenter.
y /
pcbIUScale.IU_PER_MM;
1982 SFVEC3F boxMin( offsetX - bboxW * 0.5f, offsetY - bboxH * 0.5f, 0.0f );
1983 SFVEC3F boxMax( offsetX + bboxW * 0.5f, offsetY + bboxH * 0.5f, scaleZ );
1987 for(
int i = 0; i < 8; ++i )
1989 SFVEC3F corner( ( i & 1 ) ? boxMax.x : boxMin.x, ( i & 2 ) ? boxMax.y : boxMin.y,
1990 ( i & 4 ) ? boxMax.z : boxMin.z );
1992 corners[i] =
SFVEC3F( aFpMatrix * glm::vec4( corner, 1.0f ) );
1995 static const int faces[6][4] = { { 4, 5, 7, 6 }, { 0, 2, 3, 1 }, { 0, 1, 5, 4 },
1996 { 3, 2, 6, 7 }, { 0, 4, 6, 2 }, { 1, 3, 7, 5 } };
2005 aDstContainer.
Add( triangle );
2008 for(
const int* face : faces )
2010 addTriangle( corners[face[0]], corners[face[2]], corners[face[1]] );
2011 addTriangle( corners[face[0]], corners[face[3]], corners[face[2]] );
2025 if(
chain.PointCount() < 3 )
2032 for(
int i = 0; i <
chain.PointCount(); i++ )
2035 SFVEC2F pt( (
float) a.
x * aBiuTo3d, (
float) ( -a.
y ) * aBiuTo3d );
2037 if( ( i == 0 ) || ( fabs( prevPt.x - pt.x ) > FLT_EPSILON ) || ( fabs( prevPt.y - pt.y ) > FLT_EPSILON ) )
2043 segNormals.push_back( sn );
2048 if( segNormals.size() >= 3 )
2050 std::vector<SFVEC2F> tmpNormals( segNormals.size() );
2051 unsigned int j = segNormals.size() - 1;
2053 for(
unsigned int i = 0; i < segNormals.size(); j = i++ )
2055 SFVEC2F slope = segNormals[j].m_Start - segNormals[i].m_Start;
2056 segNormals[i].m_Precalc_slope = slope;
2057 tmpNormals[i] = glm::normalize(
SFVEC2F( slope.y, -slope.x ) );
2060 j = segNormals.size() - 1;
2062 for(
unsigned int i = 0; i < segNormals.size(); j = i++ )
2064 const SFVEC2F& nBefore = tmpNormals[j];
2065 const SFVEC2F& nCur = tmpNormals[i];
2066 const SFVEC2F& nAfter = tmpNormals[( i + 1 ) % segNormals.size()];
2068 float dotBefore = glm::dot( nBefore, nCur );
2069 float dotAfter = glm::dot( nAfter, nCur );
2071 segNormals[i].m_Normals.m_Start =
2072 ( dotBefore < 0.7f ) ? nCur : glm::normalize( nBefore * dotBefore + nCur );
2073 segNormals[i].m_Normals.m_End = ( dotAfter < 0.7f ) ? nCur : glm::normalize( nAfter * dotAfter + nCur );
2076 SEGMENTS capSegments( segNormals.size() );
2078 for(
unsigned int i = 0; i < segNormals.size(); i++ )
2079 capSegments[i].m_Start = segNormals[i].m_Start;
2081 j = capSegments.size() - 1;
2083 for(
unsigned int i = 0; i < capSegments.size(); j = i++ )
2085 capSegments[i].m_inv_JY_minus_IY = 1.0f / ( capSegments[j].m_Start.y - capSegments[i].m_Start.y );
2086 capSegments[i].m_JX_minus_IX = capSegments[j].m_Start.x - capSegments[i].m_Start.x;
2090 outersAndHoles.
m_Outers.push_back( capSegments );
2092 aObjContainer.
Add(
new POLYGON_2D( segNormals, outersAndHoles, aBoardItem ) );
2098 size_t prevSize = aObjContainer.
GetList().size();
2100 added += aObjContainer.
GetList().size() - prevSize;
2126 float standoff3d = body->
m_standoff * biuTo3d;
2134 zBot = boardSurfaceZ + standoff3d + zOffset3d;
2135 zTop = zBot + bodyThickness;
2139 zTop = boardSurfaceZ - standoff3d - zOffset3d;
2140 zBot = zTop - bodyThickness;
2154 size_t prevCount = objList.size();
2165 auto it = objList.begin();
2166 std::advance( it, prevCount );
2168 for( ; it != objList.end(); ++it )
2175 aDstContainer.
Add( layerItem );
2179 if( standoff3d > 0.0f )
2186 float oppositeSurfaceZ =
m_boardAdapter.GetFootprintZPos( !isBack );
2187 float protrusion = 1.0f *
pcbIUScale.IU_PER_MM * biuTo3d;
2188 float pinZBot, pinZTop;
2192 pinZBot = oppositeSurfaceZ - protrusion + zOffset3d;
2193 pinZTop = boardSurfaceZ + standoff3d + zOffset3d;
2197 pinZTop = oppositeSurfaceZ + protrusion - zOffset3d;
2198 pinZBot = boardSurfaceZ - standoff3d - zOffset3d;
2201 auto addPinObjects =
2210 size_t prevPinCount = objList.size();
2214 auto pinIt = objList.begin();
2215 std::advance( pinIt, prevPinCount );
2217 for( ; pinIt != objList.end(); ++pinIt )
2224 aDstContainer.
Add( layerItem );
2230 addPinObjects( pinPoly, &
m_materials.m_Copper, metalColor, 0.0f );
2231 addPinObjects( pegPoly, bodyMaterial, objColor, 1.0f - (
float) c.
a );
2240 std::stop_token aStop )
2256 if( aStop.stop_requested() )
2259 bool hasModels = !fp->Models().empty();
2260 bool showMissing =
m_boardAdapter.m_Cfg->m_Render.show_missing_models;
2263 bool hasExtrudedBody =
false;
2265 if( fp->HasExtrudedBody() && fp->GetExtrudedBody()->m_show &&
m_boardAdapter.IsFootprintShown( fp ) )
2268 if( ( hasModels || showMissing ) &&
m_boardAdapter.IsFootprintShown( fp ) )
2270 const glm::mat4 fpMatrix =
m_boardAdapter.GetFootprintMatrix( *fp );
2275 wxString libraryName = fp->GetFPID().GetLibNickname();
2277 wxString footprintBasePath = wxEmptyString;
2284 std::optional<LIBRARY_TABLE_ROW*> fpRow =
2297 bool placeholderAdded =
false;
2301 if( !
model.m_Show ||
model.m_Filename.empty() )
2305 std::vector<const EMBEDDED_FILES*> embeddedFilesStack;
2306 embeddedFilesStack.push_back( fp->GetEmbeddedFiles() );
2307 embeddedFilesStack.push_back(
m_boardAdapter.GetBoard()->GetEmbeddedFiles() );
2310 std::move( embeddedFilesStack ) );
2320 addModels( aDstContainer, modelPtr, modelMatrix, (
float)
model.m_Opacity,
2321 aSkipMaterialInformation, fp );
2323 else if( showMissing && !placeholderAdded )
2326 placeholderAdded =
true;
2331 if( !hasModels && showMissing )
2360 for(
unsigned int imat = 0; imat < a3DModel->
m_MaterialsSize; ++imat )
2368 float reflectionFactor = 0.0f;
2370 if( ( material.
m_Shininess - 0.35f ) > FLT_EPSILON )
2372 reflectionFactor = glm::clamp(
2373 glm::sqrt( ( material.
m_Shininess - 0.35f ) ) * 0.40f - 0.05f, 0.0f,
2384 if(
m_boardAdapter.m_Cfg->m_Render.raytrace_procedural_textures )
2439 return materialVector;
2444 const glm::mat4& aModelMatrix,
float aFPOpacity,
2445 bool aSkipMaterialInformation,
BOARD_ITEM* aBoardItem )
2448 wxASSERT( a3DModel !=
nullptr );
2450 if( a3DModel ==
nullptr )
2454 wxASSERT( a3DModel->
m_Meshes !=
nullptr );
2458 if( aFPOpacity > 1.0f )
2461 if( aFPOpacity < 0.0f )
2469 if( !aSkipMaterialInformation )
2474 const glm::mat3 normalMatrix = glm::transpose( glm::inverse( glm::mat3( aModelMatrix ) ) );
2476 for(
unsigned int mesh_i = 0; mesh_i < a3DModel->
m_MeshesSize; ++mesh_i )
2493 float fpTransparency;
2496 if( !aSkipMaterialInformation )
2505 for(
unsigned int faceIdx = 0; faceIdx < mesh.
m_FaceIdxSize; faceIdx += 3 )
2507 const unsigned int idx0 = mesh.
m_FaceIdx[faceIdx + 0];
2508 const unsigned int idx1 = mesh.
m_FaceIdx[faceIdx + 1];
2509 const unsigned int idx2 = mesh.
m_FaceIdx[faceIdx + 2];
2526 const SFVEC3F vt0 =
SFVEC3F( aModelMatrix * glm::vec4( v0, 1.0f ) );
2530 const SFVEC3F nt0 = glm::normalize(
SFVEC3F( normalMatrix * n0 ) );
2531 const SFVEC3F nt1 = glm::normalize(
SFVEC3F( normalMatrix * n1 ) );
2532 const SFVEC3F nt2 = glm::normalize(
SFVEC3F( normalMatrix * n2 ) );
2538 aDstContainer.
Add( newTriangle );
2540 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)
glm::mat4 CalcModelMatrix(const SFVEC3F &aOffset, const SFVEC3F &aRotation, const SFVEC3F &aScale)
Build the model-to-footprint transform used by rendering and picking.
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
bool GetExtrusionPinOutlines(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aPinPoly, SHAPE_POLY_SET &aPegPoly)
Get the hole outline polygons for extruded pin rendering.
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 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...
bool IsTriangleInRange(const unsigned int *aFaceIdx, unsigned int aTriangleIdx, unsigned int aVertexCount)
Test whether the three face indices of a triangle all reference valid vertices.
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.
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)
std::shared_ptr< REPORTER > m_warningReporter
std::shared_ptr< REPORTER > m_activityReporter
BOARD_ADAPTER & m_boardAdapter
Settings reference in use for this render.
SILK_SCREEN_NORMAL m_silkScreenMaterial
struct RENDER_3D_RAYTRACE_BASE::@013206213056006125230376122042346155134272177300 m_materials
std::mutex m_hitTestMutex
Serializes hover BVH use.
void addCountersinkPlating(const SFVEC2F &aCenter, float aTopInnerRadius, float aBottomInnerRadius, float aSurfaceZ, float aDepth, bool aIsFront)
BOARD_NORMAL m_boardMaterial
CONTAINER_3D m_objectContainer
std::vector< std::unique_ptr< BLINN_PHONG_MATERIAL > > m_extrusionMaterials
COPPER_NORMAL m_copperMaterial
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
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
void load3DModels(CONTAINER_3D &aDstContainer, bool aSkipMaterialInformation, std::stop_token aStop={})
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.
std::unique_ptr< ACCELERATOR_3D > m_accelerator
void addPlaceholderToRaytracer(CONTAINER_3D &aDstContainer, const FOOTPRINT *aFootprint, const glm::mat4 &aFpMatrix, bool aHasExtrudedBody=false, float aOpacity=1.0f)
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
void Reload(bool aOnlyLoadCopperAndShapes, std::stop_token aStop={})
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
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.
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.
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