source: OniSplit/Dae/IO/ObjWriter.cs@ 1114

Last change on this file since 1114 was 1114, checked in by iritscen, 5 years ago

Adding OniSplit source code (v0.9.99.0). Many thanks to Neo for all his work over the years.

File size: 9.2 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Globalization;
4using System.IO;
5using Oni.Collections;
6
7namespace Oni.Dae.IO
8{
9 internal class ObjWriter
10 {
11 private int vBase = 1, vtBase = 1, vnBase = 1;
12 private Set<Material> materials = new Set<Material>();
13 private StreamWriter objWriter;
14 private StreamWriter mtlWriter;
15
16 internal static void WriteFile(string filePath, Scene scene)
17 {
18 var writer = new ObjWriter();
19 writer.Write(filePath, scene);
20 }
21
22 private void Write(string filePath, Scene scene)
23 {
24 using (objWriter = File.CreateText(filePath))
25 {
26 objWriter.WriteLine("# Generated by OniSplit v{0}", Utils.Version);
27 objWriter.WriteLine();
28
29 objWriter.WriteLine("mtllib {0}", Path.ChangeExtension(Path.GetFileName(filePath), ".mtl"));
30 objWriter.WriteLine();
31
32 var rootTransform = Matrix.Identity;
33
34 WriteNode(scene, ref rootTransform);
35 }
36
37 using (mtlWriter = File.CreateText(Path.ChangeExtension(filePath, ".mtl")))
38 {
39 mtlWriter.WriteLine("# Generated by OniSplit v{0}", Utils.Version);
40 mtlWriter.WriteLine();
41
42 WriteMaterialLibrary();
43 }
44 }
45
46 private void WriteNode(Node node, ref Matrix parentTransform)
47 {
48 if (!string.IsNullOrEmpty(node.Name))
49 objWriter.WriteLine("g {0}", node.Name);
50
51 var transform = node.Transforms.ToMatrix() * parentTransform;
52
53 foreach (var geometryInstance in node.GeometryInstances)
54 WriteGeometry(geometryInstance, ref transform);
55
56 foreach (var child in node.Nodes)
57 WriteNode(child, ref transform);
58 }
59
60 private void WriteGeometry(GeometryInstance geometryInstance, ref Matrix transform)
61 {
62 var geometry = geometryInstance.Target;
63
64 foreach (var primitives in geometry.Primitives)
65 {
66 var posInput = WritePositions(primitives, ref transform);
67 var texCoordInput = WriteTexCoords(primitives);
68 var normalInput = WriteNormals(primitives, ref transform);
69
70 WriteUseMaterial(geometryInstance, primitives);
71 WriteFaces(primitives, posInput, texCoordInput, normalInput);
72
73 vBase += posInput.Source.Count;
74 vtBase += texCoordInput == null ? 0 : texCoordInput.Source.Count;
75 vnBase += normalInput == null ? 0: normalInput.Source.Count;
76 }
77 }
78
79 private IndexedInput WritePositions(MeshPrimitives primitives, ref Matrix transform)
80 {
81 var input = primitives.Inputs.FirstOrDefault(i => i.Semantic == Semantic.Position);
82 var source = input.Source;
83
84 for (int i = 0; i < source.Count; i++)
85 {
86 var position = Vector3.Transform(Source.ReadVector3(source, i), ref transform);
87
88 objWriter.Write("v ");
89 objWriter.Write(position.X.ToString(CultureInfo.InvariantCulture));
90 objWriter.Write(' ');
91 objWriter.Write(position.Y.ToString(CultureInfo.InvariantCulture));
92 objWriter.Write(' ');
93 objWriter.Write(position.Z.ToString(CultureInfo.InvariantCulture));
94 objWriter.WriteLine();
95 }
96
97 objWriter.WriteLine();
98
99 return input;
100 }
101
102 private IndexedInput WriteTexCoords(MeshPrimitives primitives)
103 {
104 var input = primitives.Inputs.FirstOrDefault(i => i.Semantic == Semantic.TexCoord);
105
106 if (input == null)
107 return null;
108
109 var source = input.Source;
110 var data = source.FloatData;
111
112 for (int i = 0; i < data.Length; i += source.Stride)
113 {
114 objWriter.Write("vt ");
115 objWriter.Write(data[i + 0].ToString(CultureInfo.InvariantCulture));
116 objWriter.Write(' ');
117 objWriter.Write(data[i + 1].ToString(CultureInfo.InvariantCulture));
118 objWriter.WriteLine();
119 }
120
121 objWriter.WriteLine();
122
123 return input;
124 }
125
126 private IndexedInput WriteNormals(MeshPrimitives primitives, ref Matrix transform)
127 {
128 var input = primitives.Inputs.FirstOrDefault(i => i.Semantic == Semantic.Normal);
129
130 if (input == null)
131 return null;
132
133 var source = input.Source;
134
135 for (int i = 0; i < source.Count; i++)
136 {
137 var normal = Vector3.TransformNormal(Source.ReadVector3(source, i), ref transform);
138
139 objWriter.Write("vn ");
140 objWriter.Write(normal.X.ToString(CultureInfo.InvariantCulture));
141 objWriter.Write(' ');
142 objWriter.Write(normal.Y.ToString(CultureInfo.InvariantCulture));
143 objWriter.Write(' ');
144 objWriter.Write(normal.Z.ToString(CultureInfo.InvariantCulture));
145 objWriter.WriteLine();
146 }
147
148 objWriter.WriteLine();
149
150 return input;
151 }
152
153 private void WriteFaces(MeshPrimitives primitives, IndexedInput posInput, IndexedInput texCoordInput, IndexedInput normalInput)
154 {
155 var positionIndices = posInput.Indices;
156 var texCoordIndices = texCoordInput == null ? null : texCoordInput.Indices;
157 var normalIndices = normalInput == null ? null : normalInput.Indices;
158 int vertexIndex = 0;
159
160 foreach (var vertexCount in primitives.VertexCounts)
161 {
162 objWriter.Write("f");
163
164 for (int i = vertexIndex; i < vertexIndex + vertexCount; i++)
165 {
166 objWriter.Write(' ');
167 objWriter.Write((vBase + positionIndices[i]).ToString(CultureInfo.InvariantCulture));
168
169 if (texCoordIndices != null)
170 {
171 objWriter.Write('/');
172 objWriter.Write((vtBase + texCoordIndices[i]).ToString(CultureInfo.InvariantCulture));
173 }
174 else if (normalIndices != null)
175 {
176 objWriter.Write('/');
177 }
178
179 if (normalIndices != null)
180 {
181 objWriter.Write('/');
182 objWriter.Write((vnBase + normalIndices[i]).ToString(CultureInfo.InvariantCulture));
183 }
184 }
185
186 objWriter.WriteLine();
187
188 vertexIndex += vertexCount;
189 }
190
191 objWriter.WriteLine();
192 }
193
194 private void WriteUseMaterial(GeometryInstance geometryInstance, MeshPrimitives primitives)
195 {
196 if (string.IsNullOrEmpty(primitives.MaterialSymbol))
197 {
198 objWriter.WriteLine("usemtl");
199 }
200 else
201 {
202 var materialInstance = geometryInstance.Materials.Find(m => m.Symbol == primitives.MaterialSymbol);
203
204 if (materialInstance != null && materialInstance.Target != null)
205 {
206 objWriter.WriteLine("usemtl {0}", materialInstance.Target.Name);
207 materials.Add(materialInstance.Target);
208 }
209 }
210 }
211
212 private void WriteMaterialLibrary()
213 {
214 foreach (var material in materials)
215 {
216 mtlWriter.WriteLine("newmtl {0}", material.Name);
217
218 var effect = material.Effect;
219
220 WriteMaterialColor("Ka", effect.Ambient);
221 WriteMaterialColor("Kd", effect.Diffuse);
222
223 mtlWriter.WriteLine("Ks 0 0 0");
224 mtlWriter.WriteLine("Ns 0");
225
226 WriteMaterialTextureMap("map_Kd", effect.Diffuse);
227 WriteMaterialTextureMap("map_Tr", effect.Transparent);
228
229 if (effect.TransparentValue is EffectTexture)
230 mtlWriter.WriteLine("illum 9");
231 else
232 mtlWriter.WriteLine("illum 2");
233
234 mtlWriter.WriteLine();
235 }
236 }
237
238 private void WriteMaterialColor(string mtlCommand, EffectParameter effectParam)
239 {
240 if (effectParam == null || !(effectParam.Value is Vector4))
241 return;
242
243 var color = (Vector4)effectParam.Value;
244 mtlWriter.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} {3}", mtlCommand, color.X, color.Y, color.Z));
245 }
246
247 private void WriteMaterialTextureMap(string mtlCommand, EffectParameter effectParam)
248 {
249 if (effectParam == null)
250 return;
251
252 var texture = effectParam.Value as EffectTexture;
253
254 if (texture == null)
255 return;
256
257 mtlWriter.WriteLine("{0} {1}", mtlCommand, texture.Sampler.Surface.InitFrom.FilePath);
258 }
259 }
260}
Note: See TracBrowser for help on using the repository browser.