OBJ 파일과 BVH 를 로딩하는 샘플 코드
1 #pragma mark Mesh Loading
2 ModelBvh LoadObjModel(const DKString& obj, const DKString& tex, DKMaterial* material, bool genBvh, bool useCachedData)
3 {
4 ModelBvh result = { "", NULL, NULL };
5 DKResourcePool pool;
6 DKObject<DKTexture2D> texture = pool.LoadResource(tex).SafeCast<DKTexture2D>();
7 if (texture == NULL)
8 {
9 DKLog("Failed to load texture: %ls\n", (const wchar_t*)tex);
10 return result;
11 }
12 DKString dkMeshFile = obj + ".dkmesh";
13 DKString dkBvhFile = obj + ".dktbvh";
14
15 DKObject<DKStaticMesh> mesh = NULL;
16 DKObject<DKTriangleMeshBvh> bvh = NULL;
17
18 if (useCachedData)
19 {
20 mesh = pool.LoadResource(dkMeshFile).SafeCast<DKStaticMesh>();
21 if (mesh && genBvh)
22 {
23 DKObject<DKData> triData = pool.LoadResourceData(dkBvhFile);
24 if (triData && triData->Length() > 0)
25 {
26 DKObject<BvhMesh> bvhMesh = DKOBJECT_NEW BvhMesh();
27
28 const DKTriangle* triangles = reinterpret_cast<const DKTriangle*>(triData->LockShared());
29 int numTri = (int)(triData->Length() / sizeof(DKTriangle));
30 bvhMesh->triangles.Add(triangles, numTri);
31 triData->UnlockShared();
32
33 bvh = DKOBJECT_NEW DKTriangleMeshBvh();
34 bvh->Build(bvhMesh);
35 }
36 }
37 }
38 if (mesh == NULL || (genBvh && bvh == NULL))
39 {
40 DKObject<DKData> objData = pool.LoadResourceData(obj);
41 if (objData && objData->Length() > 0)
42 {
43 DKLog("Loading %ls... (%lu bytes)\n", (const wchar_t*)obj, objData->Length());
44 DKTimer timer;
45 timer.Reset();
46
47 DKArray<DKVector3> positions;
48 DKArray<DKVector2> texcoords;
49 DKArray<DKVector3> normals;
50 struct Face
51 {
52 int pos, uv, normal;
53 };
54 DKArray<Face> faces;
55 DKString lineString;
56
57 positions.Reserve(0x10000);
58 texcoords.Reserve(0x10000);
59 normals.Reserve(0x10000);
60 faces.Reserve(0x10000);
61
62 DKUniChar8* p = (DKUniChar8*)objData->LockShared();
63 size_t length = objData->Length();
64 size_t pos = 0;
65 for (size_t i = 0; i < length; ++i)
66 {
67 if (p[i] == '\n')
68 {
69 if (pos < i)
70 {
71 DKString::StringArray words = DKString(&p[pos], (i - pos)).SplitByWhitespace();
72 if (words.Count() > 0)
73 {
74 if (words.Value(0).CompareNoCase("v") == 0) // vertex
75 {
76 if (words.Count() > 3)
77 {
78 DKVector3 vector(words.Value(1).ToRealNumber(),
79 words.Value(2).ToRealNumber(),
80 words.Value(3).ToRealNumber());
81 positions.Add(vector);
82 }
83 }
84 else if (words.Value(0).CompareNoCase("vn") == 0) // normal
85 {
86 if (words.Count() > 3)
87 {
88 DKVector3 vector(words.Value(1).ToRealNumber(),
89 words.Value(2).ToRealNumber(),
90 words.Value(3).ToRealNumber());
91 normals.Add(vector);
92 }
93 }
94 else if (words.Value(0).CompareNoCase("vt") == 0) // tex-coords
95 {
96 if (words.Count() > 2)
97 {
98 DKVector2 vector(words.Value(1).ToRealNumber(),
99 words.Value(2).ToRealNumber());
100
101 texcoords.Add(vector);
102 }
103 }
104 else if (words.Value(0).CompareNoCase("f") == 0) // face
105 {
106 size_t numFaces = words.Count() - 1;
107 Face f[4];
108 int idx = 0;
109 auto getIndex = [](int idx, int count) -> int
110 {
111 int v;
112 if (idx > 0)
113 v = idx - 1;
114 else
115 v = count + idx;
116 return Clamp(v, 0, count - 1);
117 };
118 while (idx < numFaces)
119 {
120 DKString::IntegerArray indices = words.Value(idx + 1).ToIntegerArray("/");
121 if (indices.Count() > 2) // pos, uv, normal
122 {
123 f[idx].pos = getIndex(indices.Value(0), positions.Count());
124 f[idx].uv = getIndex(indices.Value(1), texcoords.Count());
125 f[idx].normal = getIndex(indices.Value(2), normals.Count());
126 idx++;
127 }
128 else if (indices.Count() > 1) // pos, uv
129 {
130 f[idx].pos = getIndex(indices.Value(0), positions.Count());
131 f[idx].uv = getIndex(indices.Value(1), texcoords.Count());
132 f[idx].normal = 0;
133 idx++;
134 }
135 else
136 break;
137 }
138 if (idx == 3) // triangle
139 {
140 faces.Add(f, 3);
141 }
142 else if (idx == 4) // quad
143 {
144 faces.Add({ f[1], f[2], f[0], f[0], f[2], f[3] });
145 }
146 else // error??
147 {
148 }
149 }
150 }
151 }
152 pos = i + 1;
153 }
154 }
155 objData->UnlockShared();
156 objData = NULL;
157
158 DKLog("Num Positions: %lu\n", positions.Count());
159 DKLog("Num TexCoords: %lu\n", texcoords.Count());
160 DKLog("Num Normals: %lu\n", normals.Count());
161 DKLog("Num Faces: %lu\n", faces.Count());
162
163 if (faces.Count() > 0 && positions.Count() > 0 && texcoords.Count() > 0)
164 {
165 struct Vertex
166 {
167 DKVector3 pos;
168 DKVector3 normal;
169 DKVector2 uv;
170 };
171 DKAabb aabb;
172 DKArray<Vertex> vertices;
173 vertices.Reserve(faces.Count());
174 if (normals.Count() > 0)
175 {
176 for (int i = 0; (i + 2) < faces.Count(); i += 3)
177 {
178 const Face& f1 = faces.Value(i);
179 const Face& f2 = faces.Value(i + 1);
180 const Face& f3 = faces.Value(i + 2);
181
182 Vertex v[3] = {
183 { positions.Value(f1.pos), normals.Value(f1.normal), texcoords.Value(f1.uv) },
184 { positions.Value(f2.pos), normals.Value(f2.normal), texcoords.Value(f2.uv) },
185 { positions.Value(f3.pos), normals.Value(f2.normal), texcoords.Value(f3.uv) },
186 };
187
188 vertices.Add(v, 3);
189 aabb.Expand(v[0].pos);
190 aabb.Expand(v[1].pos);
191 aabb.Expand(v[2].pos);
192 }
193 }
194 else
195 {
196 DKLog("Generating face normals...\n");
197 for (int i = 0; (i + 2) < faces.Count(); i += 3)
198 {
199 const Face& f1 = faces.Value(i);
200 const Face& f2 = faces.Value(i + 1);
201 const Face& f3 = faces.Value(i + 2);
202
203 const DKVector3& pos1 = positions.Value(f1.pos);
204 const DKVector3& pos2 = positions.Value(f2.pos);
205 const DKVector3& pos3 = positions.Value(f3.pos);
206
207 DKVector3 faceNormal = DKVector3::Cross(pos2 - pos1, pos3 - pos1).Normalize();
208
209 Vertex v[3] = {
210 { pos1, faceNormal, texcoords.Value(f1.uv) },
211 { pos2, faceNormal, texcoords.Value(f2.uv) },
212 { pos3, faceNormal, texcoords.Value(f3.uv) },
213 };
214
215 vertices.Add(v, 3);
216 aabb.Expand(v[0].pos);
217 aabb.Expand(v[1].pos);
218 aabb.Expand(v[2].pos);
219 }
220 }
221 DKVertexBuffer::Decl decls[3] = {
222 { DKVertexStream::StreamPosition, L"", DKVertexStream::TypeFloat3, false },
223 { DKVertexStream::StreamNormal , L"", DKVertexStream::TypeFloat3, false },
224 { DKVertexStream::StreamTexCoord, L"", DKVertexStream::TypeFloat2, false },
225 };
226 DKObject<DKVertexBuffer> vb = DKVertexBuffer::Create(decls, 3, vertices, sizeof(Vertex), vertices.Count(), DKVertexBuffer::MemoryLocationStatic, DKVertexBuffer::BufferUsageDraw);
227
228 mesh = DKObject<DKStaticMesh>::New();
229 mesh->SetDrawFace(DKMesh::DrawFaceBoth);
230 mesh->SetDefaultPrimitiveType(DKPrimitive::TypeTriangles);
231 mesh->AddVertexBuffer(vb);
232 mesh->SetAabb(aabb);
233 DKLog("Obj %ls file loaded. (%f sec)\n", (const wchar_t*)obj, timer.Elapsed());
234
235 DKObject<BvhMesh> bvhMesh = NULL;
236 if (genBvh)
237 {
238 // Create bvh
239 DKTimer bvhTimer;
240 bvhTimer.Reset();
241
242 bvhMesh = DKOBJECT_NEW BvhMesh();
243 int numTri = (int)(vertices.Count() / 3);
244 bvhMesh->triangles.Reserve(numTri);
245 for (int i = 0; i < numTri; ++i)
246 {
247 const Vertex& v1 = vertices.Value(i * 3);
248 const Vertex& v2 = vertices.Value(i * 3 + 1);
249 const Vertex& v3 = vertices.Value(i * 3 + 2);
250
251 DKTriangle t = { v1.pos, v2.pos, v3.pos };
252 bvhMesh->triangles.Add(t);
253 }
254 bvh = DKOBJECT_NEW DKTriangleMeshBvh();
255 bvh->Build(bvhMesh);
256
257 double d = bvhTimer.Elapsed();
258 DKLog("Generating BVH elapsed: %f\n", d);
259 }
260 if (useCachedData)
261 {
262 DKObject<DKData> data = mesh->Serialize(DKSerializer::SerializeFormCompressedBinary);
263 if (data)
264 {
265 DKLog("Writing DKMesh file: %ls\n", (const wchar_t*)dkMeshFile);
266 data->WriteToFile(dkMeshFile, true);
267 }
268 if (bvhMesh && bvhMesh->triangles.Count() > 0)
269 {
270 data = DKData::StaticData(bvhMesh->triangles, sizeof(DKTriangle) * bvhMesh->triangles.Count());
271 if (data)
272 {
273 DKLog("Writing DKBvh file: %ls\n", (const wchar_t*)dkBvhFile);
274 data->WriteToFile(dkBvhFile, true);
275 }
276 }
277 }
278 }
279 }
280 else
281 {
282 // error.
283 DKLog("Failed to load obj file: %ls\n", (const wchar_t*)obj);
284 }
285 }
286 if (mesh)
287 {
288 DKAabb aabb = mesh->Aabb();
289 DKLog("AABB: (%.3f, %.3f, %.3f), (%.3f, %.3f, %.3f)\n",
290 aabb.positionMin.x, aabb.positionMin.y, aabb.positionMin.z,
291 aabb.positionMax.x, aabb.positionMax.y, aabb.positionMax.z);
292 DKLog("AABB width: %.3f, height: %.3f, depth: %.3f\n",
293 aabb.positionMax.x - aabb.positionMin.x,
294 aabb.positionMax.y - aabb.positionMin.y,
295 aabb.positionMax.z - aabb.positionMin.z);
296
297 // DKObject<DKTextureSampler> sampler = DKOBJECT_NEW DKTextureSampler();
298 // sampler->magFilter = DKTextureSampler::MagFilterNearest;
299 // sampler->minFilter = DKTextureSampler::MinFilterNearest;
300 mesh->SetMaterial(material);
301 mesh->SetSampler(L"diffuseMap", DKMaterial::TextureArray(texture.SafeCast<DKTexture>(), 1), NULL);
302 result.mesh = mesh;
303 result.bvh = bvh;
304 }
305 else
306 {
307 DKLog("Load %ls failed.\n", (const wchar_t*)obj);
308 }
309 return result;
310 }
- DKGL v1.2 버전용