wiki:SampleCodes/ObjLoader

Version 2 (modified by Hongtae Kim, 6 years ago) (diff)

--

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

Line 
1#pragma mark Mesh Loading
2ModelBvh 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 develop 브랜치 버전용