Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
ObjModelReader.cs
浏览该文件的文档.
1using Engine;
3
4namespace Game {
5 public class ObjModelReader {
6 public static Dictionary<int, List<int>> FaceMap = [];
7
8 static ObjModelReader() {
9 FaceMap.Add(4, [0, 2, 1]); //顶面
10 FaceMap.Add(5, [0, 2, 1]); //底面
11 FaceMap.Add(2, [0, 2, 1]); //逆
12 FaceMap.Add(3, [0, 2, 1]); //逆
13 FaceMap.Add(0, [0, 2, 1]); //顺
14 FaceMap.Add(1, [0, 2, 1]); //顺
15 }
16
17 public struct ObjPosition {
18 public float x, y, z;
19
20 public ObjPosition(string x_, string y_, string z_) {
21 x = float.Parse(x_);
22 y = float.Parse(y_);
23 z = float.Parse(z_);
24 }
25
26 public ObjPosition(float x_, float y_, float z_) {
27 x = x_;
28 y = y_;
29 z = z_;
30 }
31 }
32
33 public struct ObjVertex {
37 }
38
39 public struct ObjNormal {
40 public float x, y, z;
41
42 public ObjNormal(string x_, string y_, string z_) {
43 x = float.Parse(x_);
44 y = float.Parse(y_);
45 z = float.Parse(z_);
46 }
47
48 public ObjNormal(float x_, float y_, float z_) {
49 x = x_;
50 y = y_;
51 z = z_;
52 }
53 }
54
55 public struct ObjTexCood {
56 public float tx, ty;
57
58 public ObjTexCood(string tx_, string ty_) {
59 tx = float.Parse(tx_);
60 ty = float.Parse(ty_);
61 }
62
63 public ObjTexCood(float tx_, float ty_) {
64 tx = tx_;
65 ty = ty_;
66 }
67 }
68
69 public class ObjMesh(string meshname) {
70 public int ElementIndex;
71 public DynamicArray<ObjVertex> Vertices = [];
72 public DynamicArray<int> Indices = [];
73 public string TexturePath = "Textures/NoneTexture"; //默认位置
74 public string MeshName = meshname;
76
78 List<Vector3> vectors = [];
79 for (int i = 0; i < Vertices.Count; i++) {
80 vectors.Add(new Vector3(Vertices[i].position.x, Vertices[i].position.y, Vertices[i].position.z));
81 }
82 return new BoundingBox(vectors);
83 }
84
85 public List<ObjMesh> ChildMeshes = [];
86 }
87
88 public static ObjModel Load(Stream stream) {
89 Dictionary<string, ObjMesh> Meshes = [];
90 Dictionary<string, string> TexturePaths = [];
91 List<ObjPosition> objPositions = [];
92 List<ObjTexCood> objTexCoods = [];
93 List<ObjNormal> objNormals = [];
94 using (stream) {
95 StreamReader streamReader = new(stream);
96 ObjMesh objMesh = null;
97 string CurrentTkey = null;
98 while (!streamReader.EndOfStream) {
99 string line = streamReader.ReadLine();
100 string[] spl = line.Split([(char)0x09, (char)0x20], StringSplitOptions.None);
101 switch (spl[0]) {
102 case "mtllib": {
103 MtllibStruct mtllibStruct = ContentManager.Get<MtllibStruct>(spl[1]);
104 TexturePaths = mtllibStruct.TexturePaths;
105 break;
106 }
107 case "o": {
108 if (Meshes.TryGetValue(spl[1], out ObjMesh mesh)) {
109 objMesh = mesh;
110 }
111 else {
112 objMesh = new ObjMesh(spl[1]);
113 Meshes.Add(spl[1], objMesh);
114 }
115 break;
116 }
117 case "v": {
118 objPositions.Add(new ObjPosition(spl[1], spl[2], spl[3]));
119 break;
120 }
121 case "vt": {
122 objTexCoods.Add(new ObjTexCood(spl[1], spl[2]));
123 break;
124 }
125 case "vn": {
126 objNormals.Add(new ObjNormal(spl[1], spl[2], spl[3]));
127 break;
128 }
129 case "usemtl": {
130 if (TexturePaths.TryGetValue(spl[1], out CurrentTkey)) {
131 //LoadingScreen.Info("Parse Obj mtl:" + CurrentTkey);
132 }
133 break;
134 }
135 case "f": {
136 if (string.IsNullOrEmpty(CurrentTkey)) {
137 CurrentTkey = "Textures/NoneTexture";
138 }
139 objMesh.TexturePath = CurrentTkey;
140 int SideCount = spl.Length - 1;
141 if (SideCount != 3) {
142 throw new Exception("模型必须为三角面");
143 }
144 int i = 0;
145 int startCount = objMesh.Vertices.Count;
146 while (++i < spl.Length) {
147 string[] param = spl[i].Split(['/'], StringSplitOptions.None);
148 if (param.Length != 3) {
149 throw new Exception("面参数错误");
150 }
151 int pa = int.Parse(param[0]); //顶点索引
152 int pb = int.Parse(param[1]); //纹理索引
153 int pc = int.Parse(param[2]); //法线索引
154 ObjPosition objPosition = objPositions[pa - 1];
155 ObjTexCood texCood = objTexCoods[pb - 1];
156 ObjNormal objNormal = objNormals[pc - 1];
157 int face = CellFace.Vector3ToFace(new Vector3(objNormal.x, objNormal.y, objNormal.z));
158 objMesh.Indices.Add(startCount + FaceMap[face][i - 1]);
159 objMesh.Vertices.Add(new ObjVertex { position = objPosition, objNormal = objNormal, texCood = texCood });
160 }
161 break;
162 }
163 }
164 }
165 }
166 return ObjMeshesToModel<ObjModel>(Meshes);
167 }
168
169 public static void AppendMesh(Model model, ModelBone rootBone, string texturepath, ObjMesh objMesh) {
170 ModelBone modelBone = model.NewBone(objMesh.MeshName, objMesh.MeshMatrix ?? Matrix.Identity, rootBone);
171 if (objMesh.Vertices.Count > 0) {
172 ModelMesh mesh = model.NewMesh(objMesh.MeshName, modelBone, objMesh.CalculateBoundingBox());
173 VertexBuffer vertexBuffer = new(
177 new VertexElement(24, VertexElementFormat.Vector2, VertexElementSemantic.TextureCoordinate)
178 ),
179 objMesh.Vertices.Count
180 );
181 MemoryStream stream1 = new();
182 MemoryStream stream2 = new();
183 BinaryWriter binaryWriter1 = new(stream1);
184 BinaryWriter binaryWriter2 = new(stream2);
185 for (int i = 0; i < objMesh.Vertices.Count; i++) {
186 ObjVertex objVertex = objMesh.Vertices[i];
187 binaryWriter1.Write(objVertex.position.x);
188 binaryWriter1.Write(objVertex.position.y);
189 binaryWriter1.Write(objVertex.position.z);
190 binaryWriter1.Write(objVertex.objNormal.x);
191 binaryWriter1.Write(objVertex.objNormal.y);
192 binaryWriter1.Write(objVertex.objNormal.z);
193 binaryWriter1.Write(objVertex.texCood.tx);
194 binaryWriter1.Write(objVertex.texCood.ty);
195 }
196 for (int i = 0; i < objMesh.Indices.Count; i++) {
197 binaryWriter2.Write(objMesh.Indices[i]);
198 }
199 byte[] vs = stream1.ToArray();
200 byte[] ins = stream2.ToArray();
201 stream1.Close();
202 stream2.Close();
203 vertexBuffer.SetData(objMesh.Vertices.Array, 0, objMesh.Vertices.Count);
204 vertexBuffer.Tag = vs;
205 IndexBuffer indexBuffer = new(IndexFormat.ThirtyTwoBits, objMesh.Indices.Count);
206 indexBuffer.SetData(objMesh.Indices.Array, 0, objMesh.Indices.Count);
207 indexBuffer.Tag = ins;
208 ModelMeshPart modelMeshPart = mesh.NewMeshPart(vertexBuffer, indexBuffer, 0, objMesh.Indices.Count, objMesh.CalculateBoundingBox());
209 modelMeshPart.TexturePath = objMesh.TexturePath;
210 model.AddMesh(mesh);
211 }
212 foreach (ObjMesh objMesh1 in objMesh.ChildMeshes) {
213 AppendMesh(model, modelBone, objMesh1.TexturePath, objMesh1);
214 }
215 }
216
217 public static T ObjMeshesToModel<T>(Dictionary<string, ObjMesh> Meshes) where T : class {
218 Type ctype = typeof(T);
219 if (!ctype.IsSubclassOf(typeof(Model))) {
220 throw new Exception($"不能将{ctype.Name}转换为Model类型");
221 }
222#pragma warning disable IL2087
223 object iobj = Activator.CreateInstance(ctype);
224#pragma warning restore IL2087
225 Model Model = iobj as Model;
226 ModelBone rootBone = Model.NewBone("Object", Matrix.Identity, null);
227 foreach (KeyValuePair<string, ObjMesh> c in Meshes) {
228 AppendMesh(Model, rootBone, c.Key, c.Value);
229 }
230 return iobj as T;
231 }
232 }
233
234 public class ObjModel : Model { }
235}
Engine.Vector3 Vector3
ModelBone NewBone(string name, Matrix transform, ModelBone parentBone)
ModelMesh NewMesh(string name, ModelBone parentBone, BoundingBox boundingBox)
void AddMesh(ModelMesh mesh)
ModelMeshPart NewMeshPart(VertexBuffer vertexBuffer, IndexBuffer indexBuffer, int startIndex, int indicesCount, BoundingBox boundingBox)
static object Get(Type type, string name)
Dictionary< string, string > TexturePaths
DynamicArray< ObjVertex > Vertices
static ObjModel Load(Stream stream)
static void AppendMesh(Model model, ModelBone rootBone, string texturepath, ObjMesh objMesh)
static T ObjMeshesToModel< T >(Dictionary< string, ObjMesh > Meshes)
static Dictionary< int, List< int > > FaceMap
static readonly Matrix Identity
static int Vector3ToFace(Vector3 v, int maxFace=5)
ObjNormal(string x_, string y_, string z_)
ObjNormal(float x_, float y_, float z_)
ObjPosition(string x_, string y_, string z_)
ObjPosition(float x_, float y_, float z_)
ObjTexCood(string tx_, string ty_)