{"id":21874237,"url":"https://github.com/stefanjohnsen/wavefrontobj","last_synced_at":"2025-10-20T04:56:05.482Z","repository":{"id":191817973,"uuid":"685446697","full_name":"StefanJohnsen/WavefrontOBJ","owner":"StefanJohnsen","description":"Wavefront OBJ parser C++ 11","archived":false,"fork":false,"pushed_at":"2023-09-18T10:53:25.000Z","size":6455,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-26T17:37:40.793Z","etag":null,"topics":["cpp","cpp11","header-only","obj","wavefront","wavefront-obj"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/StefanJohnsen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-31T08:48:03.000Z","updated_at":"2025-01-17T15:44:32.000Z","dependencies_parsed_at":"2024-11-28T08:31:08.907Z","dependency_job_id":null,"html_url":"https://github.com/StefanJohnsen/WavefrontOBJ","commit_stats":null,"previous_names":["stefanjohnsen/wavefrontobj"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StefanJohnsen%2FWavefrontOBJ","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StefanJohnsen%2FWavefrontOBJ/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StefanJohnsen%2FWavefrontOBJ/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StefanJohnsen%2FWavefrontOBJ/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/StefanJohnsen","download_url":"https://codeload.github.com/StefanJohnsen/WavefrontOBJ/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244880660,"owners_count":20525515,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp11","header-only","obj","wavefront","wavefront-obj"],"created_at":"2024-11-28T07:11:40.944Z","updated_at":"2025-10-20T04:56:00.434Z","avatar_url":"https://github.com/StefanJohnsen.png","language":"C++","readme":"# WavefrontOBJ\nEmpower your project with a self-contained header-only C++ 11 OBJ parser.\n\n### Compatibility and Dependencies\n- C++ 11 Standard\n- Standard Template Library (STL)\n\nThis project is designed to be compatible with C++11 and utilizes solely C++ Standard Template Library (STL) components. It has been thoughtfully engineered to function independently without the need for any external libraries or dependencies. This design ensures the project remains self-contained, promoting simplicity and ease of integration into your development environment.\u003cbr\u003e\n\n*If you require the use of **C++98**, see [Wavefront98](https://github.com/StefanJohnsen/Wavefront98) repository.*\n\n### OS Support\n- Windows\n- Linux\n- macOS\n\n### Speed and memory\n- By supporting C++ 11 Standard only and without use of multithreading, we have achieved a good level of speed.\n- This solution boasts minimal memory usage, typically averaging twice the file size in memory consumption.\n  \n### Usage\nCopy `WavefrontOBJ.h` to your project and include the file.\n\n```\n#include \"WavefrontOBJ.h\"\n```\n\n### Parsed examples\n*WavfrontOBJ and [WavefrontMTL](https://github.com/StefanJohnsen/WavefrontMTL) parsers have been integrated into the [Polyscope 3D viewer](https://github.com/nmwsharp/polyscope), showcasing the parsing capabilities.*\n\n![Polyscope](https://github.com/StefanJohnsen/WavefrontOBJ/blob/main/Pictures/polyscope.jpg)\n*[3D model Mars Perseverance Rover](https://mars.nasa.gov/resources/25042/mars-perseverance-rover-3d-model/),  from NASA's Jet Propulsion Laboratory*\n\n## 3D Model Data Structures\nAfter parsing the obj file, users gain access to geometry by utilizing the following lists.\n\t\n| Component | Description                                    |\n|-----------|------------------------------------------------|\n| Vertex    | Defines points in 3D space, shaping the model. |\n| Texture   | Manages texture details for enhanced visuals.  |\n| Normal    | Specifies surface orientation for lighting.    |\n| Face      | Contains indices for creating flat surfaces.   |\n| Line      | Stores indices, useful for wireframe models.   |\n| Point     | Manages indices for individual 3D points.      |\n\nWavefrontOBJ supports various vertex and texture coordinate lists, allowing you to copy coordinates to your list formats. \n\n### Supported user vertex list formats\n\n- **Classic Format (x, y, z):** Represents vertices with x, y, and z coordinates in 3D space.\u003cbr\u003e*{x,y,z, x,y,z, x,y,z, ....} =\u003e obj::VertexFormat::xyz*\n  \n- **Homogeneous Format (x, y, z, w):** Extends the classic format with an additional component, w, often used for transformations.\u003cbr\u003e*{x,y,z,w, x,y,z,w, x,y,z,w, ....} =\u003e obj::VertexFormat::xyzw*\n  \n- **Ending RGB Format (x, y, z, r, g, b):** Combines vertex position with colour attributes, enhancing visual representation.\u003cbr\u003e*{x,y,z,r,g,b, x,y,z,r,g,b, x,y,z,r,g,b, ....} =\u003e obj::VertexFormat::xyzrgb*\n\n### Supported user texture list formats\n\n- **Classic UV Format (u, v):** Represents texture coordinates using U and V values.\u003cbr\u003e*{u,v, u,v, u,v, ....} =\u003e obj::TextureFormat::uv*\n  \n- **UVW Format (u, v, w):** Extends the UV format with an additional component, w, useful for specific texture mapping scenarios.\u003cbr\u003e*{u,v,w, u,v,w, u,v,w, ....} =\u003e obj::TextureFormat::uvw*\n  \nWhen copying data, these formats follow your coordinate data structures. \n\nIf your list aligns with any of the examples below, WavefrontOBJ allows you to copy the internal list to your list using a single copy operation.\n\n```cpp\nstd::vector\u003cfloat\u003e vertex;\nstd::vector\u003cfloat\u003e normal;\nstd::vector\u003cfloat\u003e texture;\n\nstd::vector\u003cdouble\u003e vertex;\nstd::vector\u003cdouble\u003e normal;\nstd::vector\u003cdouble\u003e texture;\n\nstd::vector\u003cstd::vector\u003cfloat\u003e\u003e vertex;\nstd::vector\u003cstd::vector\u003cfloat\u003e\u003e normal;\nstd::vector\u003cstd::vector\u003cfloat\u003e\u003e texture;\n\nstd::vector\u003cstd::vector\u003cdouble\u003e\u003e vertex;\nstd::vector\u003cstd::vector\u003cdouble\u003e\u003e normal;\nstd::vector\u003cstd::vector\u003cdouble\u003e\u003e texture;\n```\nIf not, you'll need to copy the internal list to your list manually.\u003cbr\u003e\n*See section [Load and get vertex manually](https://github.com/StefanJohnsen/WavefrontOBJ#sample-code).*\n\n## Examples\n\n### Load and count\n```cpp\n#include \"WavefrontOBJ.h\"\n#include \u003ciostream\u003e\n\nint main()\n{\n\tobj::Load file;\n\n\tif( !file.load(\"C:\\\\temp\\\\example.obj\") )\n\t\treturn 1;\n\n\tstd::cout \u003c\u003c \"Geometric vertices: \" \u003c\u003c obj.vertex.size() \u003c\u003c std::endl;\n\tstd::cout \u003c\u003c \"Texture vertices: \" \u003c\u003c obj.texture.size() \u003c\u003c std::endl;\n\tstd::cout \u003c\u003c \"Normal vertices: \" \u003c\u003c obj.normal.size() \u003c\u003c std::endl;\n\t\n\tstd::cout \u003c\u003c \"Vertex indices: \" \u003c\u003c obj.face.vertex.size() \u003c\u003c std::endl;\n\tstd::cout \u003c\u003c \"Texture indices: \" \u003c\u003c obj.face.texture.size() \u003c\u003c std::endl;\n\tstd::cout \u003c\u003c \"Normal indices: \" \u003c\u003c obj.face.normal.size() \u003c\u003c std::endl;\n\n\treturn 0;\n}\n```\n\n### Load and get coordinates with the same list types (float)\n```cpp\nobj::Load obj;\n\nif (!obj.load(\"C:\\\\temp\\\\example.obj\"))\n\treturn 1;\n\nstd::vector\u003cfloat\u003e vertex;\nstd::vector\u003cfloat\u003e normal;\nstd::vector\u003cfloat\u003e texture;\n\nobj::copy(obj.vertex, vertex);\nobj::copy(obj.texture, texture);\nobj::copy(obj.normal, normal);\n```\n*If all vertex in the above obj.vertex list has the same format as xyz, the obj.vertex list will be moved to vertex list (std::move).\u003cbr\u003e\nWavfrontOBJ will always try to move the list instead of copying the list for better performence.*\n\n### Load and get coordinates with different list types\n```cpp\nobj::Load obj;\n\nif (!obj.load(\"C:\\\\temp\\\\example.obj\"))\n\treturn 1;\n\n{\n\tstd::vector\u003cdouble\u003e vertex;\n\tstd::vector\u003cdouble\u003e normal;\n\tstd::vector\u003cdouble\u003e texture;\n\n\tobj::copy(obj.vertex, vertex);\n\tobj::copy(obj.texture, texture);\n\tobj::copy(obj.normal, normal);\n}\n\n{\n\tstd::vector\u003cstd::vector\u003cdouble\u003e\u003e vertex;\n\tstd::vector\u003cstd::vector\u003cdouble\u003e\u003e normal;\n\tstd::vector\u003cstd::vector\u003cdouble\u003e\u003e texture;\n\n\tobj::copy(obj.vertex, vertex);\n\tobj::copy(obj.texture, texture);\n\tobj::copy(obj.normal, normal);\n}\n\n```\n*WavfrontOBJ will copy all lists above.\u003cbr\u003e\nAbove obj.vertex list is double and therefor it will be copied into vertex list.\u003cbr\u003e\nYou can choose xyz, xyzw or xyzrgb as third argument in copy function. Default is xyz.\u003cbr\u003eEx. If you choose xyzrgb and obj.vertex don't have that format, your list will contains zero values for rgb {x,y,z,0,0,0}*\n\n### Load and get face colors\nWavefrontOBJ uses [WavefrontMTL](https://github.com/StefanJohnsen/WavefrontMTL) to simplify the process of loading materials and colors. To easily integrate this feature, copy the WavefrontMTL.h file from the WavefrontMTL repository into the same directory as WavefrontOBJ.h. This enables straightforward handling of materials and colors within your project.\n\n```cpp\n#include \"WavefrontOBJ.h\"\n#include \"WavefrontMTL.h\"\n#include \u003ciostream\u003e\n\nint main()\n{\n\tobj::Load obj;\n\n\tif (!obj.load(\"C:\\\\temp\\\\example.obj\"))\n\t\treturn 1;\n\n\tmtl::Load mtl;\n\n\tif (!mtl.load(obj.mtllib()))\n\t\treturn 1;\n\n\tstd::vector\u003cfloat\u003e color;\n\t\n\tobj::Copy(obj, mtl, color);\n\n\treturn 0;\n}\n```\n\nPossible color lists:\n\n```cpp\nstd::vector\u003cfloat\u003e color;\nstd::vector\u003cdouble\u003e color;\n\nstd::vector\u003cstd::vector\u003cfloat\u003e\u003e color;\nstd::vector\u003cstd::vector\u003cdouble\u003e\u003e color;\n```\n\n## Triangulation\nIn the Wavefront OBJ file format, 3D models are commonly described using triangles due to their simplicity and broad compatibility. However, the format also supports faces with polygons, which means more than three vertices. \nWhile some applications struggle to handle these polygons, many prefer triangles for predictable rendering.\n\n*To bridge this gap, a solution known as triangulation is provided, see [TriangulateOBJ](https://github.com/StefanJohnsen/TriangulateOBJ) repository.*\n\nTo perform triangulation on an OBJ file, specify the following object definition.\n```cpp\nobj::Load file(true);\n```\n\n## Benchmark\nThe benchmark was conducted on a computer with the following specifications:\n\n- **Processor:** Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz   2.59 GHz\n- **Memory:** 16.0 GB\n- **Operating System:** 64-bit operating system, x64-based processor\n- **Compiler:** Visual Studio Version 2022 (v143, C++ 14 Standard)\n- **Release Mode:** Visual Studio release mode was used for benchmarking.\n\n| File Name    | File Size (KB) | Load time (Milliseconds)  | Memory Usage   |\n|--------------|---------------:|:-------------------------:|:--------------:|\n|  rungholt    |     269 215    |           1271            |    594MB       |\n|  powerplant  |     798 723    |           3563            |    1.6GB       |\n|  san-miguel  |   1 116 252    |           4982            |    2.1GB       |\n\nTime was evaluated through 10 iterative runs, calculating the average execution time.\u003cbr\u003e\nMemory usage was analyzed using Visual Studio 2022 C++17 Diagnostic Tools in Release mode.\u003cbr\u003e\n*See section [Benchmark code](https://github.com/StefanJohnsen/WavefrontOBJ#benchmark-code) at the end of this document.*\u003cbr\u003e\n\nThe files above are sourced from [**Morgan McGuire, Computer Graphics Archive, July 2017**](https://casual-effects.com/g3d/data10).\u003cbr\u003e\u003cbr\u003e\n*The benchmark results vary based on the computer's hardware and software configuration.*\n\n## References\nThe following sources have been utilized in developing this Wavefront OBJ parser.\n\n[Paul Bourke: Object Files (OBJ)](http://paulbourke.net/dataformats/obj/)\n\n[Wikipedia: Wavefront .obj file](https://en.wikipedia.org/wiki/Wavefront_.obj_file)\n\n## License\nThis software is released under the GNU General Public License v3.0 terms.\u003cbr\u003e \nDetails and terms of this license can be found at: https://www.gnu.org/licenses/gpl-3.0.html\u003cbr\u003e\u003cbr\u003e\nFor those who require the freedom to operate without the constraints of the GPL,\u003cbr\u003e\na commercial license can be obtained by contacting the author at stefan.johnsen@outlook.com\n\n--- \n\n## Need a Wavefront Material Template Library (MTL) parser?\nWhen working with Wavefront OBJ files, having a robust Wavefront Material Template Library (MTL) parser can greatly enhance your workflow.\nWavefrontOBJ is designed to complement and work seamlessly with the [WavefrontMTL](https://github.com/StefanJohnsen/WavefrontMTL) repository.\n\n## Sample codes\n\n### Load and get vertex manually\n```cpp\nobj::Load obj;\n\nif (!obj.load(\"C:\\\\temp\\\\example.obj\"))\n\treturn 1;\n\nauto vertex = obj.vertex.v.begin();\n\nfor (const auto\u0026 size : obj.vertex.s)\n{\n\tobj::VertexFormat format = obj::vertexFormat(size);\n\n\tswitch (format)\n\t{\n\t\tcase obj::xyz:\n\t\t{\n\t\t\tdouble x = *(vertex + 0);\n\t\t\tdouble y = *(vertex + 1);\n\t\t\tdouble z = *(vertex + 2);\n\n//\t\t\t... your code here\n\n\t\t\tbreak;\n\t\t}\n\t\n\t\tcase obj::xyzw:\n\t\t{\n\t\t\tdouble x = *(vertex + 0);\n\t\t\tdouble y = *(vertex + 1);\n\t\t\tdouble z = *(vertex + 2);\n\t\t\tdouble w = *(vertex + 3);\n\t\t\tbreak;\n\t\t}\n\t\n\t\tcase obj::xyzrgb:\n\t\t{\n\t\t\tdouble x = *(vertex + 0);\n\t\t\tdouble y = *(vertex + 1);\n\t\t\tdouble z = *(vertex + 2);\n\t\t\tdouble r = *(vertex + 3);\n\t\t\tdouble g = *(vertex + 4);\n\t\t\tdouble b = *(vertex + 5);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tvertex += size;\n}\n```\n\n### Load and get texture manually\n```cpp\nobj::Load obj;\n\nif (!obj.load(\"C:\\\\temp\\\\example.obj\"))\n\treturn 1;\n\nauto texture = obj.texture.v.begin();\n\nfor (const auto\u0026 size : obj.texture.s)\n{\n\tobj::TextureFormat format = obj::textureFormat(size);\n\n\tswitch (format)\n\t{\n\t\tcase obj::uv:\n\t\t{\n\t\t\tdouble u = *(texture + 0);\n\t\t\tdouble v = *(texture + 1);\n\t\t\tbreak;\n\t\t}\n\n\t\tcase obj::uvw:\n\t\t{\n\t\t\tdouble u = *(texture + 0);\n\t\t\tdouble v = *(texture + 1);\n\t\t\tdouble w = *(texture + 2);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tvertex += size;\n}\n```\n\n### Load and get normal manually\n```cpp\nobj::Load obj;\n\nif (!obj.load(\"C:\\\\temp\\\\example.obj\"))\n\treturn 1;\n\nauto normal = obj.normal.v.begin();\n\nfor (const auto\u0026 size : obj.normal.s)\n{\n\tdouble x = *(normal + 0);\n\tdouble y = *(normal + 1);\n\tdouble z = *(normal + 2);\n\n\tnormal += size;\n}\n```\n\n## Benchmark code\nThis code snippet demonstrates the file-loading performance for OBJ and MTL files. The program loads each file 10 times and calculates the average time taken for loading. The resulting average loading times are then displayed, providing insights into the efficiency of loading processes enabled by the WavefrontOBJ and WavefrontMTL libraries.\n\n```cpp\n#include \"WavefrontOBJ.h\"\n#include \"WavefrontMTL.h\"\n#include \u003ciostream\u003e\n#include \u003cchrono\u003e\n\nusing namespace std::chrono;\n\ntemplate\u003ctypename Wavefront\u003e\nvoid SpeedTest(const std::string\u0026 file)\n{\n\tstd::cout \u003c\u003c std::endl \u003c\u003c \"File \" \u003c\u003c file \u003c\u003c \" \";\n\n\tint count(0);\n\n\tint number_of_runs(10);\n\n\tmicroseconds microSeconds(0);\n\n\twhile (count++ \u003c number_of_runs)\n\t{\n\t\tWavefront load;\n\n\t\tstd::cout \u003c\u003c \".\";\n\n\t\tauto start = high_resolution_clock::now();\n\n\t\tif (!load.load(file)) return;\n\n\t\tauto stop = high_resolution_clock::now();\n\n\t\tmicroSeconds += duration_cast\u003cmicroseconds\u003e(stop - start);\n\t}\n\n\tmicroSeconds = std::chrono::microseconds(microSeconds.count() / number_of_runs);\n\n\tif(microSeconds.count() \u003e 1000)\n\t{\n\t\tauto milliSeconds = duration_cast\u003cmilliseconds\u003e(microSeconds);\n\n\t\tstd::cout \u003c\u003c std::endl \u003c\u003c \"Loading was completed in \" \u003c\u003c milliSeconds.count() \u003c\u003c \" milliseconds\" \u003c\u003c std::endl;\n\t}\n\telse\n\t\tstd::cout \u003c\u003c std::endl \u003c\u003c \"Loading was completed in \" \u003c\u003c microSeconds.count() \u003c\u003c \" microseconds\" \u003c\u003c std::endl;\n}\n\nint main()\n{\n\tSpeedTest\u003cobj::Load\u003e(\"C:\\\\temp\\\\rungholt.obj\");\n\tSpeedTest\u003cmtl::Load\u003e(\"C:\\\\temp\\\\rungholt.mtl\");\n\n\treturn 0;\n}\n```\n\u003cpre\u003e\nFile C:\\temp\\rungholt.obj ..........\nLoading was completed in 1164 milliseconds\n\nFile C:\\temp\\rungholt.mtl ..........\nLoading was completed in 783 microseconds\n\u003c/pre\u003e\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstefanjohnsen%2Fwavefrontobj","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstefanjohnsen%2Fwavefrontobj","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstefanjohnsen%2Fwavefrontobj/lists"}