FCStd (FreeCAD Standard) file이 오픈 CAD tool이라 많이 사용되는데 이 툴에서 다양한 파일로 Export가 가능함
FCStd -> GLTF, stl, obj 로 변환 가능
FCStd를 GLTF로 내보내기 할 때는 컴포넌트 좌표나 색상이 그대로 나가는데 stl 이나 obj는 1) object가 hierarchical 구조를 가질 때는 상위 transformation이 적용이 안되기 때문에 별도로 flatten 시켜서 내보내야 함, 2) 색상이 나가지 않기 때문에 import 한후에 색상을 적용해야 함
C#에서 import할 때 HelixToolkit.Wpf의 ModelImporter()를 사용하면 stl을 로딩할 수 있는데 gltf 처럼 색상을 지원하지 않기 때문에 로딩 한 후에 오브젝트별로 색상을 다시 넣어주어야 함
HelixToolkit.Wpf, SharpGLTF, SharpGLTF.Schema2 등 3D 콤포넌트는 Solution 탐색기에서 Project 선택한 후 NuGet관리자를 실행시켜서 검색 설치가 가능함
도구의 Addon manager에서 part-o-magic과 Lattice2를 설치해서 object를 flatten 시켜서 내보내야 함. 그렇지 않으면 상위 계층의 transform 정보가 없이 맨 하위 계층 object의 transform 정보만 나가기 때문에 c#에서 import 하면 위치가 다 깨짐
1) part-o-matic addon에서 "Mux Assembly"를 적용
2) lattice2 의 "Downgrade to leaves" 적용
(https://forum.freecad.org/viewtopic.php?t=32755 참고)
using HelixToolkit.Wpf;
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Media3D;
using SharpGLTF;
using SharpGLTF.Schema2;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Media;
private void Display3DModel()
{
ModelVisual3D device3D = new ModelVisual3D();
Model3DGroup group = new Model3DGroup();
Model3D satm = Display3d("Model\\lumir.stl");
Transform3DGroup transfromGroup = new Transform3DGroup();
AxisAngleRotation3D r1 = new AxisAngleRotation3D(new Vector3D(0, 1, 0), -90);
RotateTransform3D rt1 = new RotateTransform3D(r1);
AxisAngleRotation3D r2 = new AxisAngleRotation3D(new Vector3D(0, 1, 0), 90);
RotateTransform3D rt2 = new RotateTransform3D(r1);
TranslateTransform3D translateDelte = new TranslateTransform3D(8000, 0, 0);
transfromGroup.Children.Add(rt1);
transfromGroup.Children.Add(translateDelte);
group.Transform = transfromGroup;
group.Children.Add(satm);
device3D.Content = group;
viewPort3d.Children.Add(device3D);
}
private Model3D Display3d(string model)
{
Model3D device = null;
try
{
//Adding a gesture here
viewPort3d.RotateGesture = new MouseGesture(MouseAction.LeftClick);
//Import 3D model file
ModelImporter import = new ModelImporter();
//Load the 3D model file
device = import.Load(model);
}
catch (Exception e)
{
// Handle exception in case can not file 3D model
MessageBox.Show("Exception Error : " + e.StackTrace);
}
return device;
}
// Create a sphere using HelixToolkit's Earth material
var sphere = new SphereVisual3D() {
Radius = 5000, PhiDiv =100, ThetaDiv=100 };
var material = new DiffuseMaterial(
new ImageBrush(new BitmapImage(
new Uri("your.bmp", UriKind.Relative))));
sphere.Material = material;
// Create a model visual
var modelVisual = new ModelVisual3D();
modelVisual.Children.Add(sphere);
// Add the model to the Viewport3D
viewPort3d.Children.Add(modelVisual);
// Set up the camera
var camera = new PerspectiveCamera
{
Position = new Point3D(0, 0, 10000),
LookDirection = new Vector3D(0, 0, -10000),
UpDirection = new Vector3D(0, 10000, 0),
FieldOfView = 60
};
viewPort3d.Camera = camera;
// Add a light
var light = new DirectionalLight(Colors.White, new Vector3D(-0.5, -0.5, -1));
viewPort3d.Children.Add(
new ModelVisual3D { Content = light });
여러 레벨로 계층 적용 가능함
// Create the top-level group
Model3DGroup topLevelGroup = new Model3DGroup();
// Create a sub-group
Model3DGroup subGroup = new Model3DGroup();
// Load your model
ModelImporter import = new ModelImporter();
Model stm = import.Load("model.stl");
// Add the loaded model to the sub-group
subGroup.Children.Add(stm);
// You can add multiple models to the sub-group if needed
// subGroup.Children.Add(anotherModel);
// Add the sub-group to the top-level group
topLevelGroup.Children.Add(subGroup);
// You can add more sub-groups or individual models to the top-level group
// topLevelGroup.Children.Add(anotherSubGroup);
// topLevelGroup.Children.Add(someOtherModel);
// Create a ModelVisual3D to hold the top-level group
ModelVisual3D modelVisual = new ModelVisual3D();
modelVisual.Content = topLevelGroup;
// Add the ModelVisual3D to your Viewport3D
viewPort3d.Children.Add(modelVisual);
멀티 레벨로의 확장
Model3DGroup topLevelGroup = new Model3DGroup();
Model3DGroup midLevelGroup = new Model3DGroup();
Model3DGroup lowLevelGroup = new Model3DGroup();
// Load and add your model to the low-level group
Model stm = import.Load("model.stl");
lowLevelGroup.Children.Add(stm);
// Add the low-level group to the mid-level group
midLevelGroup.Children.Add(lowLevelGroup);
// Add the mid-level group to the top-level group
topLevelGroup.Children.Add(midLevelGroup);
// Create a ModelVisual3D and add the top-level group
ModelVisual3D modelVisual = new ModelVisual3D();
modelVisual.Content = topLevelGroup;
viewPort3d.Children.Add(modelVisual);
Transform3DGroup transformGroup = new Transform3DGroup();
transformGroup.Children.Add(new TranslateTransform3D(1, 2, 3));
transformGroup.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 45)));
midLevelGroup.Transform = transformGroup;
1. 단일 오브젝트 예
ModelVisual3D device3D = new ModelVisual3D();
Model3DGroup group = new Model3DGroup();
ModelImporter import = new ModelImporter();
Model stm = import.Load("model.stl");
// Create a new material with the desired color
Material newMaterial = new DiffuseMaterial(new SolidColorBrush(Colors.Red));
// Apply the new material to the entire model
if (stm is GeometryModel3D geometryModel)
{
geometryModel.Material = newMaterial;
geometryModel.BackMaterial = newMaterial; // For double-sided rendering
}
group.Children.Add(stm);
device3D.Content = group;
viewPort3d.Children.Add(device3D);
2. 여러 오브젝트 예
// Assuming stm is a Model3DGroup with multiple GeometryModel3D children
if (stm is Model3DGroup modelGroup)
{
foreach (var child in modelGroup.Children)
{
if (child is GeometryModel3D geometryModel)
{
// You can set different colors for different parts if needed
geometryModel.Material = new DiffuseMaterial(new SolidColorBrush(Colors.Blue));
geometryModel.BackMaterial = new DiffuseMaterial(new SolidColorBrush(Colors.Blue));
}
}
}
3. 동적 색상 변경
// Create a reusable material
DiffuseMaterial material = new DiffuseMaterial(new SolidColorBrush(Colors.Green));
// Apply the material to your model as shown in the previous examples
// Later, to change the color:
((SolidColorBrush)material.Brush).Color = Colors.Yellow;
4. 텍스쳐 변경
if (stm is GeometryModel3D geometryModel)
{
// Create a new texture with a solid color
RenderTargetBitmap renderBitmap = new RenderTargetBitmap(1, 1, 96, 96, PixelFormats.Pbgra32);
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawRectangle(new SolidColorBrush(Colors.Purple), null, new Rect(0, 0, 1, 1));
}
renderBitmap.Render(drawingVisual);
// Create a material with the new texture
ImageBrush textureBrush = new ImageBrush(renderBitmap);
Material newMaterial = new DiffuseMaterial(textureBrush);
// Apply the new material
geometryModel.Material = newMaterial;
geometryModel.BackMaterial = newMaterial;
}