From 556f50274d992b1dcefd99b533e918b7134be776 Mon Sep 17 00:00:00 2001 From: hal8174 Date: Wed, 2 Oct 2024 23:43:13 +0200 Subject: [PATCH] Add obj parsing --- Cargo.lock | 335 +++++++++++++++++++- ray-tracing-core/src/material.rs | 3 +- ray-tracing-material/src/default.rs | 1 + ray-tracing-material/src/diffuse.rs | 3 +- ray-tracing-material/src/mirror.rs | 1 + ray-tracing-scene/Cargo.toml | 2 + ray-tracing-scene/examples/parse_obj.rs | 10 + ray-tracing-scene/obj/box.obj | 43 +++ ray-tracing-scene/obj/box2.obj | 38 +++ ray-tracing-scene/obj/cornell_box.mtl | 27 ++ ray-tracing-scene/obj/cornell_box.obj | 140 ++++++++ ray-tracing-scene/src/lib.rs | 1 + ray-tracing-scene/src/parse_obj.rs | 403 ++++++++++++++++++++++++ 13 files changed, 1004 insertions(+), 3 deletions(-) create mode 100644 ray-tracing-scene/examples/parse_obj.rs create mode 100644 ray-tracing-scene/obj/box.obj create mode 100644 ray-tracing-scene/obj/box2.obj create mode 100644 ray-tracing-scene/obj/cornell_box.mtl create mode 100644 ray-tracing-scene/obj/cornell_box.obj create mode 100644 ray-tracing-scene/src/parse_obj.rs diff --git a/Cargo.lock b/Cargo.lock index c2d37e7..829cc4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -78,6 +87,30 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide 0.8.0", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "backtrace-ext" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", +] + [[package]] name = "bit_field" version = "0.10.2" @@ -90,6 +123,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "bitstream-io" version = "2.5.3" @@ -211,6 +250,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "exr" version = "1.72.0" @@ -276,6 +325,12 @@ dependencies = [ "weezl", ] +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" + [[package]] name = "half" version = "2.4.1" @@ -358,6 +413,12 @@ dependencies = [ "syn", ] +[[package]] +name = "is_ci" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" + [[package]] name = "itertools" version = "0.12.1" @@ -405,6 +466,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "lock_api" version = "0.4.12" @@ -445,6 +512,37 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "miette" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4edc8853320c2a0dab800fbda86253c8938f6ea88510dc92c5f1ed20e794afc1" +dependencies = [ + "backtrace", + "backtrace-ext", + "cfg-if", + "miette-derive", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -542,6 +640,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "object" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.20.1" @@ -551,6 +658,12 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "owo-colors" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56" + [[package]] name = "paste" version = "1.0.15" @@ -569,7 +682,7 @@ version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", @@ -759,6 +872,8 @@ dependencies = [ name = "ray-tracing-scene" version = "0.1.0" dependencies = [ + "miette", + "nom", "ray-tracing-core", "ray-tracing-material", ] @@ -804,6 +919,25 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "0.38.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -866,6 +1000,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + [[package]] name = "spin" version = "0.9.8" @@ -875,6 +1015,27 @@ dependencies = [ "lock_api", ] +[[package]] +name = "supports-color" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8775305acf21c96926c900ad056abeef436701108518cf890020387236ac5a77" +dependencies = [ + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c0a1e5168041f5f3ff68ff7d95dcb9c8749df29f6e7e89ada40dd4c9de404ee" + +[[package]] +name = "supports-unicode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" + [[package]] name = "syn" version = "2.0.79" @@ -905,12 +1066,33 @@ version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "tev_client" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c845c2d56d4f732d09a32c9ea2cd3f01923be7a5f98d9f7f0a347205c3141036" +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.64" @@ -982,6 +1164,18 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + [[package]] name = "v_frame" version = "0.3.8" @@ -1066,6 +1260,145 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "winnow" version = "0.6.20" diff --git a/ray-tracing-core/src/material.rs b/ray-tracing-core/src/material.rs index cb9e60f..31498e4 100644 --- a/ray-tracing-core/src/material.rs +++ b/ray-tracing-core/src/material.rs @@ -1,7 +1,8 @@ use crate::prelude::*; +use std::fmt::Debug; /// All calculations for the material are done a tangent space of the intersection. -pub trait Material: Sync { +pub trait Material: Sync + Debug { fn eval(&self, w_in: Dir3, w_out: Dir3, rng: &mut R) -> Color; fn sample(&self, w_in: Dir3, rng: &mut R) -> SampleResult { diff --git a/ray-tracing-material/src/default.rs b/ray-tracing-material/src/default.rs index 42d0f26..8b356d1 100644 --- a/ray-tracing-material/src/default.rs +++ b/ray-tracing-material/src/default.rs @@ -1,5 +1,6 @@ use ray_tracing_core::prelude::*; +#[derive(Debug)] pub struct DefaultMaterial {} impl Material for DefaultMaterial { diff --git a/ray-tracing-material/src/diffuse.rs b/ray-tracing-material/src/diffuse.rs index 1131b53..32df758 100644 --- a/ray-tracing-material/src/diffuse.rs +++ b/ray-tracing-material/src/diffuse.rs @@ -1,7 +1,8 @@ use ray_tracing_core::prelude::*; +#[derive(Debug)] pub struct DiffuseMaterial { - pub(crate) albedo: Color, + albedo: Color, } impl DiffuseMaterial { diff --git a/ray-tracing-material/src/mirror.rs b/ray-tracing-material/src/mirror.rs index f53df0c..546921b 100644 --- a/ray-tracing-material/src/mirror.rs +++ b/ray-tracing-material/src/mirror.rs @@ -1,5 +1,6 @@ use ray_tracing_core::prelude::*; +#[derive(Debug)] pub struct Mirror { color: Color, } diff --git a/ray-tracing-scene/Cargo.toml b/ray-tracing-scene/Cargo.toml index 83e5b19..8ad447c 100644 --- a/ray-tracing-scene/Cargo.toml +++ b/ray-tracing-scene/Cargo.toml @@ -4,5 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +miette = { version = "7.2.0", features = ["fancy"] } +nom = "7.1.3" ray-tracing-core = { path = "../ray-tracing-core" } ray-tracing-material = { path = "../ray-tracing-material" } diff --git a/ray-tracing-scene/examples/parse_obj.rs b/ray-tracing-scene/examples/parse_obj.rs new file mode 100644 index 0000000..7fe5a5f --- /dev/null +++ b/ray-tracing-scene/examples/parse_obj.rs @@ -0,0 +1,10 @@ +use miette::Result; +use ray_tracing_scene::parse_obj::ObjData; + +fn main() -> Result<()> { + let obj = ObjData::new("obj/cornell_box.obj")?; + + dbg!(obj); + + Ok(()) +} diff --git a/ray-tracing-scene/obj/box.obj b/ray-tracing-scene/obj/box.obj new file mode 100644 index 0000000..cf91a8d --- /dev/null +++ b/ray-tracing-scene/obj/box.obj @@ -0,0 +1,43 @@ +o box + +# left side +v 0.5 -0.5 -0.5 +v 0.5 -0.5 0.5 +v 0.5 0.5 0.5 +v 0.5 0.5 -0.5 +f -4 -3 -2 -1 + +# right side +v -0.5 -0.5 -0.5 +v -0.5 -0.5 0.5 +v -0.5 0.5 0.5 +v -0.5 0.5 -0.5 +f -4 -3 -2 -1 + +# bottom side +v -0.5 -0.5 -0.5 +v -0.5 -0.5 0.5 +v 0.5 -0.5 0.5 +v 0.5 -0.5 -0.5 +f -4 -3 -2 -1 + +# top side +v -0.5 0.5 -0.5 +v -0.5 0.5 0.5 +v 0.5 0.5 0.5 +v 0.5 0.5 -0.5 +f -4 -3 -2 -1 + +# front side +v -0.5 -0.5 -0.5 +v -0.5 0.5 -0.5 +v 0.5 0.5 -0.5 +v 0.5 -0.5 -0.5 +f -4 -3 -2 -1 + +# back side +v -0.5 -0.5 0.5 +v -0.5 0.5 0.5 +v 0.5 0.5 0.5 +v 0.5 -0.5 0.5 +f -4 -3 -2 -1 \ No newline at end of file diff --git a/ray-tracing-scene/obj/box2.obj b/ray-tracing-scene/obj/box2.obj new file mode 100644 index 0000000..92aec4c --- /dev/null +++ b/ray-tracing-scene/obj/box2.obj @@ -0,0 +1,38 @@ +# Blender 4.1.1 +# www.blender.org +o box +v -0.500000 -0.500000 0.500000 +v -0.500000 0.500000 0.500000 +v -0.500000 -0.500000 -0.500000 +v -0.500000 0.500000 -0.500000 +v 0.500000 -0.500000 0.500000 +v 0.500000 0.500000 0.500000 +v 0.500000 -0.500000 -0.500000 +v 0.500000 0.500000 -0.500000 +vn -1.0000 -0.0000 -0.0000 +vn -0.0000 -0.0000 -1.0000 +vn 1.0000 -0.0000 -0.0000 +vn -0.0000 -0.0000 1.0000 +vn -0.0000 -1.0000 -0.0000 +vn -0.0000 1.0000 -0.0000 +vt 0.375000 0.000000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.250000 +vt 0.625000 0.500000 +vt 0.375000 0.500000 +vt 0.625000 0.750000 +vt 0.375000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.125000 0.500000 +vt 0.125000 0.750000 +vt 0.875000 0.500000 +vt 0.875000 0.750000 +s 0 +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/4/2 4/3/2 8/5/2 7/6/2 +f 7/6/3 8/5/3 6/7/3 5/8/3 +f 5/8/4 6/7/4 2/9/4 1/10/4 +f 3/11/5 7/6/5 5/8/5 1/12/5 +f 8/5/6 4/13/6 2/14/6 6/7/6 diff --git a/ray-tracing-scene/obj/cornell_box.mtl b/ray-tracing-scene/obj/cornell_box.mtl new file mode 100644 index 0000000..e3a444a --- /dev/null +++ b/ray-tracing-scene/obj/cornell_box.mtl @@ -0,0 +1,27 @@ +newmtl white +Ka 0 0 0 +Kd 1 1 1 +Ks 0 0 0 + +newmtl red +Ka 0 0 0 +Kd 1 0 0 +Ks 0 0 0 + +newmtl green +Ka 0 0 0 +Kd 0 1 0 +Ks 0 0 0 + +newmtl blue +Ka 0 0 0 +Kd 0 0 1 +Ks 0 0 0 + +newmtl light +Ka 20 20 20 +Kd 1 1 1 +Ks 0 0 0 + +newmtl glass +type glass diff --git a/ray-tracing-scene/obj/cornell_box.obj b/ray-tracing-scene/obj/cornell_box.obj new file mode 100644 index 0000000..ccb1eb1 --- /dev/null +++ b/ray-tracing-scene/obj/cornell_box.obj @@ -0,0 +1,140 @@ +# original cornell box data + +mtllib cornell_box.mtl + +o floor +usemtl white +v 552.8 0.0 0.0 +v 0.0 0.0 0.0 +v 0.0 0.0 559.2 +v 549.6 0.0 559.2 + +v 130.0 0.0 65.0 +v 82.0 0.0 225.0 +v 240.0 0.0 272.0 +v 290.0 0.0 114.0 + +v 423.0 0.0 247.0 +v 265.0 0.0 296.0 +v 314.0 0.0 456.0 +v 472.0 0.0 406.0 + +f 1 2 3 4 +f 8 7 6 5 +f 12 11 10 9 + +o light +usemtl light +v 343.0 548.0 227.0 +v 343.0 548.0 332.0 +v 213.0 548.0 332.0 +v 213.0 548.0 227.0 +#f -4 -3 -2 -1 + +o ceiling +usemtl white +v 556.0 548.8 0.0 +v 556.0 548.8 559.2 +v 0.0 548.8 559.2 +v 0.0 548.8 0.0 +f -4 -3 -2 -1 + +o back_wall +usemtl white +v 549.6 0.0 559.2 +v 0.0 0.0 559.2 +v 0.0 548.8 559.2 +v 556.0 548.8 559.2 +f -4 -3 -2 -1 + +o front_wall +usemtl blue +v 549.6 0.0 0 +v 0.0 0.0 0 +v 0.0 548.8 0 +v 556.0 548.8 0 +#f -1 -2 -3 -4 + +o green_wall +usemtl green +v 0.0 0.0 559.2 +v 0.0 0.0 0.0 +v 0.0 548.8 0.0 +v 0.0 548.8 559.2 +f -4 -3 -2 -1 + +o red_wall +usemtl red +v 552.8 0.0 0.0 +v 549.6 0.0 559.2 +v 556.0 548.8 559.2 +v 556.0 548.8 0.0 +f -4 -3 -2 -1 + +o short_block +usemtl glass + +v 130.0 165.0 65.0 +v 82.0 165.0 225.0 +v 240.0 165.0 272.0 +v 290.0 165.0 114.0 +f -4 -3 -2 -1 + +v 290.0 0.0 114.0 +v 290.0 165.0 114.0 +v 240.0 165.0 272.0 +v 240.0 0.0 272.0 +f -4 -3 -2 -1 + +v 130.0 0.0 65.0 +v 130.0 165.0 65.0 +v 290.0 165.0 114.0 +v 290.0 0.0 114.0 +f -4 -3 -2 -1 + +v 82.0 0.0 225.0 +v 82.0 165.0 225.0 +v 130.0 165.0 65.0 +v 130.0 0.0 65.0 +f -4 -3 -2 -1 + +v 240.0 0.0 272.0 +v 240.0 165.0 272.0 +v 82.0 165.0 225.0 +v 82.0 0.0 225.0 +f -4 -3 -2 -1 + +o tall_block +usemtl white + +v 423.0 330.0 247.0 +v 265.0 330.0 296.0 +v 314.0 330.0 456.0 +v 472.0 330.0 406.0 +f -4 -3 -2 -1 + +usemtl white +v 423.0 0.0 247.0 +v 423.0 330.0 247.0 +v 472.0 330.0 406.0 +v 472.0 0.0 406.0 +f -4 -3 -2 -1 + +v 472.0 0.0 406.0 +v 472.0 330.0 406.0 +v 314.0 330.0 456.0 +v 314.0 0.0 456.0 +f -4 -3 -2 -1 + +v 314.0 0.0 456.0 +v 314.0 330.0 456.0 +v 265.0 330.0 296.0 +v 265.0 0.0 296.0 +f -4 -3 -2 -1 + +v 265.0 0.0 296.0 +v 265.0 330.0 296.0 +v 423.0 330.0 247.0 +v 423.0 0.0 247.0 +f -4 -3 -2 -1 + diff --git a/ray-tracing-scene/src/lib.rs b/ray-tracing-scene/src/lib.rs index d56f56c..052ab74 100644 --- a/ray-tracing-scene/src/lib.rs +++ b/ray-tracing-scene/src/lib.rs @@ -1,2 +1,3 @@ pub mod basic_scene; +pub mod parse_obj; pub mod triangle_bvh; diff --git a/ray-tracing-scene/src/parse_obj.rs b/ray-tracing-scene/src/parse_obj.rs new file mode 100644 index 0000000..0908955 --- /dev/null +++ b/ray-tracing-scene/src/parse_obj.rs @@ -0,0 +1,403 @@ +use miette::{bail, miette, Context, IntoDiagnostic, LabeledSpan, Result, Severity}; +use nom::{ + branch::alt, + bytes::complete::{tag, take_till, take_till1}, + character, + error::Error, + multi::{fill, many1}, + number::complete::double, + Finish, IResult, +}; +use ray_tracing_core::prelude::*; +use std::{collections::HashMap, path::Path}; + +#[derive(Debug)] +pub struct ObjData { + pub vertices: Vec, + pub normals: Vec, + pub texcoord: Vec<[Float; 2]>, + pub faces: Vec, + pub materials: Vec, +} + +#[derive(Debug)] +pub struct ObjMaterial { + name: String, + map: HashMap, +} + +#[derive(Debug)] +pub struct Face { + pub v: Vec, + pub t: Option>, + pub n: Option>, + pub mat: Option, +} + +#[derive(Debug)] +pub struct RelativeFace { + pub v: Vec, + pub t: Option>, + pub n: Option>, +} + +#[derive(Debug)] +enum Line<'a> { + Vertex(Pos3), + Normal(Dir3), + Texcoord([Float; 2]), + Face(RelativeFace), + Material(&'a str), + Mtllib(&'a str), + Empty, +} + +fn remove_whitespace(i: &str) -> IResult<&str, ()> { + let (i, _) = take_till(|c| c != ' ')(i)?; + Ok((i, ())) +} + +fn parse_float(i: &str) -> IResult<&str, Float> { + let (i, _) = remove_whitespace(i)?; + double(i).map(|(i, f)| (i, f as Float)) +} + +fn parse_vertex(i: &str) -> IResult<&str, Line> { + let mut v = [0.0; 3]; + let (i, _) = fill(parse_float, &mut v)(i)?; + Ok((i, Line::Vertex(Pos3::new(v[0], v[1], v[2])))) +} + +fn parse_normal(i: &str) -> IResult<&str, Line> { + let mut v = [0.0; 3]; + let (i, _) = fill(parse_float, &mut v)(i)?; + Ok((i, Line::Normal(Dir3::new(v[0], v[1], v[2])))) +} + +fn parse_texcoord(i: &str) -> IResult<&str, Line> { + let mut v = [0.0; 2]; + let (i, _) = fill(parse_float, &mut v)(i)?; + Ok((i, Line::Texcoord(v))) +} + +fn parse_identifier(i: &str) -> IResult<&str, &str> { + let (i, ()) = remove_whitespace(i)?; + alt((tag("#"), take_till(|c| c == ' ')))(i) +} + +fn face_vertex_empty(i: &str) -> IResult<&str, i32> { + let (i, _) = remove_whitespace(i)?; + let (i, v) = character::complete::i32(i)?; + + Ok((i, v)) +} +fn face_vertex_normal(i: &str) -> IResult<&str, (i32, i32)> { + let (i, _) = remove_whitespace(i)?; + let (i, v) = character::complete::i32(i)?; + let (i, _) = tag("//")(i)?; + let (i, n) = character::complete::i32(i)?; + + Ok((i, (v, n))) +} +fn face_vertex_tex(i: &str) -> IResult<&str, (i32, i32)> { + let (i, _) = remove_whitespace(i)?; + let (i, v) = character::complete::i32(i)?; + let (i, _) = tag("/")(i)?; + let (i, t) = character::complete::i32(i)?; + + Ok((i, (v, t))) +} +fn face_vertex_normal_tex(i: &str) -> IResult<&str, (i32, i32, i32)> { + let (i, _) = remove_whitespace(i)?; + let (i, v) = character::complete::i32(i)?; + let (i, _) = tag("/")(i)?; + let (i, t) = character::complete::i32(i)?; + let (i, _) = tag("/")(i)?; + let (i, n) = character::complete::i32(i)?; + + Ok((i, (v, t, n))) +} + +fn parse_face(i: &str) -> IResult<&str, Line> { + if let Ok((i, s)) = many1(face_vertex_normal_tex)(i) { + if s.len() >= 3 { + Ok(( + i, + Line::Face(RelativeFace { + v: s.iter().map(|t| t.0).collect(), + t: Some(s.iter().map(|t| t.1).collect()), + n: Some(s.iter().map(|t| t.2).collect()), + }), + )) + } else { + Err(nom::Err::Error(Error { + input: i, + code: nom::error::ErrorKind::Tag, + })) + } + } else if let Ok((i, s)) = many1(face_vertex_normal)(i) { + if s.len() >= 3 { + Ok(( + i, + Line::Face(RelativeFace { + v: s.iter().map(|t| t.0).collect(), + t: None, + n: Some(s.iter().map(|t| t.1).collect()), + }), + )) + } else { + Err(nom::Err::Error(Error { + input: i, + code: nom::error::ErrorKind::Tag, + })) + } + } else if let Ok((i, s)) = many1(face_vertex_tex)(i) { + if s.len() >= 3 { + Ok(( + i, + Line::Face(RelativeFace { + v: s.iter().map(|t| t.0).collect(), + t: Some(s.iter().map(|t| t.1).collect()), + n: None, + }), + )) + } else { + Err(nom::Err::Error(Error { + input: i, + code: nom::error::ErrorKind::Tag, + })) + } + } else if let Ok((i, s)) = many1(face_vertex_empty)(i) { + if s.len() >= 3 { + Ok(( + i, + Line::Face(RelativeFace { + v: s, + t: None, + n: None, + }), + )) + } else { + Err(nom::Err::Error(Error { + input: i, + code: nom::error::ErrorKind::Tag, + })) + } + } else { + Err(nom::Err::Error(Error { + input: i, + code: nom::error::ErrorKind::Tag, + })) + } +} + +fn parse_mtllib(i: &str) -> IResult<&str, Line> { + let (i, s) = take_till(|c| c == ' ')(i)?; + Ok((i, Line::Mtllib(s))) +} + +fn parse_mtl(i: &str) -> IResult<&str, Line> { + let (i, s) = take_till(|c| c == ' ')(i)?; + Ok((i, Line::Material(s))) +} + +fn parse_line(i: &str) -> IResult<&str, Line> { + let (i, ident) = parse_identifier(i)?; + let (i, _) = remove_whitespace(i)?; + match ident { + "v" => parse_vertex(i), + "#" | "" => Ok((i, Line::Empty)), + "f" => parse_face(i), + "o" => Ok((i, Line::Empty)), + "vn" => parse_normal(i), + "vt" => parse_texcoord(i), + "usemtl" => parse_mtl(i), + "mtllib" => parse_mtllib(i), + _ => Err(nom::Err::Failure(nom::error::Error { + input: i, + code: nom::error::ErrorKind::Fail, + })), + } +} + +fn handle_relative(x: i32, len: i32) -> Result { + if x == 0 { + Err(miette!("Index cannot be 0")) + } else if x > 0 { + if x <= len { + Ok(x as u32 - 1) + } else { + Err(miette!("Index {x} out of bounds")) + } + } else if len + x >= 0 { + Ok((len + x) as u32) + } else { + Err(miette!("Index {x} out of bounds")) + } +} + +enum MaterialsLine<'a> { + Material(&'a str), + KeyValue(&'a str, &'a str), + Empty, +} + +fn parse_new_material(i: &str) -> IResult<&str, MaterialsLine> { + let (i, ident) = take_till1(|c| c == ' ')(i)?; + Ok((i, MaterialsLine::Material(ident))) +} + +fn parse_line_material(i: &str) -> IResult<&str, MaterialsLine> { + let (i, ident) = parse_identifier(i)?; + let (i, _) = remove_whitespace(i)?; + match ident { + "newmtl" => parse_new_material(i), + "#" | "" => Ok((i, MaterialsLine::Empty)), + _ => Ok((i, MaterialsLine::KeyValue(ident, i))), + } +} + +fn read_mtllib(path: impl AsRef) -> Result> { + let string = std::fs::read_to_string(path.as_ref()) + .into_diagnostic() + .with_context(|| format!("opening file {:?}", path.as_ref()))?; + + let mut materials = Vec::new(); + + let mut current_material = None; + + for (i, l) in string.lines().enumerate() { + let t = match parse_line_material(l).finish() { + Ok(t) => t.1, + Err(e) => { + return Err(miette!( + severity = Severity::Error, + code = e.code.description(), + labels = vec![LabeledSpan::at_offset(l.len() - e.input.len(), "here")], + "unable to parse line {}", + i + 1 + ) + .with_source_code(l.to_string())); + } + }; + + match t { + MaterialsLine::Material(name) => { + if let Some(m) = current_material.take() { + materials.push(m); + } + + current_material = Some(ObjMaterial { + name: name.to_string(), + map: HashMap::new(), + }); + } + MaterialsLine::KeyValue(k, v) => { + if let Some(m) = current_material.as_mut() { + m.map.insert(k.to_string(), v.to_string()); + } else { + bail!("Material property appears multiple times in line {}", i + 1); + } + } + MaterialsLine::Empty => (), + } + } + + if let Some(m) = current_material { + materials.push(m); + } + + Ok(materials) +} + +impl ObjData { + pub fn new(path: impl AsRef) -> Result { + let string = std::fs::read_to_string(path.as_ref()) + .into_diagnostic() + .with_context(|| format!("opening file {:?}", path.as_ref()))?; + + let mut vertices = Vec::new(); + let mut normals = Vec::new(); + let mut texcoord = Vec::new(); + let mut faces = Vec::new(); + let mut materials = Vec::new(); + let mut materials_map = HashMap::new(); + + let mut current_material = None; + + for (i, l) in string.lines().enumerate() { + let t = match parse_line(l).finish() { + Ok(t) => t.1, + Err(e) => { + return Err(miette!( + severity = Severity::Error, + code = e.code.description(), + labels = vec![LabeledSpan::at_offset(l.len() - e.input.len(), "here")], + "unable to parse line {}", + i + 1 + ) + .with_source_code(l.to_string())); + } + }; + + match t { + Line::Vertex(v) => vertices.push(v), + Line::Normal(n) => normals.push(n), + Line::Texcoord(t) => texcoord.push(t), + Line::Face(f) => faces.push(Face { + v: f.v + .iter() + .map(|&c| { + handle_relative(c, vertices.len() as i32) + .with_context(|| format!("In line {}", i + 1)) + }) + .collect::>>()?, + t: f.t + .map(|t| { + t.iter() + .map(|&c| { + handle_relative(c, texcoord.len() as i32) + .with_context(|| format!("In line {}", i + 1)) + }) + .collect::>>() + }) + .transpose()?, + n: f.n + .map(|t| { + t.iter() + .map(|&c| { + handle_relative(c, normals.len() as i32) + .with_context(|| format!("In line {}", i + 1)) + }) + .collect::>>() + }) + .transpose()?, + mat: current_material, + }), + Line::Material(s) => { + current_material = Some( + *materials_map + .get(s) + .ok_or(miette!("Unknown material \"{s}\" in line {}", i + 1))?, + ); + } + Line::Mtllib(s) => { + for m in read_mtllib(path.as_ref().parent().ok_or(miette!("Unable "))?.join(s))? + { + materials_map.insert(m.name.clone(), materials.len() as u32); + materials.push(m); + } + } + Line::Empty => (), + } + } + + Ok(Self { + vertices, + normals, + texcoord, + faces, + materials, + }) + } +}