Files
phy/tobj/index.html
Orion Kindel 0ce894e6b0 doc
2025-03-18 10:30:23 -05:00

195 lines
22 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Tiny OBJ Loader"><title>tobj - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-42caa33d.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="tobj" data-themes="" data-resource-suffix="" data-rustdoc-version="1.84.0 (9fc6b4312 2025-01-07)" data-channel="1.84.0" data-search-js="search-92e6798f.js" data-settings-js="settings-0f613d39.js" ><script src="../static.files/storage-59e33391.js"></script><script defer src="../crates.js"></script><script defer src="../static.files/main-5f194d8c.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-893ab5e7.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-6580c154.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod crate"><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="mobile-topbar"><button class="sidebar-menu-toggle" title="show sidebar"></button></nav><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../tobj/index.html">tobj</a><span class="version">4.0.2</span></h2></div><div class="sidebar-elems"><ul class="block"><li><a id="all-types" href="all.html">All Items</a></li></ul><section id="rustdoc-toc"><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#tiny-obj-loader" title="Tiny OBJ Loader">Tiny OBJ Loader</a><ul><li><a href="#triangulation" title="Triangulation">Triangulation</a></li><li><a href="#optional--normals--texture-coordinates" title="Optional Normals &#38; Texture Coordinates">Optional Normals &amp; Texture Coordinates</a></li><li><a href="#flat-data" title="Flat Data">Flat Data</a></li><li><a href="#indices" title="Indices">Indices</a></li><li><a href="#materials" title="Materials">Materials</a></li><li><a href="#example" title="Example">Example</a></li><li><a href="#rendering-examples" title="Rendering Examples">Rendering Examples</a></li><li><a href="#features" title="Features">Features</a></li></ul></li></ul><h3><a href="#structs">Crate Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#enums" title="Enums">Enums</a></li><li><a href="#constants" title="Constants">Constants</a></li><li><a href="#functions" title="Functions">Functions</a></li><li><a href="#types" title="Type Aliases">Type Aliases</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer"></div><main><div class="width-limiter"><rustdoc-search></rustdoc-search><section id="main-content" class="content"><div class="main-heading"><h1>Crate <span>tobj</span><button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/tobj/lib.rs.html#1-2208">Source</a> </span></div><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><h2 id="tiny-obj-loader"><a class="doc-anchor" href="#tiny-obj-loader">§</a>Tiny OBJ Loader</h2>
<p>A tiny OBJ loader, inspired by Syoyos excellent <a href="https://github.com/syoyo/tinyobjloader"><code>tinyobjloader</code></a>.
Aims to be a simple and lightweight option for loading <code>OBJ</code> files.</p>
<p>Just returns two <code>Vec</code>s containing loaded models and materials.</p>
<h3 id="triangulation"><a class="doc-anchor" href="#triangulation">§</a>Triangulation</h3>
<p>Meshes can be triangulated on the fly or left as-is.</p>
<p>Only polygons that are trivially convertible to triangle fans are supported.
Arbitrary polygons may not behave as expected. The best solution would be to
convert your mesh to solely consist of triangles in your modeling software.</p>
<h3 id="optional--normals--texture-coordinates"><a class="doc-anchor" href="#optional--normals--texture-coordinates">§</a>Optional Normals &amp; Texture Coordinates</h3>
<p>It is assumed that all meshes will at least have positions, but normals and
texture coordinates are optional.</p>
<p>If no normals or texture coordinates are found then the corresponding
<a href="struct.Mesh.html#structfield.normals" title="field tobj::Mesh::normals"><code>Vec</code></a>s for the <a href="struct.Mesh.html" title="struct tobj::Mesh"><code>Mesh</code></a> will be empty.</p>
<h3 id="flat-data"><a class="doc-anchor" href="#flat-data">§</a>Flat Data</h3>
<p>Values are stored packed as <a href="https://doc.rust-lang.org/1.84.0/std/primitive.f32.html" title="primitive f32"><code>f32</code></a>s (or <a href="https://doc.rust-lang.org/1.84.0/std/primitive.f64.html" title="primitive f64"><code>f64</code></a>s with the use_f64 feature)
in flat <code>Vec</code>s.</p>
<p>For example, the <code>positions</code> member of a <code>Mesh</code> will contain <code>[x, y, z, x, y, z, ...]</code> which you can then use however you like.</p>
<h3 id="indices"><a class="doc-anchor" href="#indices">§</a>Indices</h3>
<p>Indices are also loaded and may re-use vertices already existing in the
mesh, this data is stored in the <a href="struct.Mesh.html#structfield.indices" title="field tobj::Mesh::indices"><code>indices</code></a> member.</p>
<p>When a <code>Mesh</code> contains <em>per vertex per face</em> normals or texture coordinates,
positions can be duplicated to be <em>per vertex per face</em> too via the
<a href="struct.LoadOptions.html#structfield.single_index" title="field tobj::LoadOptions::single_index"><code>single_index</code></a> flag. This potentially changes
the topology (faces may become disconnected even though their vertices still
share a position in space).</p>
<p>By default separate indices for normals and texture coordinates are created.
This also guarantees that the topology of the <code>Mesh</code> does <em>not</em> change when
either of the latter are specified <em>per vertex per face</em>.</p>
<h3 id="materials"><a class="doc-anchor" href="#materials">§</a>Materials</h3>
<p>Standard <code>MTL</code> attributes are supported too. Any unrecognized parameters
will be stored in a <code>HashMap</code> containing the key-value pairs of the
unrecognized parameter and its value.</p>
<h3 id="example"><a class="doc-anchor" href="#example">§</a>Example</h3>
<p>In this simple example we load the classic Cornell Box model that only
defines positions and print out its attributes. This example is a slightly
trimmed down version of <code>print_model_info</code> and <code>print_material_info</code>
combined together, see them for a version that also prints out normals and
texture coordinates if the model has them.</p>
<p>The <a href="struct.LoadOptions.html" title="struct tobj::LoadOptions"><code>LoadOptions</code></a> used are typical for the case when the mesh is going to
be sent to a realtime rendering context (game engine, GPU etc.).</p>
<div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">use </span>tobj;
<span class="kw">let </span>cornell_box = tobj::load_obj(<span class="string">"obj/cornell_box.obj"</span>, <span class="kw-2">&amp;</span>tobj::GPU_LOAD_OPTIONS);
<span class="macro">assert!</span>(cornell_box.is_ok());
<span class="kw">let </span>(models, materials) = cornell_box.expect(<span class="string">"Failed to load OBJ file"</span>);
<span class="comment">// Materials might report a separate loading error if the MTL file wasn't found.
// If you don't need the materials, you can generate a default here and use that
// instead.
</span><span class="kw">let </span>materials = materials.expect(<span class="string">"Failed to load MTL file"</span>);
<span class="macro">println!</span>(<span class="string">"# of models: {}"</span>, models.len());
<span class="macro">println!</span>(<span class="string">"# of materials: {}"</span>, materials.len());
<span class="kw">for </span>(i, m) <span class="kw">in </span>models.iter().enumerate() {
<span class="kw">let </span>mesh = <span class="kw-2">&amp;</span>m.mesh;
<span class="macro">println!</span>(<span class="string">"model[{}].name = \'{}\'"</span>, i, m.name);
<span class="macro">println!</span>(<span class="string">"model[{}].mesh.material_id = {:?}"</span>, i, mesh.material_id);
<span class="macro">println!</span>(
<span class="string">"Size of model[{}].face_arities: {}"</span>,
i,
mesh.face_arities.len()
);
<span class="kw">let </span><span class="kw-2">mut </span>next_face = <span class="number">0</span>;
<span class="kw">for </span>f <span class="kw">in </span><span class="number">0</span>..mesh.face_arities.len() {
<span class="kw">let </span>end = next_face + mesh.face_arities[f] <span class="kw">as </span>usize;
<span class="kw">let </span>face_indices: Vec&lt;<span class="kw">_</span>&gt; = mesh.indices[next_face..end].iter().collect();
<span class="macro">println!</span>(<span class="string">" face[{}] = {:?}"</span>, f, face_indices);
next_face = end;
}
<span class="comment">// Normals and texture coordinates are also loaded, but not printed in this example
</span><span class="macro">println!</span>(<span class="string">"model[{}].vertices: {}"</span>, i, mesh.positions.len() / <span class="number">3</span>);
<span class="macro">assert!</span>(mesh.positions.len() % <span class="number">3 </span>== <span class="number">0</span>);
<span class="kw">for </span>v <span class="kw">in </span><span class="number">0</span>..mesh.positions.len() / <span class="number">3 </span>{
<span class="macro">println!</span>(
<span class="string">" v[{}] = ({}, {}, {})"</span>,
v,
mesh.positions[<span class="number">3 </span>* v],
mesh.positions[<span class="number">3 </span>* v + <span class="number">1</span>],
mesh.positions[<span class="number">3 </span>* v + <span class="number">2</span>]
);
}
}
<span class="kw">for </span>(i, m) <span class="kw">in </span>materials.iter().enumerate() {
<span class="macro">println!</span>(<span class="string">"material[{}].name = \'{}\'"</span>, i, m.name);
<span class="kw">if let </span><span class="prelude-val">Some</span>(ambient) = m.ambient {
<span class="macro">println!</span>(
<span class="string">" material.Ka = ({}, {}, {})"</span>,
ambient[<span class="number">0</span>], ambient[<span class="number">1</span>], ambient[<span class="number">2</span>]
);
}
<span class="kw">if let </span><span class="prelude-val">Some</span>(diffuse) = m.diffuse {
<span class="macro">println!</span>(
<span class="string">" material.Kd = ({}, {}, {})"</span>,
diffuse[<span class="number">0</span>], diffuse[<span class="number">1</span>], diffuse[<span class="number">2</span>]
);
}
<span class="kw">if let </span><span class="prelude-val">Some</span>(specular) = m.specular {
<span class="macro">println!</span>(
<span class="string">" material.Ks = ({}, {}, {})"</span>,
specular[<span class="number">0</span>], specular[<span class="number">1</span>], specular[<span class="number">2</span>]
);
}
<span class="kw">if let </span><span class="prelude-val">Some</span>(shininess) = m.shininess {
<span class="macro">println!</span>(<span class="string">" material.Ns = {}"</span>, shininess);
}
<span class="kw">if let </span><span class="prelude-val">Some</span>(dissolve) = m.dissolve {
<span class="macro">println!</span>(<span class="string">" material.d = {}"</span>, dissolve);
}
<span class="kw">if let </span><span class="prelude-val">Some</span>(ambient_texture) = <span class="kw-2">&amp;</span>m.ambient_texture {
<span class="macro">println!</span>(<span class="string">" material.map_Ka = {}"</span>, ambient_texture);
}
<span class="kw">if let </span><span class="prelude-val">Some</span>(diffuse_texture) = <span class="kw-2">&amp;</span>m.diffuse_texture {
<span class="macro">println!</span>(<span class="string">" material.map_Kd = {}"</span>, diffuse_texture);
}
<span class="kw">if let </span><span class="prelude-val">Some</span>(specular_texture) = <span class="kw-2">&amp;</span>m.specular_texture {
<span class="macro">println!</span>(<span class="string">" material.map_Ks = {}"</span>, specular_texture);
}
<span class="kw">if let </span><span class="prelude-val">Some</span>(shininess_texture) = <span class="kw-2">&amp;</span>m.shininess_texture {
<span class="macro">println!</span>(<span class="string">" material.map_Ns = {}"</span>, shininess_texture);
}
<span class="kw">if let </span><span class="prelude-val">Some</span>(normal_texture) = <span class="kw-2">&amp;</span>m.normal_texture {
<span class="macro">println!</span>(<span class="string">" material.map_Bump = {}"</span>, normal_texture);
}
<span class="kw">if let </span><span class="prelude-val">Some</span>(dissolve_texture) = <span class="kw-2">&amp;</span>m.dissolve_texture {
<span class="macro">println!</span>(<span class="string">" material.map_d = {}"</span>, dissolve_texture);
}
<span class="kw">for </span>(k, v) <span class="kw">in </span><span class="kw-2">&amp;</span>m.unknown_param {
<span class="macro">println!</span>(<span class="string">" material.{} = {}"</span>, k, v);
}
}</code></pre></div>
<h3 id="rendering-examples"><a class="doc-anchor" href="#rendering-examples">§</a>Rendering Examples</h3>
<p>For an example of integration with <a href="https://github.com/tomaka/glium">glium</a>
to make a simple OBJ viewer, check out <a href="https://github.com/Twinklebear/tobj_viewer"><code>tobj viewer</code></a>.
Some more sample images can be found in <a href="http://imgur.com/a/xsg6v">this gallery</a>.</p>
<p>The Rungholt model shown below is reasonably large (6.7M triangles, 12.3M
vertices) and is loaded in ~7.47s using a peak of ~1.1GB of memory on a
Windows 10 machine with an i7-4790k and 16GB of 1600Mhz DDR3 RAM with tobj
0.1.1 on rustc 1.6.0. The model can be found on <a href="http://graphics.cs.williams.edu/data/meshes.xml">Morgan McGuires</a>
meshes page and was originally built by kescha. Future work will focus on
improving performance and memory usage.</p>
<p><img src="http://i.imgur.com/wImyNG4.png" alt="Rungholt"
style="display:block; max-width:100%; height:auto"></p>
<p>For an example of integration within a ray tracer, check out tray_rusts
<a href="https://github.com/Twinklebear/tray_rust/blob/master/src/geometry/mesh.rs">mesh module</a>.
The Stanford Buddha and Dragon from the
<a href="http://graphics.stanford.edu/data/3Dscanrep/">Stanford 3D Scanning Repository</a>
both load quite quickly. The Rust logo model was made by <a href="http://blenderartists.org/forum/showthread.php?362836-Rust-language-3D-logo">Nylithius on BlenderArtists</a>.
The materials used are from the <a href="http://www.merl.com/brdf/">MERL BRDF Database</a>.</p>
<p><img src="http://i.imgur.com/E1ylrZW.png" alt="Rust logo with friends"
style="display:block; max-width:100%; height:auto"></p>
<h3 id="features"><a class="doc-anchor" href="#features">§</a>Features</h3>
<ul>
<li>
<p><a href="https://crates.io/crates/ahash"><code>ahash</code></a> On by default. Use <a href="https://docs.rs/ahash/latest/ahash/struct.AHashMap.html"><code>AHashMap</code></a>
for hashing when reading files and merging vertices. To disable and use
the slower <a href="https://doc.rust-lang.org/1.84.0/std/collections/hash/map/struct.HashMap.html" title="struct std::collections::hash::map::HashMap"><code>HashMap</code></a> instead, unset default
features in <code>Cargo.toml</code>:</p>
<div class="example-wrap"><pre class="language-toml"><code>[dependencies.tobj]
default-features = false</code></pre></div></li>
<li>
<p><a href="LoadOptions::merge_identical_points"><code>merging</code></a> Adds support for
merging identical vertex positions on disconnected faces during import.</p>
<p><strong>Warning:</strong> this feature uses <em>const generics</em> and thus requires at
least a <code>beta</code> toolchain to build.</p>
</li>
<li>
<p><a href="LoadOptions::reorder_data"><code>reordering</code></a> Adds support for reordering
the normal- and texture coordinate indices.</p>
</li>
<li>
<p><a href="load_obj_buf_async"><code>async</code></a> Adds support for async loading of obj
files from a buffer, with an async material loader. Useful in environments
that do not support blocking IO (e.g. WebAssembly).</p>
</li>
<li>
<p>[use_f64] - Uses double-precision (f64) instead of single-precision
(f32) floating point types</p>
</li>
</ul>
</div></details><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><ul class="item-table"><li><div class="item-name"><a class="struct" href="struct.LoadOptions.html" title="struct tobj::LoadOptions">Load<wbr>Options</a></div><div class="desc docblock-short">Options for processing the mesh during loading.</div></li><li><div class="item-name"><a class="struct" href="struct.Material.html" title="struct tobj::Material">Material</a></div><div class="desc docblock-short">A material that may be referenced by one or more <a href="struct.Mesh.html" title="struct tobj::Mesh"><code>Mesh</code></a>es.</div></li><li><div class="item-name"><a class="struct" href="struct.Mesh.html" title="struct tobj::Mesh">Mesh</a></div><div class="desc docblock-short">A mesh made up of triangles loaded from some <code>OBJ</code> file.</div></li><li><div class="item-name"><a class="struct" href="struct.Model.html" title="struct tobj::Model">Model</a></div><div class="desc docblock-short">A named model within the file.</div></li></ul><h2 id="enums" class="section-header">Enums<a href="#enums" class="anchor">§</a></h2><ul class="item-table"><li><div class="item-name"><a class="enum" href="enum.LoadError.html" title="enum tobj::LoadError">Load<wbr>Error</a></div><div class="desc docblock-short">Possible errors that may occur while loading <code>OBJ</code> and <code>MTL</code> files.</div></li></ul><h2 id="constants" class="section-header">Constants<a href="#constants" class="anchor">§</a></h2><ul class="item-table"><li><div class="item-name"><a class="constant" href="constant.GPU_LOAD_OPTIONS.html" title="constant tobj::GPU_LOAD_OPTIONS">GPU_<wbr>LOAD_<wbr>OPTIONS</a></div><div class="desc docblock-short">Typical <a href="struct.LoadOptions.html" title="struct tobj::LoadOptions"><code>LoadOptions</code></a> for using meshes in a GPU/relatime context.</div></li><li><div class="item-name"><a class="constant" href="constant.OFFLINE_RENDERING_LOAD_OPTIONS.html" title="constant tobj::OFFLINE_RENDERING_LOAD_OPTIONS">OFFLINE_<wbr>RENDERING_<wbr>LOAD_<wbr>OPTIONS</a></div><div class="desc docblock-short">Typical <a href="struct.LoadOptions.html" title="struct tobj::LoadOptions"><code>LoadOptions</code></a> for using meshes with an offline rendeder.</div></li></ul><h2 id="functions" class="section-header">Functions<a href="#functions" class="anchor">§</a></h2><ul class="item-table"><li><div class="item-name"><a class="fn" href="fn.load_mtl.html" title="fn tobj::load_mtl">load_<wbr>mtl</a></div><div class="desc docblock-short">Load the materials defined in a <code>MTL</code> file.</div></li><li><div class="item-name"><a class="fn" href="fn.load_mtl_buf.html" title="fn tobj::load_mtl_buf">load_<wbr>mtl_<wbr>buf</a></div><div class="desc docblock-short">Load the various materials in a <code>MTL</code> buffer.</div></li><li><div class="item-name"><a class="fn" href="fn.load_obj.html" title="fn tobj::load_obj">load_<wbr>obj</a></div><div class="desc docblock-short">Load the various objects specified in the <code>OBJ</code> file and any associated
<code>MTL</code> file.</div></li><li><div class="item-name"><a class="fn" href="fn.load_obj_buf.html" title="fn tobj::load_obj_buf">load_<wbr>obj_<wbr>buf</a></div><div class="desc docblock-short">Load the various meshes in an <code>OBJ</code> buffer.</div></li></ul><h2 id="types" class="section-header">Type Aliases<a href="#types" class="anchor">§</a></h2><ul class="item-table"><li><div class="item-name"><a class="type" href="type.LoadResult.html" title="type tobj::LoadResult">Load<wbr>Result</a></div><div class="desc docblock-short">A <a href="https://doc.rust-lang.org/1.84.0/core/result/enum.Result.html" title="enum core::result::Result"><code>Result</code></a> containing all the models loaded from the file and any
materials from referenced material libraries. Or an error that occured while
loading.</div></li><li><div class="item-name"><a class="type" href="type.MTLLoadResult.html" title="type tobj::MTLLoadResult">MTLLoad<wbr>Result</a></div><div class="desc docblock-short">A <a href="https://doc.rust-lang.org/1.84.0/core/result/enum.Result.html" title="enum core::result::Result"><code>Result</code></a> containing all the materials loaded from the file and a map of
<code>MTL</code> name to index. Or an error that occured while loading.</div></li></ul></section></div></main></body></html>