wiki:SampleCodes/ObjLoader

Version 1 (modified by Hongtae Kim, 3 years ago) (diff)

--

OBJ 파일과 BVH 를 로딩하는 샘플 코드

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