STL文件的基本数据格式:
solid OBJECT
facet normal 0 -0 -1
outer loop
vertex -17.220884323120117 17.570217132568359 0.81012475490570068
vertex -17.220884323120117 18.465063095092773 0.81012475490570068
vertex -15.970458030700684 17.570217132568359 0.81012475490570068
endloop
endfacet
facet normal -0 -0 -1
outer loop
vertex -17.220884323120117 18.465063095092773 0.81012475490570068
vertex -17.220884323120117 19.359909057617188 0.81012475490570068
vertex -15.970458030700684 17.570217132568359 0.81012475490570068
endloop
endfacet
……………………
……………………
由若干数量的三角面片组成
facet normal 0 -0 -1
outer loop
vertex -17.220884323120117 17.570217132568359 0.81012475490570068
vertex -17.220884323120117 18.465063095092773 0.81012475490570068
vertex -15.970458030700684 17.570217132568359 0.81012475490570068
endloop
endface
为一个三角形单元:第一行三个数据为三角面片的法向量,三个vertex分别为三角形的三个顶点
测试平台:windows7 64位 vs2010旗舰版
------------------------------------------------------------------------------------------------------------
xaml
------------------------------------------------------------------------------------------------------------
<Window x:Class="WPF3D.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Basic3D Sample" Name="Main_Window" Width="800" Height="600" > <DockPanel LastChildFill="True"> <StackPanel DockPanel.Dock="Left" Width="200" > <Label>投影模式</Label> <ComboBox Name="CameraMode" SelectionChanged="CameraMode_SelectionChanged" Width="100" HorizontalContentAlignment="Center"> <ComboBoxItem>正交投影</ComboBoxItem> <ComboBoxItem>透视投影</ComboBoxItem> </ComboBox> <Label>放缩</Label> <Slider Minimum="-5" Maximum="5" Margin="3"></Slider> <Button Margin="20" Padding="10" Click="Button_Click"> 打开文件</Button> <TextBlock> <Label>三角面片个数:</Label> <Label Name="NumberOfFacets" Width="60"></Label> <Label>个</Label> </TextBlock> <TextBlock> <Label Content="绘 图 时 间 :"></Label> <Label Name="TimeOfDrawing" Width="60"></Label> <Label>ms</Label> </TextBlock> <ScrollViewer VerticalScrollBarVisibility="Auto" Padding="0 20 20 0"> <StackPanel Name="ListVisual"> <TextBlock> <Label>序号</Label> <Label >三角形个数</Label> <Label>Time(ms)</Label> </TextBlock> </StackPanel> </ScrollViewer> </StackPanel> <Viewport3D Name="myViewport3D" > </Viewport3D> </DockPanel> </Window>
------------------------------------------------------------------------------------------------------------
.cs
------------------------------------------------------------------------------------------------------------
PerspectiveCamera myPerCamera = new PerspectiveCamera(); OrthographicCamera myOrthoCamera = new OrthographicCamera(); ModelVisual3D myModelLight = new ModelVisual3D(); ModelVisual3D myModel = new ModelVisual3D(); Model3DGroup myModelGroup = new Model3DGroup(); GeometryModel3D myGeomentryModel1 = new GeometryModel3D(); GeometryModel3D myGeomentryModel2 = new GeometryModel3D(); GeometryModel3D myGeomentryModel3 = new GeometryModel3D(); MeshGeometry3D myMeshModel1 = new MeshGeometry3D(); DiffuseMaterial myDiffMaterial = new DiffuseMaterial(); AmbientLight myAmbientLight = new AmbientLight(); DirectionalLight myDirectionLight = new DirectionalLight(); PointLight myPointLight = new PointLight(); string filePath = null; private MeshGeometry3D getMeshModeFromSTLFile(string path) { MeshGeometry3D mesh = new MeshGeometry3D(); int IndexOfTriangles = 0; StreamReader sr = new StreamReader(path); string line; Vector3D vec = new Vector3D(); string[] split=new string[4]; while ((line = sr.ReadLine()) != null) { line = line.TrimStart(); if (line.StartsWith("facet normal")) { //向量 line = line.Substring(12); //split = line.Split(' '); //vec = new Vector3D(double.Parse(split[1]), double.Parse(split[2]), double.Parse(split[3])); //点 line = sr.ReadLine(); line = sr.ReadLine(); split = line.TrimStart().Split(' '); mesh.Positions.Add(new Point3D(double.Parse(split[1]), double.Parse(split[2]), double.Parse(split[3]))); //mesh.Normals.Add(vec); mesh.TriangleIndices.Add(IndexOfTriangles++); line = sr.ReadLine(); split = line.TrimStart().Split(' '); mesh.Positions.Add(new Point3D(double.Parse(split[1]), double.Parse(split[2]), double.Parse(split[3]))); //mesh.Normals.Add(vec); mesh.TriangleIndices.Add(IndexOfTriangles++); line = sr.ReadLine(); split = line.TrimStart().Split(' '); mesh.Positions.Add(new Point3D(double.Parse(split[1]), double.Parse(split[2]), double.Parse(split[3]))); //mesh.Normals.Add(vec); mesh.TriangleIndices.Add(IndexOfTriangles++); } } NumberOfFacets.Content = (IndexOfTriangles/3).ToString(); return mesh; } private void drawModel() { Stopwatch sw = new Stopwatch(); sw.Start(); Viewport3D myViewPort = new Viewport3D(); myModelLight.Content = myAmbientLight; ScaleTransform3D scale = new ScaleTransform3D(0.1, 0.1, 0.1); myGeomentryModel1.Geometry = getMeshModeFromSTLFile(filePath); myDiffMaterial = new DiffuseMaterial(Brushes.Blue); myGeomentryModel1.Material = myDiffMaterial; myGeomentryModel1.BackMaterial = new DiffuseMaterial(Brushes.Coral); myModelGroup.Children.Add(myGeomentryModel1); myModel.Content = myModelGroup; myOrthoCamera.Position = new Point3D(-1000, -1000, -1000); myOrthoCamera.NearPlaneDistance = 10; myOrthoCamera.FarPlaneDistance = double.PositiveInfinity; myOrthoCamera.LookDirection = new Vector3D(1, 1, 1); myOrthoCamera.UpDirection = new Vector3D(0, 1, 0); myOrthoCamera.Width = 200; //myModel.Transform = scale; myViewport3D.Camera = myOrthoCamera; myViewport3D.Children.Clear(); myViewport3D.Children.Add(myModelLight); myViewport3D.Children.Add(myModel); sw.Stop(); TimeOfDrawing.Content = sw.ElapsedMilliseconds.ToString(); TextBlock tb=new TextBlock(); tb.Text=" " + (ListVisual.Children.Count).ToString() + ": "+ NumberOfFacets.Content +" "+ TimeOfDrawing.Content; ListVisual.Children.Add(tb); } private void Button_Click(object sender, RoutedEventArgs e) { System.Windows.Forms.OpenFileDialog fileDlg = new System.Windows.Forms.OpenFileDialog(); //penFileDialog1.InitialDirectory = "c:\"; //openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*"; //openoFileDialog1.FilterIndex = 2; //openFileDialog1.RestoreDirectory = true; fileDlg.InitialDirectory = "E:\"; fileDlg.Filter = "STL file(*.stl)|*.stl|All files(*.*)|*.*"; fileDlg.FilterIndex = 0; fileDlg.ShowDialog(); filePath = fileDlg.FileName; if (filePath != null && filePath.ToLower().EndsWith(".stl")) { drawModel(); } } private void CameraMode_SelectionChanged(object sender, SelectionChangedEventArgs e) { ComboBox cb = sender as ComboBox; switch (cb.SelectedIndex) { case 0: myViewport3D.Camera = myOrthoCamera; break; case 1: myPerCamera.Position = new Point3D(1000, 1000, 1000); myPerCamera.NearPlaneDistance = 10; myPerCamera.LookDirection = new Vector3D(-1, -1, -1); myPerCamera.UpDirection = new Vector3D(0, 1, 0); myPerCamera.FieldOfView = 10; myPerCamera.FarPlaneDistance = double.PositiveInfinity; myViewport3D.Camera = myPerCamera; break; default: break; } }
private void myViewport3D_MouseWheel(object sender, MouseWheelEventArgs e) { if(e.Delta>0) { myOrthoCamera.Width *=1.2; myPerCamera.FieldOfView *=1.2; } if(e.Delta<0) { myOrthoCamera.Width /= 1.2; myPerCamera.FieldOfView /= 1.2; } switch (CameraMode.SelectedIndex) { case 0: myViewport3D.Camera = myOrthoCamera; break; case 1: myViewport3D.Camera = myPerCamera; break; default: break; } }
效果: