MeshGeometry3D时WPF中的一种3d显示类,之前有人发帖解决了从3dmax文件自动生成MeshGeometry3D的方法(http://www.cnblogs.com/enjoyeclipse/archive/2012/03/21/2410439.html)。
这里反其道而行发布一种将MeshGeometry3D模型导出到obj文件格式可以使用3dmax打开查看。
内容如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Windows.Media.Imaging; 6 using System.IO; 7 using System.Windows.Media.Media3D; 8 using System.Windows; 9 10 namespace ZUI.Tools 11 { 12 public class ObjWriter 13 { 14 MeshGeometry3D _model; 15 BitmapSource _texture; 16 17 const string SPLITER = "#=================================================================================================="; 18 const string STR_BETWEEN_BLOCKS = "\r\n\r\n\r\n\r\n"; 19 20 public ObjWriter(MeshGeometry3D modle, BitmapSource texture) 21 { 22 _model = modle; 23 _texture = texture; 24 } 25 26 public void OutPut(string fileName,string fileSafeName) 27 { 28 CreatObj(fileName, fileSafeName); 29 CreatMtl(fileName, fileSafeName); 30 CreatReadMe(fileName, fileSafeName); 31 CreatTexture(fileName); 32 } 33 public void CreatReadMe(string fileName, string fileSafeName) 34 { 35 FileStream fileStream = new FileStream(fileName + "Read Me.txt", FileMode.Create, FileAccess.ReadWrite); 36 StreamWriter streamWriter = new StreamWriter(fileStream); 37 38 streamWriter.WriteLine(SPLITER); 39 streamWriter.WriteLine("#"); 40 streamWriter.WriteLine("# Those files listed below is auto generated. Please DO NOT edit them ! "); 41 streamWriter.WriteLine("# You can run the first file in meshlab or 3dmax . But you MUST have all those THREE files !"); 42 streamWriter.WriteLine("# If you have more question please send e-mail to \"zhao_chenhui_scu@163.com\"."); 43 streamWriter.WriteLine("#"); 44 streamWriter.WriteLine("# 1. " + fileSafeName); 45 streamWriter.WriteLine("# 2. " + fileSafeName+".bmp"); 46 streamWriter.WriteLine("# 3. " + fileSafeName+".mtl"); 47 streamWriter.WriteLine("#"); 48 streamWriter.WriteLine("# Thank you ! And have a nice day !"); 49 streamWriter.WriteLine("# Generated Time : " + DateTime.Now.ToString()); 50 streamWriter.WriteLine(SPLITER); 51 52 streamWriter.Flush(); 53 streamWriter.Close(); 54 fileStream.Close(); 55 } 56 57 private void CreatTexture(string fileName) 58 { 59 FileStream fileStream = new FileStream(fileName + ".bmp", FileMode.Create, FileAccess.ReadWrite); 60 61 BmpBitmapEncoder encoder = new BmpBitmapEncoder(); 62 encoder.Frames.Add(BitmapFrame.Create(_texture)) ; 63 encoder.Save(fileStream); 64 65 fileStream.Close(); 66 } 67 68 private void CreatMtl(string fileName, string fileSafeName) 69 { 70 FileStream fileStream = new FileStream(fileName + ".mtl", FileMode.Create, FileAccess.ReadWrite); 71 StreamWriter streamWriter = new StreamWriter(fileStream); 72 73 streamWriter.WriteLine(SPLITER); 74 streamWriter.WriteLine("#"); 75 streamWriter.WriteLine("# Warming : This file is auto generated . Please DO NOT edit it ! "); 76 streamWriter.WriteLine("#"); 77 streamWriter.WriteLine("# Generated Time : " + DateTime.Now.ToString()); 78 streamWriter.WriteLine("#"); 79 streamWriter.WriteLine("# Description :You can open this file in meshlab or 3dmax ."); 80 streamWriter.WriteLine("# If you have more question please send e-mail to \"zhao_chenhui_scu@163.com\"."); 81 streamWriter.WriteLine("# This file MUST work with other two files named:\"" + fileSafeName + "\" and \"" + fileSafeName + ".bmp\"."); 82 streamWriter.WriteLine("#"); 83 streamWriter.WriteLine(SPLITER); 84 streamWriter.WriteLine(STR_BETWEEN_BLOCKS); 85 86 streamWriter.WriteLine("newmtl mt1"); 87 streamWriter.WriteLine("Ka 0.0000 0.0000 0.0000"); 88 streamWriter.WriteLine("Kd 0.0000 0.0000 0.0000"); 89 streamWriter.WriteLine("Ks 0.0000 0.0000 0.0000"); 90 streamWriter.WriteLine("Ke 0.9725 0.9725 0.9725"); 91 92 streamWriter.WriteLine("map_Ka " + fileSafeName + ".bmp"); 93 streamWriter.WriteLine("map_Kd " + fileSafeName + ".bmp"); 94 95 96 streamWriter.Flush(); 97 streamWriter.Close(); 98 fileStream.Close(); 99 } 100 101 private void CreatObj(string fileName, string fileSafeName) 102 { 103 FileStream fileStream = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite); 104 StreamWriter streamWriter = new StreamWriter(fileStream); 105 106 streamWriter.WriteLine(GetHeadString(fileSafeName)); 107 streamWriter.WriteLine(STR_BETWEEN_BLOCKS); 108 109 streamWriter.WriteLine(GetMatralString(fileSafeName)); 110 streamWriter.WriteLine(STR_BETWEEN_BLOCKS); 111 112 streamWriter.Write(GetVerticesString()); 113 streamWriter.WriteLine(STR_BETWEEN_BLOCKS); 114 115 streamWriter.Write(GetTexturePointString()); 116 streamWriter.WriteLine(STR_BETWEEN_BLOCKS); 117 118 streamWriter.Write(GetFaceString()); 119 120 streamWriter.Flush(); 121 streamWriter.Close(); 122 fileStream.Close(); 123 } 124 125 private string GetHeadString(string fileSafeName) 126 { 127 StringBuilder result = new StringBuilder(); 128 129 result.AppendLine(SPLITER); 130 result.AppendLine("#"); 131 result.AppendLine("# Warming : This file is auto generated . Please DO NOT edit it ! "); 132 result.AppendLine("#"); 133 result.AppendLine("# Generated Time : "+DateTime.Now.ToString()); 134 result.AppendLine("#"); 135 result.AppendLine("# Description :You can open this file in meshlab or 3dmax ."); 136 result.AppendLine("# If you have more question please send e-mail to \"zhao_chenhui_scu@163.com\"."); 137 result.AppendLine("# This file MUST work with other two files named:\"" + fileSafeName + ".mtl\" and \""+fileSafeName+".bmp\"."); 138 result.AppendLine("#"); 139 result.AppendLine(SPLITER); 140 141 return result.ToString(); 142 } 143 144 private string GetMatralString(string fileSafeName) 145 { 146 StringBuilder result = new StringBuilder(); 147 148 result.AppendLine(SPLITER + "\r\n"); 149 result.AppendLine("# Matral : 1 \r\n"); 150 result.AppendLine("mtllib " + fileSafeName + ".mtl"); 151 result.AppendLine("\r\n# Matral End \r\n"); 152 result.AppendLine(SPLITER ); 153 154 return result.ToString(); 155 } 156 157 private string GetVerticesString() 158 { 159 StringBuilder result = new StringBuilder(); 160 161 result.AppendLine(SPLITER+"\r\n"); 162 result.AppendLine("# Vertices: "+ _model.Positions.Count + "\r\n"); 163 164 foreach (Point3D p in _model.Positions) 165 result.AppendLine("v " + p.X + " " + p.Y + " " + p.Z); 166 167 result.AppendLine("\r\n# Vertices End"); 168 result.AppendLine("\r\n" + SPLITER); 169 170 return result.ToString(); 171 } 172 173 private string GetTexturePointString() 174 { 175 StringBuilder result = new StringBuilder(); 176 177 result.AppendLine(SPLITER + "\r\n"); 178 result.AppendLine("# Texture Coordinates: " + _model.TextureCoordinates.Count + "\r\n"); 179 180 foreach(Point p in _model.TextureCoordinates) 181 result.AppendLine("vt " + p.X + " " + p.Y + " 0"); 182 183 184 result.AppendLine("\r\n# Texture Coordinates End"); 185 result.AppendLine("\r\n" + SPLITER); 186 187 return result.ToString(); 188 } 189 190 private string GetFaceString() 191 { 192 StringBuilder result = new StringBuilder(); 193 194 result.AppendLine(SPLITER + "\r\n"); 195 result.AppendLine("# Faces: " + _model.TriangleIndices.Count/3 + "\r\n"); 196 result.AppendLine("usemtl mt1" + "\r\n"); 197 198 for (int i = 0; i < _model.TriangleIndices.Count - 1; i+=3) 199 { 200 201 result.Append("f "); 202 203 int p1 = _model.TriangleIndices[i] + 1; 204 int p2 = _model.TriangleIndices[i + 1] + 1; 205 int p3 = _model.TriangleIndices[i + 2] + 1; 206 207 result.Append(p1 + "/" + p1 + " "); 208 result.Append(p2 + "/" + p2 + " "); 209 result.Append(p3 + "/" + p3 + " "); 210 211 result.AppendLine(); 212 } 213 214 result.AppendLine("\r\n# Faces End"); 215 result.AppendLine("\r\n" + SPLITER); 216 217 return result.ToString(); 218 } 219 } 220 }
使用方法如下:
1 private void ObjOutPut_Click(object sender, RoutedEventArgs e) 2 { 3 try 4 { 5 if (Modle == null || Modle.Geometry == null) 6 { 7 MessageBox.Show("模型不能为空"); 8 return; 9 } 10 SaveFileDialog dialog = new SaveFileDialog(); 11 dialog.Filter = "模型(*.obj)|*.obj"; 12 dialog.FileName = Title; 13 dialog.Title = "保存模型"; 14 15 double r = sliderrate.Value; 16 if (dialog.ShowDialog() == true) 17 { 18 ObjWriter ow = new ObjWriter(Modle.Geometry as MeshGeometry3D, _texture); 19 ow.OutPut(dialog.FileName,dialog.SafeFileName); 20 MessageBox.Show("Output Success !"); 21 } 22 } 23 catch (Exception ex) 24 { 25 MessageBox.Show(ex.Message); 26 } 27 }
运行的结果导出4个文件
全名如下:
# 1. box.obj
# 2. box.obj.bmp
# 3. box.obj.mtl
# 4.box.objRead Me.txt
其中前三个是有用的可以用第一个导入3dMAX
参考:
http://www.cppblog.com/lovedday/archive/2008/06/13/53153.html obj文件结构
http://hi.baidu.com/ab_xyz/blog/item/efff4fc518a11ba48326acbe.html mtl文件结构