Compare commits
No commits in common. "master" and "main" have entirely different histories.
1
.envrc
|
@ -1 +0,0 @@
|
||||||
use flake
|
|
1
.gitattributes
vendored
|
@ -1 +0,0 @@
|
||||||
assignment-2*/ext/* linguist-vendored
|
|
4
.gitignore
vendored
|
@ -1,4 +0,0 @@
|
||||||
.direnv
|
|
||||||
.pijul
|
|
||||||
|
|
||||||
/target
|
|
2
.ignore
|
@ -1,2 +0,0 @@
|
||||||
.git
|
|
||||||
.DS_Store
|
|
1288
Cargo.lock
generated
20
Cargo.toml
|
@ -1,20 +0,0 @@
|
||||||
[workspace]
|
|
||||||
members = [
|
|
||||||
"assignment-0",
|
|
||||||
"assignment-1a",
|
|
||||||
"assignment-1b",
|
|
||||||
"assignment-1c",
|
|
||||||
"assignment-1d",
|
|
||||||
"assignment-2a-rust",
|
|
||||||
]
|
|
||||||
|
|
||||||
# For profiling with flamegraphs
|
|
||||||
[profile.release]
|
|
||||||
debug = true
|
|
||||||
|
|
||||||
# Optimize for size when creating handin
|
|
||||||
[profile.release-handin]
|
|
||||||
inherits = "release"
|
|
||||||
strip = true
|
|
||||||
lto = true
|
|
||||||
|
|
2
README.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# csci5607
|
||||||
|
|
4
assignment-0/.gitignore
vendored
|
@ -1,4 +0,0 @@
|
||||||
/target
|
|
||||||
input
|
|
||||||
out.ppm
|
|
||||||
handin.tar.gz
|
|
|
@ -1,77 +0,0 @@
|
||||||
# Assignment 0: Working with ASCII images
|
|
||||||
|
|
||||||
In this assignment, you are asked to write a program that creates an image in
|
|
||||||
ASCII PPM format.
|
|
||||||
|
|
||||||
Your program should accept, as a command line argument, the name of a file
|
|
||||||
containing an "image description" (consisting of one line of text specifying the
|
|
||||||
image height and image width, optionally followed other lines of text specifying
|
|
||||||
any additional parameters your program might use), and it should generate a
|
|
||||||
valid ASCII PPM file as output. The name of the output file should end with the
|
|
||||||
suffix .ppm. Your program should be capable of accepting different input files
|
|
||||||
and producing different output files without needing to be recompiled.
|
|
||||||
|
|
||||||
You are free to use whatever means you like to define the contents of the output
|
|
||||||
image. If you have time and are so inclined, you can earn extra credit by doing
|
|
||||||
something creative. Possibilities include: hardcoding an interesting pattern,
|
|
||||||
generating a [procedural texture][1], generating an image of the [Mandelbrot
|
|
||||||
set][2], or reading an image from a file and applying an interesting [filter][3]
|
|
||||||
or function such as [line integral convolution][4]. Whatever approach you
|
|
||||||
choose, the code you turn in **must** be your own.
|
|
||||||
|
|
||||||
[1]: https://en.wikipedia.org/wiki/Procedural_texture
|
|
||||||
[2]: https://en.wikipedia.org/wiki/Mandelbrot_set
|
|
||||||
[3]: https://en.wikipedia.org/wiki/Kernel_(image_processing)
|
|
||||||
[4]: https://en.wikipedia.org/wiki/Line_integral_convolution
|
|
||||||
|
|
||||||
### Detailed instructions
|
|
||||||
|
|
||||||
1. Please use the following syntax to define the image size in your input file:
|
|
||||||
|
|
||||||
imsize width height
|
|
||||||
|
|
||||||
where imsize is a keyword and width and height are integers.
|
|
||||||
|
|
||||||
2. Please use the following syntax to define your output image:
|
|
||||||
|
|
||||||
P3
|
|
||||||
|
|
||||||
# any comments you want to include
|
|
||||||
|
|
||||||
width height
|
|
||||||
|
|
||||||
255
|
|
||||||
|
|
||||||
r(0,0) g(0,0) b(0,0) r(1,0) g(1,0) b(1,0) r(2,0) g(2,0) b(2,0) ...
|
|
||||||
|
|
||||||
Please note that in an ASCII PPM file, each pixel color is defined as an (r, g,
|
|
||||||
b) triple, and the provided values are used to fill the image in row major
|
|
||||||
order. Specifically, the first three entries represent the red, green and blue
|
|
||||||
components of the color of the upper leftmost pixel in the image, the second
|
|
||||||
three entries represent the color of the adjacent pixel to the right, and so on.
|
|
||||||
|
|
||||||
Your program will need to specify exactly one color triple for each pixel in
|
|
||||||
your image. Try to keep the line length under 80 characters, or approximately
|
|
||||||
4-5 pixels per line. It’s also okay to put each color component on its own line
|
|
||||||
too. Do not insert any other characters such as commas, etc. between any of the
|
|
||||||
color values.
|
|
||||||
|
|
||||||
You can use the free program [GIMP] to view your image, to verify that it looks
|
|
||||||
the way you intend it to. GIMP is a general-purpose image editing tool that can
|
|
||||||
also be used to convert images from multiple other formats into ASCII PPM format
|
|
||||||
(and vice versa).
|
|
||||||
|
|
||||||
[gimp]: http://www.gimp.org
|
|
||||||
|
|
||||||
### What you should turn in
|
|
||||||
|
|
||||||
- a readme file that describes your what your program does
|
|
||||||
- all of your source code, clearly commented
|
|
||||||
- at least one ascii PPM image created by your program
|
|
||||||
|
|
||||||
We will plan to share the PPM images in class. If you would prefer that we not
|
|
||||||
show your image, please let us know.
|
|
||||||
|
|
||||||
We will use this rubric: grading-criteria-0.pdf when grading your program. You
|
|
||||||
are advised to check the rubric before beginning the assignment to fully
|
|
||||||
understand how credit will be awarded.
|
|
430
assignment-0/Cargo.lock
generated
|
@ -1,430 +0,0 @@
|
||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "0.7.20"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.68"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "assignment-0"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"clap",
|
|
||||||
"lazy_static",
|
|
||||||
"rand",
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.78"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap"
|
|
||||||
version = "4.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"clap_derive",
|
|
||||||
"clap_lex",
|
|
||||||
"is-terminal",
|
|
||||||
"once_cell",
|
|
||||||
"strsim",
|
|
||||||
"termcolor",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap_derive"
|
|
||||||
version = "4.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
|
|
||||||
dependencies = [
|
|
||||||
"heck",
|
|
||||||
"proc-macro-error",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap_lex"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
|
|
||||||
dependencies = [
|
|
||||||
"os_str_bytes",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno"
|
|
||||||
version = "0.2.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
|
||||||
dependencies = [
|
|
||||||
"errno-dragonfly",
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno-dragonfly"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.2.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "heck"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.2.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "io-lifetimes"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "is-terminal"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"io-lifetimes",
|
|
||||||
"rustix",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.139"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-raw-sys"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "once_cell"
|
|
||||||
version = "1.17.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "os_str_bytes"
|
|
||||||
version = "6.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ppv-lite86"
|
|
||||||
version = "0.2.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error-attr",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error-attr"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.50"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "1.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.6.28"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustix"
|
|
||||||
version = "0.36.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"errno",
|
|
||||||
"io-lifetimes",
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strsim"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "1.0.107"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termcolor"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-ident"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.42.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm",
|
|
||||||
"windows_aarch64_msvc",
|
|
||||||
"windows_i686_gnu",
|
|
||||||
"windows_i686_msvc",
|
|
||||||
"windows_x86_64_gnu",
|
|
||||||
"windows_x86_64_gnullvm",
|
|
||||||
"windows_x86_64_msvc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
|
|
@ -1,12 +0,0 @@
|
||||||
[package]
|
|
||||||
authors = ["Michael Zhang <zhan4854@umn.edu>"]
|
|
||||||
name = "assignment-0"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow = "1.0.68"
|
|
||||||
clap = { version = "4.1.1", features = ["derive", "cargo"] }
|
|
||||||
lazy_static = "1.4.0"
|
|
||||||
rand = "0.8.5"
|
|
||||||
regex = "1.7.1"
|
|
|
@ -1,7 +0,0 @@
|
||||||
.PHONY: clean
|
|
||||||
|
|
||||||
handin.tar.gz:
|
|
||||||
tar -czvf $@ target/release/assignment-0 Cargo.* input out.ppm README.md src
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f handin.tar.gz
|
|
|
@ -1,31 +0,0 @@
|
||||||
Assignment 0: Generating turbulence with Rust!
|
|
||||||
===
|
|
||||||
|
|
||||||
This program generates PPM images.
|
|
||||||
|
|
||||||
Using the program
|
|
||||||
---
|
|
||||||
|
|
||||||
The binary provided has been built for Ubuntu, and has been tested on CSELabs.
|
|
||||||
Run `assignment-0 --help` to find out about all the options for using this
|
|
||||||
program.
|
|
||||||
|
|
||||||
Compiling the source
|
|
||||||
---
|
|
||||||
|
|
||||||
This project is a standard Rust program, and can be built with just a Rust
|
|
||||||
compiler. The version of Rust used is the current stable at the time of writing,
|
|
||||||
1.66.
|
|
||||||
|
|
||||||
Build the program using:
|
|
||||||
|
|
||||||
```
|
|
||||||
cargo build --release
|
|
||||||
```
|
|
||||||
|
|
||||||
The binary can be found in the `target` directory.
|
|
||||||
|
|
||||||
Contact
|
|
||||||
---
|
|
||||||
|
|
||||||
Author: Michael Zhang
|
|
|
@ -1,34 +0,0 @@
|
||||||
use std::io::{Result, Write};
|
|
||||||
|
|
||||||
/// A 24-bit pixel represented by a red, green, and blue value.
|
|
||||||
pub struct Pixel(pub u8, pub u8, pub u8);
|
|
||||||
|
|
||||||
/// A representation of an image
|
|
||||||
pub struct Image {
|
|
||||||
/// Width in pixels
|
|
||||||
pub(crate) width: usize,
|
|
||||||
|
|
||||||
/// Height in pixels
|
|
||||||
pub(crate) height: usize,
|
|
||||||
|
|
||||||
/// Pixel data in row-major form.
|
|
||||||
pub(crate) data: Vec<Pixel>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Image {
|
|
||||||
/// Write the image in PPM format to a file.
|
|
||||||
pub fn write(&self, mut w: impl Write) -> Result<()> {
|
|
||||||
// Header
|
|
||||||
let header = format!("P3 {} {} 255\n", self.width, self.height);
|
|
||||||
w.write_all(header.as_bytes())?;
|
|
||||||
|
|
||||||
// Pixel data
|
|
||||||
for pixel in self.data.iter() {
|
|
||||||
let Pixel(red, green, blue) = pixel;
|
|
||||||
let pixel = format!("{red} {green} {blue}\n");
|
|
||||||
w.write_all(pixel.as_bytes())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,111 +0,0 @@
|
||||||
use std::{
|
|
||||||
fs::File,
|
|
||||||
io::Read,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
|
||||||
use clap::{Parser, ValueEnum};
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use regex::Regex;
|
|
||||||
use turbulence::generate_turbulence;
|
|
||||||
|
|
||||||
use crate::value_noise::generate_noise;
|
|
||||||
|
|
||||||
mod image;
|
|
||||||
mod turbulence;
|
|
||||||
mod value_noise;
|
|
||||||
mod vec2;
|
|
||||||
|
|
||||||
/// Noise image generator.
|
|
||||||
#[derive(Parser)]
|
|
||||||
#[clap(author, version, about, long_about = None)]
|
|
||||||
struct Opt {
|
|
||||||
/// Path to the input file to use.
|
|
||||||
///
|
|
||||||
/// The input file should follow this format:
|
|
||||||
///
|
|
||||||
/// imsize [width] [height]
|
|
||||||
///
|
|
||||||
/// Where `imsize' is a keyword, and `width' and `height' are integer values
|
|
||||||
/// denoting the desired size of the image to be generated.
|
|
||||||
#[clap()]
|
|
||||||
input_path: PathBuf,
|
|
||||||
|
|
||||||
/// The algorithm to use for pattern generation.
|
|
||||||
#[clap(long = "algorithm", default_value = "turbulence")]
|
|
||||||
algorithm: Algorithm,
|
|
||||||
|
|
||||||
/// The output image path.
|
|
||||||
#[clap(short = 'o', long = "out", default_value = "out.ppm")]
|
|
||||||
output_path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(ValueEnum, Clone)]
|
|
||||||
enum Algorithm {
|
|
||||||
/// Generates noise, which is linearly interpolated randomness.
|
|
||||||
Noise,
|
|
||||||
|
|
||||||
/// Fractal sum made with signed noise, used to resemble smoke.
|
|
||||||
Turbulence,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
|
||||||
let opt = Opt::parse();
|
|
||||||
|
|
||||||
let (width, height) = parse_input_file(&opt.input_path)?;
|
|
||||||
|
|
||||||
// We will use the default thread-local rng. Future work could include
|
|
||||||
// allowing the rng to be seedable from the command line
|
|
||||||
let rng = rand::thread_rng();
|
|
||||||
|
|
||||||
// Pick the algorithm to use based on the option passed via command line
|
|
||||||
let ppm = match opt.algorithm {
|
|
||||||
Algorithm::Noise => generate_noise(width, height, rng),
|
|
||||||
Algorithm::Turbulence => generate_turbulence(width, height, rng),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Write the PPM image to the output file specified
|
|
||||||
{
|
|
||||||
let file = File::create(&opt.output_path).with_context(|| {
|
|
||||||
format!("Could not create file {:?}.", opt.output_path)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
ppm.write(file).with_context(|| {
|
|
||||||
format!("Could not write to file {:?}.", opt.output_path)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref INPUT_PATTERN: Regex =
|
|
||||||
Regex::new(r"imsize\s+(?P<width>\d+)\s+(?P<height>\d+)")
|
|
||||||
.expect("Failed to compile regex.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse the input file, returning the target image dimensions
|
|
||||||
fn parse_input_file(path: impl AsRef<Path>) -> Result<(usize, usize)> {
|
|
||||||
let path = path.as_ref();
|
|
||||||
|
|
||||||
// Read the contents from the file
|
|
||||||
let contents = {
|
|
||||||
let mut contents = String::new();
|
|
||||||
let mut file = File::open(path)?;
|
|
||||||
file.read_to_string(&mut contents)?;
|
|
||||||
contents
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse the contents using regex
|
|
||||||
let matches = match INPUT_PATTERN.captures(&contents) {
|
|
||||||
Some(v) => v,
|
|
||||||
None => bail!("Invalid input file syntax."),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Extract the parsed captures and convert to int
|
|
||||||
let width = matches.name("width").unwrap().as_str().parse()?;
|
|
||||||
let height = matches.name("height").unwrap().as_str().parse()?;
|
|
||||||
|
|
||||||
Ok((width, height))
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
// Follows this algorithm:
|
|
||||||
// https://www.scratchapixel.com/lessons/procedural-generation-virtual-worlds/procedural-patterns-noise-part-1/simple-pattern-examples.html
|
|
||||||
|
|
||||||
use rand::RngCore;
|
|
||||||
|
|
||||||
use crate::image::{Image, Pixel};
|
|
||||||
use crate::value_noise::ValueNoise;
|
|
||||||
use crate::vec2::Vec2;
|
|
||||||
|
|
||||||
pub fn generate_turbulence(
|
|
||||||
width: usize,
|
|
||||||
height: usize,
|
|
||||||
rng: impl RngCore,
|
|
||||||
) -> Image {
|
|
||||||
let mut noise_map = vec![0.0; width * height];
|
|
||||||
let noise = ValueNoise::new(rng);
|
|
||||||
|
|
||||||
let frequency = 0.02;
|
|
||||||
let frequency_mult = 1.8;
|
|
||||||
let amplitude_mult = 0.35;
|
|
||||||
let num_layers = 5;
|
|
||||||
let mut max_noise_val = 0.0f64;
|
|
||||||
|
|
||||||
for j in 0..height {
|
|
||||||
for i in 0..width {
|
|
||||||
let mut noise_point = Vec2::new(i as f64, j as f64) * frequency;
|
|
||||||
let mut amplitude = 1.0;
|
|
||||||
|
|
||||||
for _ in 0..num_layers {
|
|
||||||
noise_map[j * width + i] =
|
|
||||||
(2.0 * noise.eval(noise_point) - 1.0).abs() * amplitude;
|
|
||||||
noise_point = noise_point * frequency_mult;
|
|
||||||
amplitude *= amplitude_mult;
|
|
||||||
}
|
|
||||||
|
|
||||||
max_noise_val = max_noise_val.max(noise_map[j * width + i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = noise_map
|
|
||||||
.into_iter()
|
|
||||||
.map(|f| {
|
|
||||||
let v = (f / max_noise_val * 192.0 + 32.0).floor() as u8;
|
|
||||||
Pixel(v, v, v)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
Image {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
data,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
// Follows this algorithm:
|
|
||||||
// https://www.scratchapixel.com/lessons/procedural-generation-virtual-worlds/procedural-patterns-noise-part-1/creating-simple-2D-noise.html
|
|
||||||
|
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
use rand::{Rng, RngCore};
|
|
||||||
|
|
||||||
use crate::image::{Pixel, Image};
|
|
||||||
use crate::vec2::Vec2;
|
|
||||||
|
|
||||||
const MAX_TABLE_SIZE: usize = 256;
|
|
||||||
const MAX_TABLE_SIZE_MASK: usize = MAX_TABLE_SIZE - 1;
|
|
||||||
|
|
||||||
pub fn generate_noise(width: usize, height: usize, rng: impl RngCore) -> Image {
|
|
||||||
let mut noise_map = vec![0.0; width * height];
|
|
||||||
let noise = ValueNoise::new(rng);
|
|
||||||
let frequency = 0.05;
|
|
||||||
|
|
||||||
for j in 0..height {
|
|
||||||
for i in 0..width {
|
|
||||||
let vec = Vec2::new(i as f64, j as f64);
|
|
||||||
noise_map[j * width + i] = noise.eval(vec * frequency);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = noise_map
|
|
||||||
.into_iter()
|
|
||||||
.map(|f| {
|
|
||||||
let v = (f * 256.0).floor() as u8;
|
|
||||||
Pixel(v, v, v)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
Image {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ValueNoise {
|
|
||||||
r: [f64; MAX_TABLE_SIZE * MAX_TABLE_SIZE],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ValueNoise {
|
|
||||||
pub fn new(mut rng: impl RngCore) -> Self {
|
|
||||||
let mut r: [f64; MAX_TABLE_SIZE * MAX_TABLE_SIZE] =
|
|
||||||
unsafe { mem::zeroed() };
|
|
||||||
for k in 0..MAX_TABLE_SIZE * MAX_TABLE_SIZE {
|
|
||||||
r[k] = rng.gen_range(0.0..1.0);
|
|
||||||
}
|
|
||||||
ValueNoise { r }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn eval(&self, point: Vec2) -> f64 {
|
|
||||||
let xi = point.x.floor();
|
|
||||||
let yi = point.y.floor();
|
|
||||||
|
|
||||||
let tx = point.x - xi;
|
|
||||||
let ty = point.y - yi;
|
|
||||||
|
|
||||||
let xi = xi as usize;
|
|
||||||
let yi = yi as usize;
|
|
||||||
|
|
||||||
let rx0 = xi & MAX_TABLE_SIZE_MASK;
|
|
||||||
let rx1 = (rx0 + 1) & MAX_TABLE_SIZE_MASK;
|
|
||||||
let ry0 = yi & MAX_TABLE_SIZE_MASK;
|
|
||||||
let ry1 = (ry0 + 1) & MAX_TABLE_SIZE_MASK;
|
|
||||||
|
|
||||||
let c00 = self.r[ry0 * MAX_TABLE_SIZE_MASK + rx0];
|
|
||||||
let c10 = self.r[ry0 * MAX_TABLE_SIZE_MASK + rx1];
|
|
||||||
let c01 = self.r[ry1 * MAX_TABLE_SIZE_MASK + rx0];
|
|
||||||
let c11 = self.r[ry1 * MAX_TABLE_SIZE_MASK + rx1];
|
|
||||||
|
|
||||||
let sx = smooth_step(tx);
|
|
||||||
let sy = smooth_step(ty);
|
|
||||||
|
|
||||||
let nx0 = lerp(c00, c10, sx);
|
|
||||||
let nx1 = lerp(c01, c11, sx);
|
|
||||||
|
|
||||||
lerp(nx0, nx1, sy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn smooth_step(t: f64) -> f64 {
|
|
||||||
t * t * (3.0 - 2.0 * t)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lerp(lo: f64, hi: f64, t: f64) -> f64 {
|
|
||||||
lo * (1.0 - t) + hi * t
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
use std::ops::Mul;
|
|
||||||
|
|
||||||
/// A generic 2-dimensional point class.
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct Vec2<T = f64> {
|
|
||||||
pub x: T,
|
|
||||||
pub y: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Vec2<T> {
|
|
||||||
pub fn new(x: T, y: T) -> Self {
|
|
||||||
Self { x, y }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: Copy, T: Mul<S>> Mul<S> for Vec2<T> {
|
|
||||||
type Output = Vec2<T::Output>;
|
|
||||||
|
|
||||||
fn mul(self, rhs: S) -> Self::Output {
|
|
||||||
Vec2 {
|
|
||||||
x: self.x * rhs,
|
|
||||||
y: self.y * rhs,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
6
assignment-1a/.gitignore
vendored
|
@ -1,6 +0,0 @@
|
||||||
/target
|
|
||||||
/assignment-1
|
|
||||||
/examples/*.png
|
|
||||||
*.ppm
|
|
||||||
*.zip
|
|
||||||
*.pdf
|
|
|
@ -1,183 +0,0 @@
|
||||||
# Assignment 1a: Getting Started with Ray Casting
|
|
||||||
|
|
||||||
In this assignment, you are asked to begin writing a basic ray casting program.
|
|
||||||
|
|
||||||
This program should:
|
|
||||||
|
|
||||||
1. read a simple scene description from a file that is provided as a command
|
|
||||||
line argument
|
|
||||||
2. define an array of pixels that will hold a computer-generated image of the
|
|
||||||
scene
|
|
||||||
3. use ray casting to determine the appropriate color to store in each pixel of
|
|
||||||
the output image
|
|
||||||
4. write the rendered image to an output file in ascii PPM format
|
|
||||||
|
|
||||||
As with assignment 0, the output file name should match the input file name
|
|
||||||
except for the suffix. You can also earn extra credit by enabling your program
|
|
||||||
to render a parallel projection and/or to render not only spheres but also
|
|
||||||
cylinders.
|
|
||||||
|
|
||||||
You are asked to run your program on multiple different input files, featuring a
|
|
||||||
diverse range of different input parameter settings. One of the objectives of
|
|
||||||
this assignment is to help you to develop an intuitive understanding of how each
|
|
||||||
of the various input settings affects the appearance of the rendered scene.
|
|
||||||
Please be sure to specifically consider these three questions:
|
|
||||||
|
|
||||||
- How does the direction of the 'up' vector affect the rendered view of a scene?
|
|
||||||
You should specifically consider tipping the 'up' vector from side to side and
|
|
||||||
forward to back. You will want to define scenes with multiple objects,
|
|
||||||
asymmetrically arranged, to explore this question.
|
|
||||||
- How do changes in the field of view settings affect the contents of your
|
|
||||||
rendered images?
|
|
||||||
- How do various modifications of the viewing parameters affect the amount of
|
|
||||||
perspective distortion apparent in your image?
|
|
||||||
|
|
||||||
In subsequent assignments you will be asked to extend the code you write for
|
|
||||||
this assignment to incorporate additional effects like illumination, shadows,
|
|
||||||
specular reflections and transparency, with these latter effects being achieved
|
|
||||||
by recursive ray tracing. Be sure that your code is structured with these
|
|
||||||
extensions in mind. In particular, you are advised to write simple, modular code
|
|
||||||
following the example described in class.
|
|
||||||
|
|
||||||
Please be sure to check the grading criteria to ensure that all requirements are
|
|
||||||
understood.
|
|
||||||
|
|
||||||
### Detailed instructions
|
|
||||||
|
|
||||||
1. Your program should read the following information from an input scene
|
|
||||||
description file (the syntax is shown below each item; entries in italics
|
|
||||||
are variables, entries in bold are keywords):
|
|
||||||
|
|
||||||
- The view origin, also variously referred to as the 'eye position', 'camera
|
|
||||||
position' or 'center of projection' (a 3D point in space)
|
|
||||||
|
|
||||||
eye eyex eyey eyez
|
|
||||||
|
|
||||||
- The viewing direction (a 3D vector)
|
|
||||||
|
|
||||||
viewdir vdirx vdiry vdirz
|
|
||||||
|
|
||||||
- The 'up' direction (a 3D vector)
|
|
||||||
|
|
||||||
updir upx upy upz
|
|
||||||
|
|
||||||
- The horizontal field of view (in degrees, please)
|
|
||||||
|
|
||||||
hfov fovh
|
|
||||||
|
|
||||||
- The size of the output image (in pixel units)
|
|
||||||
|
|
||||||
imsize width height
|
|
||||||
|
|
||||||
- The 'background' color (using r, g, b components defined on a scale from
|
|
||||||
0-1)
|
|
||||||
|
|
||||||
bkgcolor r g b
|
|
||||||
|
|
||||||
- A 'material' color (in terms of r, g, b components defined on a scale from
|
|
||||||
0-1). The material color should be treated as a state variable, meaning
|
|
||||||
that all subsequently-defined objects should use the immediately-preceding
|
|
||||||
material color
|
|
||||||
|
|
||||||
mtlcolor r g b
|
|
||||||
|
|
||||||
- A sequence of one or more objects. For this assignment, your program is
|
|
||||||
only required to be able to handle spheres. In subsequent assignments you
|
|
||||||
will be asked to extend your code to handle triangles, so you will want to
|
|
||||||
write your code with this future extension in mind. A sphere should be
|
|
||||||
defined by the coordinates of its center point (a 3D point in space) and
|
|
||||||
radius.
|
|
||||||
|
|
||||||
sphere cx cy cz r
|
|
||||||
|
|
||||||
- If you would like to attempt the extra credit portion of this assignment,
|
|
||||||
please use this format to define a parallel projection
|
|
||||||
|
|
||||||
projection parallel
|
|
||||||
|
|
||||||
- If you would like to attempt the extra credit portion of this assignment,
|
|
||||||
please use this format to define a finite cylinder (without endcaps) that
|
|
||||||
is centered at the point (cx, cy, cz) and oriented in the direction (dirx,
|
|
||||||
diry, dirz).
|
|
||||||
|
|
||||||
cylinder cx cy cz dirx diry dirz radius length
|
|
||||||
|
|
||||||
2. Define an array of sufficient size to store the color values of your image.
|
|
||||||
|
|
||||||
3. Using knowledge of the view origin, viewing direction, up direction,
|
|
||||||
horizontal field of view and desired image aspect ratio, define an
|
|
||||||
appropriate “viewing window” in world coordinate space, and a 1-1 mapping
|
|
||||||
between points within this viewing window and pixel locations in your output
|
|
||||||
image.
|
|
||||||
|
|
||||||
4. For each pixel in the output image:
|
|
||||||
|
|
||||||
- Define the equation of the ray that begins at the view origin and passes
|
|
||||||
through the corresponding 3D point in the viewing window
|
|
||||||
- Then, for each object in the scene:
|
|
||||||
- Determine whether the current viewing ray intersects that object, and if
|
|
||||||
so at what point or points
|
|
||||||
- If there are one or more ray/object intersection points that are 'in
|
|
||||||
front of' the view origin with respect to the positive viewing
|
|
||||||
direction, determine which of them is closest to the view origin,
|
|
||||||
remembering that ray/object intersection points that are 'behind' the
|
|
||||||
view origin, with respect to the viewing direction, should be ignored
|
|
||||||
- Determine the color of the object at the closest forward ray/object
|
|
||||||
intersection point, if there is one, and return that value to be stored
|
|
||||||
at the appropriate location in your image array
|
|
||||||
- If no ray/object intersection is found, return the background color
|
|
||||||
|
|
||||||
5. After all of the rays have been cast and a color has been determined for
|
|
||||||
each pixel in the output image, write the final image to an output file,
|
|
||||||
using the ascii PPM format.
|
|
||||||
|
|
||||||
You are strongly encouraged to begin with a very simple scene description,
|
|
||||||
consisting for example of a single sphere located directly in front of the eye
|
|
||||||
in the direction of view. You are also advised to begin by using a very small
|
|
||||||
image size, to expedite the debugging process.
|
|
||||||
|
|
||||||
To explore the effects of various scene parameters, you are advised to start by
|
|
||||||
varying the values of just one viewing parameter at a time, such as: the eye
|
|
||||||
position, the viewing direction, the direction of the 'up' vector, the vertical
|
|
||||||
field of view, the image aspect ratio, etc. Once you understand the effect of
|
|
||||||
each parameter in isolation, you should experiment with combinations of changes,
|
|
||||||
such as: co-varying the field of view and the proximity of the eye to the
|
|
||||||
objects in your scene. Your ability to appreciate the effects of different view
|
|
||||||
settings will be improved if you use a relatively complex but intuitively
|
|
||||||
organized scene, with some asymmetric features and not too much empty space. One
|
|
||||||
example is: spheres centered at each of the 8 corners of a cube, using different
|
|
||||||
colors for each corner, or cylinders arranged along each of the 12 edges of a
|
|
||||||
cube.
|
|
||||||
|
|
||||||
### What you should turn in
|
|
||||||
|
|
||||||
- All of your source code, clearly commented, plus a ~~readme file with
|
|
||||||
compiling instructions or a~~ Makefile or CMake file that the TA can use to
|
|
||||||
compile your code.
|
|
||||||
- One "showcase" image produced by your program, that I can share with the rest
|
|
||||||
of the class. To save time for the TA, we would be grateful if you could
|
|
||||||
provide this image in a format that is supported for direct display in Google
|
|
||||||
Slides or Powerpoint.
|
|
||||||
- A 1-3 page writeup (including pictures) in which you discuss your observations
|
|
||||||
on how the key viewing parameters affect the appearance of the rendered scene.
|
|
||||||
Please incorporate sufficient images produced by your ray casting program to
|
|
||||||
illustrate and explain your findings. In your writeup, be sure to specifically
|
|
||||||
address each of these three points:
|
|
||||||
- How does the apparent rotation of the scene with respect to the viewpoint
|
|
||||||
change with changes in the direction of the 'up' vector?
|
|
||||||
- How do changes in the field of view settings affect the appearance of the
|
|
||||||
scene in your rendered image?
|
|
||||||
- How can the viewing parameters (e.g. the camera location, field of view
|
|
||||||
settings, …) be adjusted to achieve a less exaggerated vs more exaggerated
|
|
||||||
amount of apparent perspective distortion in your image?
|
|
||||||
- Please submit all of the above as a single zip file, containing appropriate
|
|
||||||
subfolders, using the naming convention hw1a.firstname.lastname.zip. Please
|
|
||||||
do not use tar or rar or any other alternative compression mode that could
|
|
||||||
complicate the grading process for the TA.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Two sample input files with their corresponding output images are provided in
|
|
||||||
the Files directory of this Canvas website. Please feel free to use these
|
|
||||||
examples to partially check the functionality of your program. We will be
|
|
||||||
testing your code on additional input files.
|
|
637
assignment-1a/Cargo.lock
generated
|
@ -1,637 +0,0 @@
|
||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.68"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "approx"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "assignment-1"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"clap",
|
|
||||||
"nalgebra",
|
|
||||||
"num",
|
|
||||||
"ordered-float",
|
|
||||||
"rayon",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytemuck"
|
|
||||||
version = "1.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.79"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap"
|
|
||||||
version = "4.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"clap_derive",
|
|
||||||
"clap_lex",
|
|
||||||
"is-terminal",
|
|
||||||
"once_cell",
|
|
||||||
"strsim",
|
|
||||||
"termcolor",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap_derive"
|
|
||||||
version = "4.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
|
|
||||||
dependencies = [
|
|
||||||
"heck",
|
|
||||||
"proc-macro-error",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap_lex"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
|
|
||||||
dependencies = [
|
|
||||||
"os_str_bytes",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-channel"
|
|
||||||
version = "0.5.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-deque"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-epoch",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.9.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"memoffset",
|
|
||||||
"scopeguard",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-utils"
|
|
||||||
version = "0.8.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "either"
|
|
||||||
version = "1.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno"
|
|
||||||
version = "0.2.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
|
||||||
dependencies = [
|
|
||||||
"errno-dragonfly",
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno-dragonfly"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "heck"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.2.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "io-lifetimes"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "is-terminal"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"io-lifetimes",
|
|
||||||
"rustix",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.139"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-raw-sys"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "matrixmultiply"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84"
|
|
||||||
dependencies = [
|
|
||||||
"rawpointer",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memoffset"
|
|
||||||
version = "0.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nalgebra"
|
|
||||||
version = "0.32.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f6515c882ebfddccaa73ead7320ca28036c4bc84c9bcca3cc0cbba8efe89223a"
|
|
||||||
dependencies = [
|
|
||||||
"approx",
|
|
||||||
"matrixmultiply",
|
|
||||||
"nalgebra-macros",
|
|
||||||
"num-complex",
|
|
||||||
"num-rational",
|
|
||||||
"num-traits",
|
|
||||||
"simba",
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nalgebra-macros"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
|
|
||||||
dependencies = [
|
|
||||||
"num-bigint",
|
|
||||||
"num-complex",
|
|
||||||
"num-integer",
|
|
||||||
"num-iter",
|
|
||||||
"num-rational",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-bigint"
|
|
||||||
version = "0.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-complex"
|
|
||||||
version = "0.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-integer"
|
|
||||||
version = "0.1.45"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-iter"
|
|
||||||
version = "0.1.43"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-rational"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-bigint",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-traits"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_cpus"
|
|
||||||
version = "1.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "once_cell"
|
|
||||||
version = "1.17.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ordered-float"
|
|
||||||
version = "3.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d84eb1409416d254e4a9c8fa56cc24701755025b458f0fcd8e59e1f5f40c23bf"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "os_str_bytes"
|
|
||||||
version = "6.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "paste"
|
|
||||||
version = "1.0.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error-attr",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error-attr"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.50"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rawpointer"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon"
|
|
||||||
version = "1.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"rayon-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon-core"
|
|
||||||
version = "1.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-channel",
|
|
||||||
"crossbeam-deque",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"num_cpus",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustix"
|
|
||||||
version = "0.36.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"errno",
|
|
||||||
"io-lifetimes",
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "safe_arch"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scopeguard"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.152"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "simba"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4"
|
|
||||||
dependencies = [
|
|
||||||
"approx",
|
|
||||||
"num-complex",
|
|
||||||
"num-traits",
|
|
||||||
"paste",
|
|
||||||
"wide",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strsim"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "1.0.107"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termcolor"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typenum"
|
|
||||||
version = "1.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-ident"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wide"
|
|
||||||
version = "0.7.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ae41ecad2489a1655c8ef8489444b0b113c0a0c795944a3572a0931cf7d2525c"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
"safe_arch",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.42.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm",
|
|
||||||
"windows_aarch64_msvc",
|
|
||||||
"windows_i686_gnu",
|
|
||||||
"windows_i686_msvc",
|
|
||||||
"windows_x86_64_gnu",
|
|
||||||
"windows_x86_64_gnullvm",
|
|
||||||
"windows_x86_64_msvc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
|
|
@ -1,13 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "assignment-1"
|
|
||||||
authors = ["Michael Zhang <zhan4854@umn.edu>"]
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow = "1.0.68"
|
|
||||||
clap = { version = "4.1.4", features = ["derive"] }
|
|
||||||
nalgebra = "0.32.1"
|
|
||||||
num = { version = "0.4.0", features = ["serde"] }
|
|
||||||
ordered-float = "3.4.0"
|
|
||||||
rayon = "1.6.1"
|
|
|
@ -1,43 +0,0 @@
|
||||||
.PHONY: all clean
|
|
||||||
|
|
||||||
DOCKER := docker
|
|
||||||
ZIP := zip
|
|
||||||
PANDOC := pandoc
|
|
||||||
CONVERT := convert
|
|
||||||
|
|
||||||
HANDIN := hw1a.michael.zhang.zip
|
|
||||||
BINARY := ./assignment-1
|
|
||||||
WRITEUP := writeup.pdf
|
|
||||||
SOURCES := $(shell find -name "*.rs")
|
|
||||||
|
|
||||||
EXAMPLES := $(shell find examples -name "*.txt")
|
|
||||||
EXAMPLES_PPM := $(patsubst %.txt,%.ppm,$(EXAMPLES))
|
|
||||||
EXAMPLES_PNG := $(patsubst %.txt,%.png,$(EXAMPLES))
|
|
||||||
|
|
||||||
all: $(HANDIN)
|
|
||||||
|
|
||||||
$(BINARY): $(SOURCES)
|
|
||||||
$(DOCKER) run \
|
|
||||||
--rm \
|
|
||||||
-v "$(shell pwd)":/usr/src/myapp \
|
|
||||||
-v cargo-registry:/usr/local/cargo \
|
|
||||||
--user "$(shell id -u)":"$(shell id -g)" \
|
|
||||||
-w /usr/src/myapp \
|
|
||||||
rust \
|
|
||||||
cargo build --release
|
|
||||||
mv target/release/assignment-1 $@
|
|
||||||
|
|
||||||
$(HANDIN): $(BINARY) $(WRITEUP) Makefile Cargo.toml Cargo.lock README.md $(EXAMPLES_PNG) $(EXAMPLES_PPM)
|
|
||||||
$(ZIP) -r $@ src examples $^
|
|
||||||
|
|
||||||
examples/%.ppm: examples/%.txt
|
|
||||||
cargo run -- -o $@ $<
|
|
||||||
|
|
||||||
examples/%.png: examples/%.ppm
|
|
||||||
convert $< $@
|
|
||||||
|
|
||||||
writeup.pdf: writeup.md $(EXAMPLES_PNG)
|
|
||||||
$(PANDOC) -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(HANDIN) $(BINARY) $(WRITEUP) $(EXAMPLES_PPM) $(EXAMPLES_PNG)
|
|
|
@ -1,25 +0,0 @@
|
||||||
# Raycaster
|
|
||||||
|
|
||||||
## Bundle contents
|
|
||||||
|
|
||||||
Writeup is located at `/writeup.pdf`.
|
|
||||||
|
|
||||||
The binary can be found at `/assignment-1`. Run `./assignment-1 --help` to see
|
|
||||||
how to use it. The binary has been built using the Rust Docker image, which
|
|
||||||
should have an environment similar to CSELabs. If there is trouble running the
|
|
||||||
binary, try building from source, as documented below.
|
|
||||||
|
|
||||||
Examples are found in the `examples` directory. The text files are the input
|
|
||||||
sources, and the ppm files are the corresponding outputs. They have been
|
|
||||||
generated by running this program. For convenience, pngs have also been provided
|
|
||||||
using imagemagick.
|
|
||||||
|
|
||||||
## Building from source
|
|
||||||
|
|
||||||
The Makefile currently uses Docker to produce a more consistent build. If you
|
|
||||||
have a Rust+Cargo toolchain installed locally, it's also possible to build the
|
|
||||||
source using just:
|
|
||||||
|
|
||||||
cargo build --release
|
|
||||||
|
|
||||||
The binary will be found in `target/release`.
|
|
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 25 KiB |
|
@ -1,21 +0,0 @@
|
||||||
imsize 640 480
|
|
||||||
eye 0 0 15
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 60
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
|
|
||||||
mtlcolor 0 0.5 0.5
|
|
||||||
sphere -1 -2 -5 2
|
|
||||||
sphere 3 -5 -1 0.5
|
|
||||||
|
|
||||||
mtlcolor 0.5 0.5 1
|
|
||||||
sphere 1 2 -3 3
|
|
||||||
sphere -6 3 -4 1
|
|
||||||
|
|
||||||
mtlcolor 0.5 0 0.5
|
|
||||||
sphere 5 5 -1 1
|
|
||||||
sphere -6 -4 -8 7
|
|
||||||
|
|
||||||
mtlcolor 0.5 1 0.5
|
|
||||||
cylinder 5 1 -2 1 -2 1 1 2
|
|
|
@ -1,21 +0,0 @@
|
||||||
imsize 640 480
|
|
||||||
eye 0 0 15
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 30
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
|
|
||||||
mtlcolor 0 0.5 0.5
|
|
||||||
sphere -1 -2 -5 2
|
|
||||||
sphere 3 -5 -1 0.5
|
|
||||||
|
|
||||||
mtlcolor 0.5 0.5 1
|
|
||||||
sphere 1 2 -3 3
|
|
||||||
sphere -6 3 -4 1
|
|
||||||
|
|
||||||
mtlcolor 0.5 0 0.5
|
|
||||||
sphere 5 5 -1 1
|
|
||||||
sphere -6 -4 -8 7
|
|
||||||
|
|
||||||
mtlcolor 0.5 1 0.5
|
|
||||||
cylinder 5 1 -2 1 -2 1 1 2
|
|
|
@ -1,21 +0,0 @@
|
||||||
imsize 640 480
|
|
||||||
eye 0 0 15
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 60
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
|
|
||||||
mtlcolor 0 0.5 0.5
|
|
||||||
sphere -1 -2 -5 2
|
|
||||||
sphere 3 -5 -1 0.5
|
|
||||||
|
|
||||||
mtlcolor 0.5 0.5 1
|
|
||||||
sphere 1 2 -3 3
|
|
||||||
sphere -6 3 -4 1
|
|
||||||
|
|
||||||
mtlcolor 0.5 0 0.5
|
|
||||||
sphere 5 5 -1 1
|
|
||||||
sphere -6 -4 -8 7
|
|
||||||
|
|
||||||
mtlcolor 0.5 1 0.5
|
|
||||||
cylinder 5 1 -2 1 -2 1 1 2
|
|
|
@ -1,8 +0,0 @@
|
||||||
imsize 256 256
|
|
||||||
eye 0 0 0
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 90
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
mtlcolor 0 0 1
|
|
||||||
sphere 0 0 -5 2
|
|
|
@ -1,10 +0,0 @@
|
||||||
imsize 512 256
|
|
||||||
eye 0 0 0
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 130
|
|
||||||
updir 0 1 1
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
mtlcolor 0 1 0
|
|
||||||
sphere -0.5 -1 -8 3
|
|
||||||
mtlcolor 1 0 0
|
|
||||||
sphere 3 1 -3 1
|
|
|
@ -1,9 +0,0 @@
|
||||||
imsize 640 480
|
|
||||||
eye 0 0 8
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 60
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 1 1 1
|
|
||||||
|
|
||||||
mtlcolor 0.5 1 0.5
|
|
||||||
cylinder 0 0 -4 1 0 0 1 8
|
|
|
@ -1,9 +0,0 @@
|
||||||
imsize 640 480
|
|
||||||
eye 0 0 8
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 60
|
|
||||||
updir 1 1 0
|
|
||||||
bkgcolor 1 1 1
|
|
||||||
|
|
||||||
mtlcolor 0.5 1 0.5
|
|
||||||
cylinder 0 0 -4 1 0 0 1 8
|
|
|
@ -1,55 +0,0 @@
|
||||||
use std::io::{Result, Write};
|
|
||||||
|
|
||||||
/// A 24-bit pixel represented by a red, green, and blue value.
|
|
||||||
#[derive(Clone, Copy, Default, Debug)]
|
|
||||||
pub struct Color {
|
|
||||||
pub red: u8,
|
|
||||||
pub green: u8,
|
|
||||||
pub blue: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Color {
|
|
||||||
pub fn new(r: u8, g: u8, b: u8) -> Self {
|
|
||||||
Color {
|
|
||||||
red: r,
|
|
||||||
green: g,
|
|
||||||
blue: b,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_01_float(r: f64, g: f64, b: f64) -> Self {
|
|
||||||
Color::new((r * 256.0) as u8, (g * 256.0) as u8, (b * 256.0) as u8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A representation of an image
|
|
||||||
pub struct Image {
|
|
||||||
/// Width in pixels
|
|
||||||
pub(crate) width: usize,
|
|
||||||
|
|
||||||
/// Height in pixels
|
|
||||||
pub(crate) height: usize,
|
|
||||||
|
|
||||||
/// Pixel data in row-major form.
|
|
||||||
pub(crate) data: Vec<Color>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Image {
|
|
||||||
/// Write the image in PPM format to a file.
|
|
||||||
pub fn write(&self, mut w: impl Write) -> Result<()> {
|
|
||||||
// Header
|
|
||||||
let header = format!("P3 {} {} 255\n", self.width, self.height);
|
|
||||||
w.write_all(header.as_bytes())?;
|
|
||||||
|
|
||||||
// Pixel data
|
|
||||||
assert_eq!(self.data.len(), self.width * self.height);
|
|
||||||
|
|
||||||
for pixel in self.data.iter() {
|
|
||||||
let Color { red, green, blue } = pixel;
|
|
||||||
let pixel = format!("{red} {green} {blue}\n");
|
|
||||||
w.write_all(pixel.as_bytes())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
use std::{fs::File, io::Read, path::Path};
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use nalgebra::Vector3;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
image::Color,
|
|
||||||
scene::{
|
|
||||||
cylinder::Cylinder,
|
|
||||||
data::{Object, Scene},
|
|
||||||
sphere::Sphere,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Parse the input file into a scene
|
|
||||||
pub fn parse_input_file(path: impl AsRef<Path>) -> Result<Scene> {
|
|
||||||
let contents = {
|
|
||||||
let mut contents = String::new();
|
|
||||||
let mut file = File::open(path.as_ref())?;
|
|
||||||
file.read_to_string(&mut contents)?;
|
|
||||||
contents
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut scene = Scene::default();
|
|
||||||
let mut material_color = None;
|
|
||||||
|
|
||||||
for line in contents.lines() {
|
|
||||||
let mut parts = line.split_whitespace();
|
|
||||||
let keyword = match parts.next() {
|
|
||||||
Some(v) => v,
|
|
||||||
None => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
if keyword == "imsize" {
|
|
||||||
let parts = parts
|
|
||||||
.map(|s| s.parse::<usize>().map_err(|e| e.into()))
|
|
||||||
.collect::<Result<Vec<_>>>()?;
|
|
||||||
if let [width, height] = parts[..] {
|
|
||||||
scene.image_width = width;
|
|
||||||
scene.image_height = height;
|
|
||||||
}
|
|
||||||
} else if keyword == "projection" {
|
|
||||||
if let Some("parallel") = parts.next() {
|
|
||||||
scene.parallel_projection = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Do float parsing instead
|
|
||||||
else {
|
|
||||||
let parts = parts
|
|
||||||
.map(|s| s.parse::<f64>().map_err(|e| e.into()))
|
|
||||||
.collect::<Result<Vec<_>>>()?;
|
|
||||||
|
|
||||||
let read_vec3 = |start: usize| {
|
|
||||||
if parts.len() < 3 {
|
|
||||||
bail!("Vec3 requires 3 components.");
|
|
||||||
}
|
|
||||||
Ok(Vector3::new(
|
|
||||||
parts[start],
|
|
||||||
parts[start + 1],
|
|
||||||
parts[start + 2],
|
|
||||||
))
|
|
||||||
};
|
|
||||||
|
|
||||||
let read_color = || {
|
|
||||||
if parts.len() < 3 {
|
|
||||||
bail!("Color requires 3 components.");
|
|
||||||
}
|
|
||||||
Ok(Color::from_01_float(parts[0], parts[1], parts[2]))
|
|
||||||
};
|
|
||||||
|
|
||||||
match keyword {
|
|
||||||
"eye" => scene.eye_pos = read_vec3(0)?,
|
|
||||||
"viewdir" => scene.view_dir = read_vec3(0)?,
|
|
||||||
"updir" => scene.up_dir = read_vec3(0)?,
|
|
||||||
|
|
||||||
"hfov" => scene.hfov = parts[0],
|
|
||||||
"bkgcolor" => scene.bkg_color = read_color()?,
|
|
||||||
|
|
||||||
"mtlcolor" => {
|
|
||||||
let idx = scene.material_colors.len();
|
|
||||||
material_color = Some(idx);
|
|
||||||
scene.material_colors.push(read_color()?);
|
|
||||||
}
|
|
||||||
|
|
||||||
"sphere" => scene.objects.push(Object {
|
|
||||||
kind: Box::new(Sphere {
|
|
||||||
center: read_vec3(0)?,
|
|
||||||
radius: parts[3],
|
|
||||||
}),
|
|
||||||
material: match material_color {
|
|
||||||
Some(v) => v,
|
|
||||||
None => bail!("Each sphere must be preceded by a `mtlcolor` line"),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
"cylinder" => scene.objects.push(Object {
|
|
||||||
kind: Box::new(Cylinder {
|
|
||||||
center: read_vec3(0)?,
|
|
||||||
direction: read_vec3(3)?,
|
|
||||||
radius: parts[6],
|
|
||||||
length: parts[7],
|
|
||||||
}),
|
|
||||||
material: match material_color {
|
|
||||||
Some(v) => v,
|
|
||||||
None => bail!("Each sphere must be preceded by a `mtlcolor` line"),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
_ => bail!("Unknown keyword {keyword}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(scene)
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
#[macro_use]
|
|
||||||
extern crate anyhow;
|
|
||||||
|
|
||||||
mod image;
|
|
||||||
mod input_file;
|
|
||||||
mod utils;
|
|
||||||
mod ray;
|
|
||||||
mod scene;
|
|
||||||
|
|
||||||
use std::fs::File;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use clap::Parser;
|
|
||||||
use ordered_float::NotNan;
|
|
||||||
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
|
|
||||||
|
|
||||||
use crate::image::Image;
|
|
||||||
use crate::input_file::parse_input_file;
|
|
||||||
use crate::ray::Ray;
|
|
||||||
|
|
||||||
/// Simple raycaster.
|
|
||||||
#[derive(Parser)]
|
|
||||||
#[clap(author, version, about, long_about = None)]
|
|
||||||
struct Opt {
|
|
||||||
/// Path to the input file to use.
|
|
||||||
#[clap()]
|
|
||||||
input_path: PathBuf,
|
|
||||||
|
|
||||||
/// Path to the output (defaults to the same file name as the input except
|
|
||||||
/// with an extension of .ppm)
|
|
||||||
#[clap(short = 'o', long = "output")]
|
|
||||||
output_path: Option<PathBuf>,
|
|
||||||
|
|
||||||
/// Force parallel projection to be used
|
|
||||||
#[clap(long = "parallel")]
|
|
||||||
force_parallel: bool,
|
|
||||||
|
|
||||||
/// Override distance from eye
|
|
||||||
#[clap(long = "distance", default_value = "1.0")]
|
|
||||||
distance: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
|
||||||
let opt = Opt::parse();
|
|
||||||
let out_file = opt
|
|
||||||
.output_path
|
|
||||||
.unwrap_or_else(|| opt.input_path.with_extension("ppm"));
|
|
||||||
|
|
||||||
let mut scene = parse_input_file(&opt.input_path)?;
|
|
||||||
let distance = opt.distance;
|
|
||||||
|
|
||||||
if opt.force_parallel {
|
|
||||||
scene.parallel_projection = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the viewing window
|
|
||||||
let view_window = scene.compute_viewing_window(distance);
|
|
||||||
|
|
||||||
// Translate image pixels to real-world 3d coords
|
|
||||||
let translate_pixel = {
|
|
||||||
let dx = view_window.upper_right - view_window.upper_left;
|
|
||||||
let pixel_base_x = dx / scene.image_width as f64;
|
|
||||||
|
|
||||||
let dy = view_window.lower_left - view_window.upper_left;
|
|
||||||
let pixel_base_y = dy / scene.image_height as f64;
|
|
||||||
|
|
||||||
move |px: usize, py: usize| {
|
|
||||||
let x_component = pixel_base_x * px as f64;
|
|
||||||
let y_component = pixel_base_y * py as f64;
|
|
||||||
|
|
||||||
// Without adding this, we would be getting the top-left of the pixel's
|
|
||||||
// rectangle. We want the center, so add half of the pixel size as
|
|
||||||
// well.
|
|
||||||
let center_offset = (pixel_base_x + pixel_base_y) / 2.0;
|
|
||||||
|
|
||||||
view_window.upper_left + x_component + y_component + center_offset
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Generate a parallel iterator for pixels
|
|
||||||
// The iterator preserves order and uses row-major order
|
|
||||||
let pixels_iter = (0..scene.image_height)
|
|
||||||
.into_par_iter()
|
|
||||||
.flat_map(|y| (0..scene.image_width).into_par_iter().map(move |x| (x, y)));
|
|
||||||
|
|
||||||
// Loop through every single pixel of the output file
|
|
||||||
let pixels = pixels_iter
|
|
||||||
.map(|(px, py)| {
|
|
||||||
let pixel_in_space = translate_pixel(px, py);
|
|
||||||
|
|
||||||
let ray_start = if scene.parallel_projection {
|
|
||||||
// For a parallel projection, we'll just take the view direction and
|
|
||||||
// subtract it from the target point. This means every single
|
|
||||||
// ray will be viewed from a point at infinity, rather than a single eye
|
|
||||||
// position.
|
|
||||||
let n = scene.view_dir.normalize();
|
|
||||||
let view_dir = n * distance;
|
|
||||||
pixel_in_space - view_dir
|
|
||||||
} else {
|
|
||||||
scene.eye_pos
|
|
||||||
};
|
|
||||||
|
|
||||||
let ray = Ray::from_endpoints(ray_start, pixel_in_space);
|
|
||||||
|
|
||||||
let earliest_intersection = scene
|
|
||||||
.objects
|
|
||||||
.iter()
|
|
||||||
.filter_map(|object| {
|
|
||||||
let intersection_point_opt = object.kind.intersects_ray_at(&ray);
|
|
||||||
|
|
||||||
intersection_point_opt.and_then(|t| {
|
|
||||||
// Unfortunately, IEEE floats in Rust don't have total ordering,
|
|
||||||
// because NaNs violate ordering properties. The way to remedy this
|
|
||||||
// is to ensure we don't have NaNs by wrapping it into this type,
|
|
||||||
// which then implements total ordering
|
|
||||||
let t = NotNan::new(t);
|
|
||||||
|
|
||||||
// Return both the t and the sphere, because we want to sort on the
|
|
||||||
// t but later retrieve attributes from the sphere
|
|
||||||
t.ok().map(|t| (t, object))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
// Sort the list of intersection times by the lowest one.
|
|
||||||
.min_by_key(|(t, _)| *t);
|
|
||||||
|
|
||||||
match earliest_intersection {
|
|
||||||
// Take the object's material color
|
|
||||||
Some((_, object)) => scene.compute_pixel_color(object.material),
|
|
||||||
|
|
||||||
// There was no intersection, so this should default to the scene's
|
|
||||||
// background color
|
|
||||||
None => scene.bkg_color,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// Construct and emit image
|
|
||||||
let image = Image {
|
|
||||||
width: scene.image_width,
|
|
||||||
height: scene.image_height,
|
|
||||||
data: pixels,
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
let file = File::create(out_file)?;
|
|
||||||
image.write(file)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
use nalgebra::Vector3;
|
|
||||||
|
|
||||||
/// A normalized parametric Ray of the form (origin + direction * time)
|
|
||||||
///
|
|
||||||
/// That means at any time t: f64, the point represented by origin + direction *
|
|
||||||
/// time occurs on the ray.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Ray {
|
|
||||||
pub origin: Vector3<f64>,
|
|
||||||
pub direction: Vector3<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ray {
|
|
||||||
/// Construct a ray from endpoints
|
|
||||||
pub fn from_endpoints(start: Vector3<f64>, end: Vector3<f64>) -> Self {
|
|
||||||
let delta = (end - start).normalize();
|
|
||||||
Ray {
|
|
||||||
origin: start,
|
|
||||||
direction: delta,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluate the ray at a certain point in time, yielding a point
|
|
||||||
pub fn eval(&self, time: f64) -> Vector3<f64> {
|
|
||||||
self.origin + self.direction * time
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
use nalgebra::Vector3;
|
|
||||||
|
|
||||||
use crate::ray::Ray;
|
|
||||||
use crate::utils::{compute_rotation_matrix, min_f64};
|
|
||||||
|
|
||||||
use super::data::ObjectKind;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Cylinder {
|
|
||||||
pub center: Vector3<f64>,
|
|
||||||
pub direction: Vector3<f64>,
|
|
||||||
pub radius: f64,
|
|
||||||
pub length: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObjectKind for Cylinder {
|
|
||||||
/// Given a cylinder, returns the first time at which this ray intersects the
|
|
||||||
/// cylinder.
|
|
||||||
///
|
|
||||||
/// If there is no intersection point, returns None.
|
|
||||||
fn intersects_ray_at(&self, ray: &Ray) -> Option<f64> {
|
|
||||||
// Determine rotation matrix for turning the cylinder upright along the
|
|
||||||
// Z-axis
|
|
||||||
let target_direction = Vector3::new(0.0, 0.0, 1.0);
|
|
||||||
let rotation_matrix =
|
|
||||||
compute_rotation_matrix(self.direction, target_direction);
|
|
||||||
|
|
||||||
// Transform all parameters according to this rotation matrix
|
|
||||||
let rotated_cylinder_center = rotation_matrix * self.center;
|
|
||||||
let rotated_ray_origin = rotation_matrix * ray.origin;
|
|
||||||
let rotated_ray_direction = rotation_matrix * ray.direction;
|
|
||||||
|
|
||||||
// Now that we know the cylinder is upright, we can start checking against
|
|
||||||
// the formula:
|
|
||||||
//
|
|
||||||
// (ox + t*rx - cx)^2 + (oy + t*ry - cy)^2 = r^2
|
|
||||||
//
|
|
||||||
// where o{xy} is the ray origin, r{xy} is the ray direction, and c{xy} is
|
|
||||||
// the cylinder center. The z will be taken care of after the fact. To
|
|
||||||
// solve, we must put it into the form At^2 + Bt + c = 0. The variables
|
|
||||||
// are:
|
|
||||||
//
|
|
||||||
// A: rx^2 + ry^2
|
|
||||||
// B: 2(rx(ox - cx) + ry(oy - cy))
|
|
||||||
// C: (cx - ox)^2 + (cy - oy)^2 - r^2
|
|
||||||
let (a, b, c) = {
|
|
||||||
let o = rotated_ray_origin;
|
|
||||||
let r = rotated_ray_direction;
|
|
||||||
let c = rotated_cylinder_center;
|
|
||||||
|
|
||||||
(
|
|
||||||
r.x.powi(2) + r.y.powi(2),
|
|
||||||
2.0 * (r.x * (o.x - c.x) + r.y * (o.y - c.y)),
|
|
||||||
(c.x - o.x).powi(2) + (c.y - o.y).powi(2) - self.radius.powi(2),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let discriminant = b * b - 4.0 * a * c;
|
|
||||||
|
|
||||||
let possible_side_solutions = match discriminant {
|
|
||||||
// Discriminant < 0, means the equation has no solutions.
|
|
||||||
d if d < 0.0 => vec![],
|
|
||||||
|
|
||||||
// Discriminant == 0
|
|
||||||
d if d == 0.0 => vec![-b / 2.0 * a],
|
|
||||||
|
|
||||||
// Discriminant > 0, 2 solutions available.
|
|
||||||
d if d > 0.0 => {
|
|
||||||
vec![
|
|
||||||
(-b + discriminant.sqrt()) / (2.0 * a),
|
|
||||||
(-b - discriminant.sqrt()) / (2.0 * a),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Probably hit some NaN or Infinity value due to faulty inputs...
|
|
||||||
_ => unreachable!("Invalid determinant value: {discriminant}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Filter out solutions that don't have a valid Z position.
|
|
||||||
let side_solutions = possible_side_solutions.into_iter().filter(|t| {
|
|
||||||
let ray_point = ray.eval(*t);
|
|
||||||
let rotated_ray_point = rotation_matrix * ray_point;
|
|
||||||
let z = rotated_ray_point.z - rotated_cylinder_center.z;
|
|
||||||
|
|
||||||
// Check to see if z is between -len/2 and len/2
|
|
||||||
z.abs() < self.length / 2.0
|
|
||||||
});
|
|
||||||
|
|
||||||
// We also need to add solutions for the two ends of the cylinder, which
|
|
||||||
// uses a similar method except backwards: check intersection points
|
|
||||||
// with the correct z-plane and then see if the points are within the
|
|
||||||
// circle.
|
|
||||||
//
|
|
||||||
// Luckily, this means we only need to care about one dimension at first,
|
|
||||||
// and don't need to perform the quadratic equation method above.
|
|
||||||
//
|
|
||||||
// oz + t * rz = cz +- (len / 2)
|
|
||||||
// t = (oz + cz +- (len / 2)) / rz
|
|
||||||
let possible_z_intersections = {
|
|
||||||
let o = rotated_ray_origin;
|
|
||||||
let r = rotated_ray_direction;
|
|
||||||
let c = rotated_cylinder_center;
|
|
||||||
|
|
||||||
vec![
|
|
||||||
(o.z + c.z + self.length / 2.0) / r.z,
|
|
||||||
(o.z + c.z - self.length / 2.0) / r.z,
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
// Filter out all the solutions where the z does not lie in the circle
|
|
||||||
let end_solutions = possible_z_intersections.into_iter().filter(|t| {
|
|
||||||
let ray_point = ray.eval(*t);
|
|
||||||
ray_point.x.powi(2) + ray_point.y.powi(2) <= self.radius.powi(2)
|
|
||||||
});
|
|
||||||
|
|
||||||
let solutions = side_solutions
|
|
||||||
.into_iter()
|
|
||||||
.chain(end_solutions.into_iter())
|
|
||||||
// Remove any t < 0, since that means it's behind the viewer and we
|
|
||||||
// can't see it.
|
|
||||||
.filter(|t| *t >= 0.0);
|
|
||||||
|
|
||||||
// Return the minimum solution
|
|
||||||
min_f64(solutions)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
use nalgebra::Vector3;
|
|
||||||
|
|
||||||
use crate::image::Color;
|
|
||||||
use crate::ray::Ray;
|
|
||||||
|
|
||||||
pub trait ObjectKind: Debug + Send + Sync {
|
|
||||||
/// Determine where the ray intersects this object, returning the earliest
|
|
||||||
/// time this happens. Returns None if no intersection occurs.
|
|
||||||
///
|
|
||||||
/// Also known as Trace_Ray in the slides, except not the part where it calls
|
|
||||||
/// Shade_Ray.
|
|
||||||
fn intersects_ray_at(&self, ray: &Ray) -> Option<f64>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Object {
|
|
||||||
pub kind: Box<dyn ObjectKind>,
|
|
||||||
|
|
||||||
/// Index into the scene's material color list
|
|
||||||
pub material: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Rect {
|
|
||||||
pub upper_left: Vector3<f64>,
|
|
||||||
pub upper_right: Vector3<f64>,
|
|
||||||
pub lower_left: Vector3<f64>,
|
|
||||||
pub lower_right: Vector3<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct Scene {
|
|
||||||
pub eye_pos: Vector3<f64>,
|
|
||||||
pub view_dir: Vector3<f64>,
|
|
||||||
pub up_dir: Vector3<f64>,
|
|
||||||
|
|
||||||
/// Horizontal field of view (in degrees)
|
|
||||||
pub hfov: f64,
|
|
||||||
pub parallel_projection: bool,
|
|
||||||
|
|
||||||
pub image_width: usize,
|
|
||||||
pub image_height: usize,
|
|
||||||
|
|
||||||
/// Background color
|
|
||||||
pub bkg_color: Color,
|
|
||||||
|
|
||||||
pub material_colors: Vec<Color>,
|
|
||||||
pub objects: Vec<Object>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Scene {
|
|
||||||
/// Determine the color that should be used to fill this pixel
|
|
||||||
///
|
|
||||||
/// Also known as Shade_Ray in the slides.
|
|
||||||
pub fn compute_pixel_color(&self, material_idx: usize) -> Color {
|
|
||||||
// TODO: Does it make sense to make this function fallible from an API
|
|
||||||
// design standpoint?
|
|
||||||
self
|
|
||||||
.material_colors
|
|
||||||
.get(material_idx)
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or(self.bkg_color)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Determine the boundaries of the viewing window in world coordinates
|
|
||||||
pub fn compute_viewing_window(&self, distance: f64) -> Rect {
|
|
||||||
// Compute viewing directions
|
|
||||||
let u = self.view_dir.cross(&self.up_dir).normalize();
|
|
||||||
let v = u.cross(&self.view_dir).normalize();
|
|
||||||
|
|
||||||
// Compute dimensions of viewing window based on field of view
|
|
||||||
let viewing_width = {
|
|
||||||
// Divide the angle in 2 since we are trying to use trig rules so we must
|
|
||||||
// get it from a right triangle
|
|
||||||
let half_hfov = self.hfov.to_radians() / 2.0;
|
|
||||||
|
|
||||||
// tan(hfov / 2) = w / 2d
|
|
||||||
let w_over_2d = half_hfov.tan();
|
|
||||||
|
|
||||||
// To find the viewing width we must multiply by 2d now
|
|
||||||
w_over_2d * 2.0 * distance
|
|
||||||
};
|
|
||||||
|
|
||||||
let aspect_ratio = self.image_width as f64 / self.image_height as f64;
|
|
||||||
let viewing_height = viewing_width / aspect_ratio;
|
|
||||||
|
|
||||||
// Compute viewing window corners
|
|
||||||
let n = self.view_dir.normalize();
|
|
||||||
#[rustfmt::skip] // Otherwise this line wraps over
|
|
||||||
let view_window = Rect {
|
|
||||||
upper_left: self.eye_pos + n * distance - u * (viewing_width / 2.0) + v * (viewing_height / 2.0),
|
|
||||||
upper_right: self.eye_pos + n * distance + u * (viewing_width / 2.0) + v * (viewing_height / 2.0),
|
|
||||||
lower_left: self.eye_pos + n * distance - u * (viewing_width / 2.0) - v * (viewing_height / 2.0),
|
|
||||||
lower_right: self.eye_pos + n * distance + u * (viewing_width / 2.0) - v * (viewing_height / 2.0),
|
|
||||||
};
|
|
||||||
|
|
||||||
view_window
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
pub mod data;
|
|
||||||
pub mod sphere;
|
|
||||||
pub mod cylinder;
|
|
|
@ -1,99 +0,0 @@
|
||||||
use nalgebra::Vector3;
|
|
||||||
|
|
||||||
use crate::{ray::Ray, utils::min_f64};
|
|
||||||
|
|
||||||
use super::data::ObjectKind;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Sphere {
|
|
||||||
pub center: Vector3<f64>,
|
|
||||||
pub radius: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObjectKind for Sphere {
|
|
||||||
/// Given a sphere, returns the first time at which this ray intersects the
|
|
||||||
/// sphere.
|
|
||||||
///
|
|
||||||
/// If there is no intersection point, returns None.
|
|
||||||
fn intersects_ray_at(&self, ray: &Ray) -> Option<f64> {
|
|
||||||
let a = ray.direction.x.powi(2)
|
|
||||||
+ ray.direction.y.powi(2)
|
|
||||||
+ ray.direction.z.powi(2);
|
|
||||||
let b = 2.0
|
|
||||||
* (ray.direction.x * (ray.origin.x - self.center.x)
|
|
||||||
+ ray.direction.y * (ray.origin.y - self.center.y)
|
|
||||||
+ ray.direction.z * (ray.origin.z - self.center.z));
|
|
||||||
let c = (ray.origin.x - self.center.x).powi(2)
|
|
||||||
+ (ray.origin.y - self.center.y).powi(2)
|
|
||||||
+ (ray.origin.z - self.center.z).powi(2)
|
|
||||||
- self.radius.powi(2);
|
|
||||||
let discriminant = b * b - 4.0 * a * c;
|
|
||||||
|
|
||||||
match discriminant {
|
|
||||||
// Discriminant < 0, means the equation has no solutions.
|
|
||||||
d if d < 0.0 => None,
|
|
||||||
|
|
||||||
// Discriminant == 0
|
|
||||||
d if d == 0.0 => Some(-b / (2.0 * a)),
|
|
||||||
|
|
||||||
d if d > 0.0 => {
|
|
||||||
let solution_1 = (-b + discriminant.sqrt()) / (2.0 * a);
|
|
||||||
let solution_2 = (-b - discriminant.sqrt()) / (2.0 * a);
|
|
||||||
|
|
||||||
let solutions = [solution_1, solution_2]
|
|
||||||
.into_iter()
|
|
||||||
// Remove any t < 0, since that means it's behind the viewer and we
|
|
||||||
// can't see it.
|
|
||||||
.filter(|t| *t >= 0.0);
|
|
||||||
|
|
||||||
// Return the minimum solution
|
|
||||||
min_f64(solutions)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Probably hit some NaN or Infinity value due to faulty inputs...
|
|
||||||
_ => unreachable!("Invalid determinant value: {discriminant}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use nalgebra::Vector3;
|
|
||||||
|
|
||||||
use crate::ray::Ray;
|
|
||||||
use crate::scene::data::ObjectKind;
|
|
||||||
|
|
||||||
use super::Sphere;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn practice_problem_slide_154() {
|
|
||||||
let ray = Ray {
|
|
||||||
origin: Vector3::new(0.0, 0.0, 0.0),
|
|
||||||
direction: Vector3::new(0.0, 0.0, -1.0),
|
|
||||||
};
|
|
||||||
let sphere = Sphere {
|
|
||||||
center: Vector3::new(0.0, 0.0, -10.0),
|
|
||||||
radius: 4.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let point = sphere.intersects_ray_at(&ray).map(|t| ray.eval(t));
|
|
||||||
|
|
||||||
// the intersection point in this case is (0, 0, -6)
|
|
||||||
assert_eq!(point, Some(Vector3::new(0.0, 0.0, -6.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn practice_problem_slide_158() {
|
|
||||||
let ray = Ray {
|
|
||||||
origin: Vector3::new(0.0, 0.0, 0.0),
|
|
||||||
direction: Vector3::new(0.0, 0.5, -1.0),
|
|
||||||
};
|
|
||||||
let sphere = Sphere {
|
|
||||||
center: Vector3::new(0.0, 0.0, -10.0),
|
|
||||||
radius: 4.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
// oops! In this case, the ray does not intersect the sphere.
|
|
||||||
assert_eq!(sphere.intersects_ray_at(&ray), None);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
use nalgebra::{Matrix3, Vector3};
|
|
||||||
use ordered_float::NotNan;
|
|
||||||
|
|
||||||
/// Finds the minimum of an iterator of f64s, ignoring any NaN values
|
|
||||||
pub fn min_f64<I>(i: I) -> Option<f64>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = f64>,
|
|
||||||
{
|
|
||||||
i.filter_map(|i| NotNan::new(i).ok())
|
|
||||||
.min()
|
|
||||||
.map(|i| i.into_inner())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate the rotation matrix between the 2 given vectors
|
|
||||||
/// Based on the method here: https://math.stackexchange.com/a/897677
|
|
||||||
pub fn compute_rotation_matrix(
|
|
||||||
a: Vector3<f64>,
|
|
||||||
b: Vector3<f64>,
|
|
||||||
) -> Matrix3<f64> {
|
|
||||||
let cos_t = a.dot(&b);
|
|
||||||
let sin_t = a.cross(&b).norm();
|
|
||||||
let g = Matrix3::new(cos_t, -sin_t, 0.0, sin_t, cos_t, 0.0, 0.0, 0.0, 1.0);
|
|
||||||
|
|
||||||
// New basis vectors
|
|
||||||
let u = a;
|
|
||||||
let v = (b - a.dot(&b) * a).normalize();
|
|
||||||
let w = b.cross(&a);
|
|
||||||
// Not sure if this is required to be invertible?
|
|
||||||
let f = Matrix3::from_columns(&[u, v, w]).try_inverse().unwrap();
|
|
||||||
|
|
||||||
f.try_inverse().unwrap() * g * f
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
---
|
|
||||||
geometry: margin=2cm
|
|
||||||
output: pdf_document
|
|
||||||
---
|
|
||||||
|
|
||||||
# Raycaster
|
|
||||||
|
|
||||||
#### Michael Zhang \<zhan4854@umn.edu\>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Determining the viewing window for the raycaster for this assignment involved
|
|
||||||
creating a "virtual" screen in world coordinates, mapping image pixels into that
|
|
||||||
virtual screen, and then casting a ray through each pixel's world coordinate to
|
|
||||||
see where it would intersect objects.
|
|
||||||
|
|
||||||
### Creating a virtual screen
|
|
||||||
|
|
||||||
The virtual screen is determined first using the eye's position and where it's
|
|
||||||
looking. This gives us a single 3d vector, but it doesn't give us a 2d screen in
|
|
||||||
the world. This is where the field of view (FOV) comes in; the FOV determines
|
|
||||||
how many degrees the screen should take up.
|
|
||||||
|
|
||||||
![Field of view](doc/fov.jpg){width=180px}
|
|
||||||
|
|
||||||
Changing the angle of the field of view would result in a wider or narrower
|
|
||||||
screen, which when paired with the aspect ratio (width / height), would produce
|
|
||||||
a bigger or smaller viewing screen, like the orange box in the above diagram
|
|
||||||
shows. Simply put, FOV affects how _much_ of the frame you're able to see. An
|
|
||||||
example is shown here:
|
|
||||||
|
|
||||||
![](examples/fov-demo-1.png){width=180px}\ ![](examples/fov-demo-2.png){width=180px}
|
|
||||||
|
|
||||||
The left image uses an FOV of 60, while the right image uses an FOV of 30. As
|
|
||||||
you can see, the left side has a wider range of vision, which allows it to see
|
|
||||||
more of the world. (both images can be found in the `examples` directory of the
|
|
||||||
handin zip)
|
|
||||||
|
|
||||||
Curiously, distance from the eye actually doesn't really affect the viewing
|
|
||||||
screen very much. The reason is the screen is only used to determine how to
|
|
||||||
project rays. As the two black rectangles in the diagram above demonstrates,
|
|
||||||
changing the distance would still allow the viewer to see the same amount of the
|
|
||||||
scene. (using the word _amount_ very loosely here to mean percentage of the
|
|
||||||
landscape, rather than # of pixels, which is determined by the actual image
|
|
||||||
dimensions)
|
|
||||||
|
|
||||||
The up-direction vector controls the rotation of the scene. Without the
|
|
||||||
up-direction, it would not be possible to tell which rotation the screen should
|
|
||||||
be in.
|
|
||||||
|
|
||||||
![Rotation determined by up direction](doc/rot.jpg){width=240px}
|
|
||||||
|
|
||||||
To see what this looks like, consider the following images, where the left side
|
|
||||||
uses an up direction of $(0, 1, 0)$, while the right side uses $(1, 1, 0)$ (both
|
|
||||||
images can be found in the `examples` directory of the handin zip)
|
|
||||||
|
|
||||||
![](examples/up-dir-demo-1.png){width=180px}\ ![](examples/up-dir-demo-2.png){width=180px}
|
|
||||||
|
|
||||||
Together, all of these parameters can uniquely determine a virtual screen
|
|
||||||
location, that we can use to cast rays through and fill pixels. We can change
|
|
||||||
any of these to produce an image with a more exaggerated view of the scene for
|
|
||||||
example; simply move the eye position to be incredibly close to the object that
|
|
||||||
we are observing, and increase the field of view to cover the entire object.
|
|
||||||
|
|
||||||
Because the rays are going in much different directions and travelling different
|
|
||||||
distances, the corners of the image will seem more stretched than if we were
|
|
||||||
observing the object from afar and all the rays are in approximately the same
|
|
||||||
part of the virtual screen.
|
|
||||||
|
|
||||||
One other point to make is that we're currently using a rectangle for our
|
|
||||||
virtual screen, which automatically does a bit of the distortion. If instead we
|
|
||||||
were to use a curved lens-like shape, then the rays pointing to any pixel of the
|
|
||||||
screen would be travelling the same distance. Moving the eye position closer to
|
|
||||||
the object would still generate distortion, but to a lesser extent.
|
|
||||||
|
|
||||||
### Mapping image pixels
|
|
||||||
|
|
||||||
After the rectangle has been determined, we can simply pick one corner to start
|
|
||||||
as an anchor, and then find out what pixel values would correspond to it. For
|
|
||||||
example, in the image below:
|
|
||||||
|
|
||||||
![Mapping image pixels](doc/map.jpg){width=240px}
|
|
||||||
|
|
||||||
I would pick a starting point like $A$, and then take the vector $B-A$ and
|
|
||||||
subdivide it into 4 pieces, letting $\Delta x = \frac{B-A}{4}$. Then, same thing
|
|
||||||
for the $y$ direction, I would set $\Delta y = \frac{D-A}{4}$. Taking $A +
|
|
||||||
x_i \times \Delta x + y_i \times \Delta y$ yields the precise coordinate
|
|
||||||
location for any pixel.
|
|
||||||
|
|
||||||
(Technically really we would want the middle of the pixel, so just add
|
|
||||||
$\frac{\Delta x + \Delta y}{2}$ to the point to get that)
|
|
||||||
|
|
||||||
### Parallel Projection Notes
|
|
||||||
|
|
||||||
Because of the way I implemented parallel projection, it's recommended to
|
|
||||||
either put the eye much farther back, or use `--distance` to force a much bigger
|
|
||||||
distance from the eye for the raycaster. See the `--help` to see how this option
|
|
||||||
is used.
|
|
||||||
|
|
||||||
### Cylinder Intersection Notes
|
|
||||||
|
|
||||||
First, we will transform the current point into the vector space of the
|
|
||||||
cylinder, so that the cylinder location is $(0, 0, 0)$ and the direction vector
|
|
||||||
is normalized into $(0, 0, 1)$.
|
|
||||||
|
|
||||||
This can be done by using a rotation matrix (since we are sure this
|
|
||||||
transformation is just a rotation). This rotation is actually a 2D rotation,
|
|
||||||
around the normal between the cylinder direction and $(0, 0, 1)$. We then
|
|
||||||
rotate everything we are working with (the cylinder and the ray) into this
|
|
||||||
coordinate system to make calculations easier.
|
|
||||||
|
|
||||||
Then it's a matter of determining if the $x$ and $y$ coordinates fall into the
|
|
||||||
space constrained by the equation $(o_x + t\times r_x - c_x)^2 + (o_y + t\times
|
|
||||||
r_y - c_y)^2 = r^2$ and if $z \le L$. I can solve this using the quadratic
|
|
||||||
formula the same way as the sphere case.
|
|
||||||
|
|
||||||
We want a quadratic equation of the form $At^2 + Bt + C = 0$. The values for
|
|
||||||
$A$, $B$, and $C$ are:
|
|
||||||
|
|
||||||
- $A = r_x^2 + r_y^2$
|
|
||||||
- $B = 2(r_x(o_x - c_x) + r_y(o_y - c_y))$
|
|
||||||
- $C = (c_x - o_x)^2 + (c_y - o_y)^2 - r^2$
|
|
||||||
|
|
||||||
Solving this for $t$ yields 0-2 solutions depending on if the equation was
|
|
||||||
satisfied or not. Then, we can plug any solutions we get back into the ray
|
|
||||||
equation and determine if the $z$-coordinate is in the range of the cylinder
|
|
||||||
that we want.
|
|
||||||
|
|
||||||
We will also have to do this for the ends of the cylinder, but just backwards.
|
|
||||||
So we would start with the $z$-coordinate, solve for $t$s where the ray hits
|
|
||||||
that $z$-plane, and then check the $x$ and $y$ values to see if they satisfy the
|
|
||||||
ray equation as well.
|
|
10
assignment-1b/.gitignore
vendored
|
@ -1,10 +0,0 @@
|
||||||
/target
|
|
||||||
/assignment-1b
|
|
||||||
/raytracer1b
|
|
||||||
/examples/*.png
|
|
||||||
*.ppm
|
|
||||||
*.zip
|
|
||||||
*.pdf
|
|
||||||
perf.data*
|
|
||||||
flamegraph.svg
|
|
||||||
showcase.png
|
|
838
assignment-1b/Cargo.lock
generated
|
@ -1,838 +0,0 @@
|
||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.68"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "approx"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "assignment-1b"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"base64",
|
|
||||||
"clap",
|
|
||||||
"derivative",
|
|
||||||
"nalgebra",
|
|
||||||
"num",
|
|
||||||
"ordered-float",
|
|
||||||
"rand",
|
|
||||||
"rayon",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base64"
|
|
||||||
version = "0.21.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytemuck"
|
|
||||||
version = "1.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.79"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap"
|
|
||||||
version = "4.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"clap_derive",
|
|
||||||
"clap_lex",
|
|
||||||
"is-terminal",
|
|
||||||
"once_cell",
|
|
||||||
"strsim",
|
|
||||||
"termcolor",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap_derive"
|
|
||||||
version = "4.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
|
|
||||||
dependencies = [
|
|
||||||
"heck",
|
|
||||||
"proc-macro-error",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap_lex"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
|
|
||||||
dependencies = [
|
|
||||||
"os_str_bytes",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-channel"
|
|
||||||
version = "0.5.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-deque"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-epoch",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.9.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"memoffset",
|
|
||||||
"scopeguard",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-utils"
|
|
||||||
version = "0.8.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derivative"
|
|
||||||
version = "2.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "either"
|
|
||||||
version = "1.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno"
|
|
||||||
version = "0.2.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
|
||||||
dependencies = [
|
|
||||||
"errno-dragonfly",
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno-dragonfly"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.2.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "heck"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.2.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "io-lifetimes"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "is-terminal"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"io-lifetimes",
|
|
||||||
"rustix",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.139"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-raw-sys"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log"
|
|
||||||
version = "0.4.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "matrixmultiply"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84"
|
|
||||||
dependencies = [
|
|
||||||
"rawpointer",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memoffset"
|
|
||||||
version = "0.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nalgebra"
|
|
||||||
version = "0.32.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f6515c882ebfddccaa73ead7320ca28036c4bc84c9bcca3cc0cbba8efe89223a"
|
|
||||||
dependencies = [
|
|
||||||
"approx",
|
|
||||||
"matrixmultiply",
|
|
||||||
"nalgebra-macros",
|
|
||||||
"num-complex",
|
|
||||||
"num-rational",
|
|
||||||
"num-traits",
|
|
||||||
"simba",
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nalgebra-macros"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nu-ansi-term"
|
|
||||||
version = "0.46.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
|
||||||
dependencies = [
|
|
||||||
"overload",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
|
|
||||||
dependencies = [
|
|
||||||
"num-bigint",
|
|
||||||
"num-complex",
|
|
||||||
"num-integer",
|
|
||||||
"num-iter",
|
|
||||||
"num-rational",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-bigint"
|
|
||||||
version = "0.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-complex"
|
|
||||||
version = "0.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-integer"
|
|
||||||
version = "0.1.45"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-iter"
|
|
||||||
version = "0.1.43"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-rational"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-bigint",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-traits"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_cpus"
|
|
||||||
version = "1.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "once_cell"
|
|
||||||
version = "1.17.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ordered-float"
|
|
||||||
version = "3.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d84eb1409416d254e4a9c8fa56cc24701755025b458f0fcd8e59e1f5f40c23bf"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "os_str_bytes"
|
|
||||||
version = "6.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "overload"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "paste"
|
|
||||||
version = "1.0.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project-lite"
|
|
||||||
version = "0.2.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ppv-lite86"
|
|
||||||
version = "0.2.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error-attr",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error-attr"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.50"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rawpointer"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon"
|
|
||||||
version = "1.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"rayon-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon-core"
|
|
||||||
version = "1.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-channel",
|
|
||||||
"crossbeam-deque",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"num_cpus",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustix"
|
|
||||||
version = "0.36.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"errno",
|
|
||||||
"io-lifetimes",
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "safe_arch"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scopeguard"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.152"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sharded-slab"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "simba"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4"
|
|
||||||
dependencies = [
|
|
||||||
"approx",
|
|
||||||
"num-complex",
|
|
||||||
"num-traits",
|
|
||||||
"paste",
|
|
||||||
"wide",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smallvec"
|
|
||||||
version = "1.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strsim"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "1.0.107"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termcolor"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thread_local"
|
|
||||||
version = "1.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"once_cell",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing"
|
|
||||||
version = "0.1.37"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"pin-project-lite",
|
|
||||||
"tracing-attributes",
|
|
||||||
"tracing-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-attributes"
|
|
||||||
version = "0.1.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-core"
|
|
||||||
version = "0.1.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
|
||||||
dependencies = [
|
|
||||||
"once_cell",
|
|
||||||
"valuable",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-log"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
"log",
|
|
||||||
"tracing-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-subscriber"
|
|
||||||
version = "0.3.16"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
|
||||||
dependencies = [
|
|
||||||
"nu-ansi-term",
|
|
||||||
"sharded-slab",
|
|
||||||
"smallvec",
|
|
||||||
"thread_local",
|
|
||||||
"tracing-core",
|
|
||||||
"tracing-log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typenum"
|
|
||||||
version = "1.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-ident"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "valuable"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wide"
|
|
||||||
version = "0.7.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ae41ecad2489a1655c8ef8489444b0b113c0a0c795944a3572a0931cf7d2525c"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
"safe_arch",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.42.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm",
|
|
||||||
"windows_aarch64_msvc",
|
|
||||||
"windows_i686_gnu",
|
|
||||||
"windows_i686_msvc",
|
|
||||||
"windows_x86_64_gnu",
|
|
||||||
"windows_x86_64_gnullvm",
|
|
||||||
"windows_x86_64_msvc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
|
|
@ -1,22 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "assignment-1b"
|
|
||||||
authors = ["Michael Zhang <zhan4854@umn.edu>"]
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "raytracer1b"
|
|
||||||
path = "src/main.rs"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow = "1.0.68"
|
|
||||||
base64 = "0.21.0"
|
|
||||||
clap = { version = "4.1.4", features = ["cargo", "derive"] }
|
|
||||||
derivative = "2.2.0"
|
|
||||||
nalgebra = "0.32.1"
|
|
||||||
num = { version = "0.4.0", features = ["serde"] }
|
|
||||||
ordered-float = "3.4.0"
|
|
||||||
rand = "0.8.5"
|
|
||||||
rayon = "1.6.1"
|
|
||||||
tracing = "0.1.37"
|
|
||||||
tracing-subscriber = "0.3.16"
|
|
|
@ -1,54 +0,0 @@
|
||||||
.PHONY: all clean
|
|
||||||
|
|
||||||
.PRECIOUS: $(EXAMPLES_PPM)
|
|
||||||
|
|
||||||
RAYTRACER_FLAGS :=
|
|
||||||
DOCKER := docker
|
|
||||||
ZIP := zip
|
|
||||||
PANDOC := pandoc
|
|
||||||
CONVERT := convert
|
|
||||||
|
|
||||||
HANDIN := ./hw1b.michael.zhang.zip
|
|
||||||
BINARY := ./raytracer1b
|
|
||||||
WRITEUP := ./writeup.pdf
|
|
||||||
SHOWCASE := ./showcase.png
|
|
||||||
SOURCES := Cargo.toml $(shell find -name "*.rs")
|
|
||||||
|
|
||||||
EXAMPLES := $(shell find examples -name "*.txt")
|
|
||||||
EXAMPLES_PPM := $(patsubst %.txt,%.ppm,$(EXAMPLES))
|
|
||||||
EXAMPLES_PNG := $(patsubst %.txt,%.png,$(EXAMPLES))
|
|
||||||
|
|
||||||
all: $(HANDIN)
|
|
||||||
|
|
||||||
$(BINARY): $(SOURCES)
|
|
||||||
mkdir -p target/docker
|
|
||||||
$(DOCKER) run \
|
|
||||||
--rm \
|
|
||||||
-v "$(shell pwd)":/usr/src/myapp \
|
|
||||||
-v cargo-registry:/usr/local/cargo \
|
|
||||||
--user "$(shell id -u)":"$(shell id -g)" \
|
|
||||||
-w /usr/src/myapp \
|
|
||||||
-e CARGO_TARGET_DIR=/usr/src/myapp/target/docker \
|
|
||||||
rust \
|
|
||||||
cargo build --profile release-handin
|
|
||||||
mv target/docker/release-handin/raytracer1b $@
|
|
||||||
|
|
||||||
$(HANDIN): $(BINARY) $(WRITEUP) Makefile Cargo.toml Cargo.lock README.md $(EXAMPLES_PNG) $(EXAMPLES_PPM) $(SHOWCASE)
|
|
||||||
$(ZIP) -r $@ src examples $^
|
|
||||||
|
|
||||||
$(SHOWCASE): examples/soft-shadow-demo.png
|
|
||||||
cp $< $@
|
|
||||||
|
|
||||||
examples/%.ppm: examples/%.txt $(SOURCES)
|
|
||||||
cargo run --release -- -o $@ $(RAYTRACER_FLAGS) $<
|
|
||||||
|
|
||||||
examples/%.png: examples/%.ppm
|
|
||||||
convert $< $@
|
|
||||||
|
|
||||||
writeup.pdf: writeup.md $(EXAMPLES_PNG)
|
|
||||||
$(PANDOC) -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf target/docker \
|
|
||||||
$(HANDIN) $(BINARY) $(WRITEUP) $(SHOWCASE) \
|
|
||||||
$(EXAMPLES_PPM) $(EXAMPLES_PNG)
|
|
|
@ -1,29 +0,0 @@
|
||||||
# Raycaster
|
|
||||||
|
|
||||||
## Bundle contents
|
|
||||||
|
|
||||||
Writeup is located at `/writeup.pdf`.
|
|
||||||
|
|
||||||
The binary can be found at `/raytracer1b`. Run `./raytracer1b --help` to see
|
|
||||||
how to use it. The binary has been built using the Rust Docker image, which
|
|
||||||
should have an environment similar to CSELabs. If there is trouble running the
|
|
||||||
binary, try building from source, as documented below.
|
|
||||||
|
|
||||||
Examples are found in the `examples` directory. The text files are the input
|
|
||||||
sources, and the ppm files are the corresponding outputs. They have been
|
|
||||||
generated by running this program. For convenience, pngs have also been provided
|
|
||||||
using imagemagick.
|
|
||||||
|
|
||||||
## Showcase image
|
|
||||||
|
|
||||||
The showcase image can be found at `/showcase.png`.
|
|
||||||
|
|
||||||
## Building from source
|
|
||||||
|
|
||||||
The Makefile currently uses Docker to produce a more consistent build. If you
|
|
||||||
have a Rust+Cargo toolchain installed locally, it's also possible to build the
|
|
||||||
source using just:
|
|
||||||
|
|
||||||
cargo build --release
|
|
||||||
|
|
||||||
The binary will be found in `target/release`.
|
|
|
@ -1,18 +0,0 @@
|
||||||
imsize 512 512
|
|
||||||
eye 0 0 0
|
|
||||||
viewdir 0 0.1 -1
|
|
||||||
hfov 90
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
|
|
||||||
light -1 -1 -1 0 0.9 0.5 0.05
|
|
||||||
|
|
||||||
mtlcolor 0 1 0 1 1 1 0.6 0.2 0.2 10
|
|
||||||
sphere 0 1.5 -4 1
|
|
||||||
|
|
||||||
mtlcolor 0 1 0 1 1 1 0.1 0.8 0.2 10
|
|
||||||
sphere -1.275 -0.75 -4 1
|
|
||||||
|
|
||||||
mtlcolor 0 1 0 1 1 1 0.1 0.2 0.8 10
|
|
||||||
sphere 1.275 -0.75 -4 1
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
eye 0 0 0
|
|
||||||
viewdir 0 -0.3 -1
|
|
||||||
updir 0 1 0
|
|
||||||
hfov 60
|
|
||||||
imsize 256 512
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
light 0 -1 0 0 1 1 1
|
|
||||||
mtlcolor 1 1 0 1 1 1 0.2 0.6 0.2 20
|
|
||||||
sphere 0 -2 -3 1
|
|
||||||
sphere 0 0 -3 0.5
|
|
|
@ -1,15 +0,0 @@
|
||||||
imsize 600 200
|
|
||||||
eye 0 0 15
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 90
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.4 0.4 0.4
|
|
||||||
|
|
||||||
attlight -15 10 5 1 1 1 1 0 0.25 0.03
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.8 1 1 1 0.4 1 0.5 15
|
|
||||||
sphere -10 0 0 2
|
|
||||||
sphere -5 0 0 2
|
|
||||||
sphere 0 0 0 2
|
|
||||||
sphere 5 0 0 2
|
|
||||||
sphere 10 0 0 2
|
|
|
@ -1,12 +0,0 @@
|
||||||
imsize 640 480
|
|
||||||
eye 0 0 15
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 60
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
|
|
||||||
light -10 10 -3 0 0 0.4 0.4
|
|
||||||
light 10 10 -3 1 0.4 0 0.4
|
|
||||||
|
|
||||||
mtlcolor 0.5 1 0.5 0.2 0.4 0.8 0.2 0.4 0 10
|
|
||||||
cylinder -2 4 -3 0 0 5 1 4
|
|
|
@ -1,15 +0,0 @@
|
||||||
imsize 640 480
|
|
||||||
eye -2.5 2 -5
|
|
||||||
viewdir -0.2 0 -1
|
|
||||||
hfov 90
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.4 0.4 0.4
|
|
||||||
|
|
||||||
depthcueing 0.4 0.4 0.4 1 0.1 60 0
|
|
||||||
light 0 5 -7.5 1 1 1 1
|
|
||||||
|
|
||||||
mtlcolor 1 0.8 0.7 1 1 1 0.6 0.6 0 10
|
|
||||||
sphere -5 2 -10 2
|
|
||||||
sphere -3 2 -20 2
|
|
||||||
sphere 1.5 2 -30 2
|
|
||||||
sphere 13 2 -60 2
|
|
|
@ -1,23 +0,0 @@
|
||||||
imsize 600 200
|
|
||||||
eye 0 0 15
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 90
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.4 0.4 0.4
|
|
||||||
|
|
||||||
light 0 5 5 1 0.7 0.7 0.8
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0 0.4 0 1
|
|
||||||
sphere -10 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.4 0 1
|
|
||||||
sphere -5 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.4 0.4 0 1
|
|
||||||
sphere 0 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.6 0.4 0 1
|
|
||||||
sphere 5 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.8 0.4 0 1
|
|
||||||
sphere 10 0 0 2
|
|
|
@ -1,23 +0,0 @@
|
||||||
imsize 600 200
|
|
||||||
eye 0 0 15
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 90
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.4 0.4 0.4
|
|
||||||
|
|
||||||
light 0 5 5 1 0.7 0.7 0.8
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0 0 1
|
|
||||||
sphere -10 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.2 0 1
|
|
||||||
sphere -5 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.4 0 1
|
|
||||||
sphere 0 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.6 0 1
|
|
||||||
sphere 5 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.8 0 1
|
|
||||||
sphere 10 0 0 2
|
|
|
@ -1,23 +0,0 @@
|
||||||
imsize 600 200
|
|
||||||
eye 0 0 15
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 90
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.4 0.4 0.4
|
|
||||||
|
|
||||||
light 0 5 5 1 0.7 0.7 0.8
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.2 0 15
|
|
||||||
sphere -10 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.2 0.2 15
|
|
||||||
sphere -5 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.2 0.4 15
|
|
||||||
sphere 0 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.2 0.6 15
|
|
||||||
sphere 5 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.2 0.8 15
|
|
||||||
sphere 10 0 0 2
|
|
|
@ -1,16 +0,0 @@
|
||||||
imsize 640 480
|
|
||||||
eye 0 0 -2
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 90
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.4 0.4 0.4
|
|
||||||
|
|
||||||
light -5 5 -7.5 1 1 1 1
|
|
||||||
light 5 5 -7.5 1 1 1 1
|
|
||||||
|
|
||||||
mtlcolor 0.4 0.6 1 1 1 1 0.2 0.6 0 10
|
|
||||||
sphere 0 -2 -10 2
|
|
||||||
|
|
||||||
mtlcolor 0.8 0.4 0.4 1 1 1 0.2 0.6 0 10
|
|
||||||
sphere -2.5 2.5 -10 1
|
|
||||||
sphere 2.5 2.5 -10 1
|
|
|
@ -1,23 +0,0 @@
|
||||||
imsize 600 200
|
|
||||||
eye 0 0 15
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 90
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.4 0.4 0.4
|
|
||||||
|
|
||||||
light 0 5 5 1 0.7 0.7 0.8
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.2 0.4 2
|
|
||||||
sphere -10 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.2 0.4 6
|
|
||||||
sphere -5 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.2 0.4 10
|
|
||||||
sphere 0 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.2 0.4 50
|
|
||||||
sphere 5 0 0 2
|
|
||||||
|
|
||||||
mtlcolor 0.6 1 0.4 1 1 1 0.2 0.2 0.4 100
|
|
||||||
sphere 10 0 0 2
|
|
|
@ -1,37 +0,0 @@
|
||||||
imsize 1920 1080
|
|
||||||
eye 0 0 15
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 60
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.4 0.4 0.4
|
|
||||||
|
|
||||||
depthcueing 0.4 0.4 0.4 1 0.1 60 0
|
|
||||||
|
|
||||||
light -10 10 -3 0 0.8 0.8 0.8
|
|
||||||
light -10 10 -3 1 0.8 0.8 0.8
|
|
||||||
|
|
||||||
mtlcolor 0 0.5 0.5 1 1 1 0.2 0.7 0.2 10
|
|
||||||
sphere -1 -2 -5 2
|
|
||||||
sphere 10 -10 -40 1
|
|
||||||
|
|
||||||
mtlcolor 0.5 0.5 1 0.4 0.4 0.4 0.2 0.7 0.4 10
|
|
||||||
sphere 1 2 -3 3
|
|
||||||
sphere -6 3 -4 1
|
|
||||||
|
|
||||||
mtlcolor 1.0 0 0.5 0.6 0.4 0.2 0.2 0.6 0.8 10
|
|
||||||
sphere 20 20 -50 6
|
|
||||||
|
|
||||||
mtlcolor 0.5 0 0.5 0.6 0.4 0.2 0.2 0.5 0 10
|
|
||||||
sphere -6 -4 -8 7
|
|
||||||
|
|
||||||
mtlcolor 0.8 0 0.3 0.6 0.4 0.2 0.2 0.4 0.2 10
|
|
||||||
cylinder -2 2 -3 0 0 5 1 4
|
|
||||||
|
|
||||||
mtlcolor 0.8 0.8 0.3 0.6 0.4 0.2 0.2 0.8 0.2 10
|
|
||||||
sphere -40 35 -80 7
|
|
||||||
sphere -25 20 -60 5
|
|
||||||
sphere -12.5 15 -40 3
|
|
||||||
sphere -7 14 -30 2
|
|
||||||
|
|
||||||
mtlcolor 0.5 1 0.5 0.2 0.4 0.8 0.2 0.4 0 10
|
|
||||||
cylinder 5 1 -2 1 -2 1 1 2
|
|
|
@ -1,12 +0,0 @@
|
||||||
imsize 256 256
|
|
||||||
eye 0 0 0
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 90
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
|
|
||||||
light -2 3 -3 0 1 0.5 0.6
|
|
||||||
light 2 3 -3 1 0.5 0.5 1
|
|
||||||
|
|
||||||
mtlcolor 0 1 0 1 1 1 0.2 0.4 0 10
|
|
||||||
sphere 0 0 -5 2
|
|
|
@ -1,45 +0,0 @@
|
||||||
imsize 640 480
|
|
||||||
eye 0 0 15
|
|
||||||
viewdir 0 0 -1
|
|
||||||
hfov 60
|
|
||||||
updir 0 1 0
|
|
||||||
bkgcolor 0.5 0.5 0.5
|
|
||||||
|
|
||||||
depthcueing 0.5 0.5 0.5 1 0.4 60 0
|
|
||||||
|
|
||||||
light 10 10 -10 1 1 1 1
|
|
||||||
|
|
||||||
mtlcolor 0.5 1 0.5 1 1 1 0.2 1 0.1 5
|
|
||||||
sphere 4.5 4.5 -20 4.5
|
|
||||||
sphere -4.5 -4.5 -20 4.5
|
|
||||||
|
|
||||||
mtlcolor 1 0.5 0.5 1 1 1 0.2 0.8 0 5
|
|
||||||
sphere -10 0 -30 4
|
|
||||||
sphere -20 0 -30 4
|
|
||||||
sphere -30 0 -30 4
|
|
||||||
sphere -40 0 -30 4
|
|
||||||
sphere 0 0 -30 4
|
|
||||||
sphere 10 0 -30 4
|
|
||||||
sphere 20 0 -30 4
|
|
||||||
sphere 30 0 -30 4
|
|
||||||
sphere 40 0 -30 4
|
|
||||||
|
|
||||||
sphere -10 -10 -30 4
|
|
||||||
sphere -20 -10 -30 4
|
|
||||||
sphere -30 -10 -30 4
|
|
||||||
sphere -40 -10 -30 4
|
|
||||||
sphere 0 -10 -30 4
|
|
||||||
sphere 10 -10 -30 4
|
|
||||||
sphere 20 -10 -30 4
|
|
||||||
sphere 30 -10 -30 4
|
|
||||||
sphere 40 -10 -30 4
|
|
||||||
|
|
||||||
sphere -10 10 -30 4
|
|
||||||
sphere -20 10 -30 4
|
|
||||||
sphere -30 10 -30 4
|
|
||||||
sphere -40 10 -30 4
|
|
||||||
sphere 0 10 -30 4
|
|
||||||
sphere 10 10 -30 4
|
|
||||||
sphere 20 10 -30 4
|
|
||||||
sphere 30 10 -30 4
|
|
||||||
sphere 40 10 -30 4
|
|
|
@ -1,41 +0,0 @@
|
||||||
use std::io::{Result, Write};
|
|
||||||
|
|
||||||
use nalgebra::Vector3;
|
|
||||||
|
|
||||||
/// A pixel color represented by a red, green, and blue value in the range 0-1.
|
|
||||||
pub type Color = Vector3<f64>;
|
|
||||||
|
|
||||||
/// A representation of an image
|
|
||||||
pub struct Image {
|
|
||||||
/// Width in pixels
|
|
||||||
pub width: usize,
|
|
||||||
|
|
||||||
/// Height in pixels
|
|
||||||
pub height: usize,
|
|
||||||
|
|
||||||
/// Pixel data in row-major form.
|
|
||||||
pub data: Vec<Color>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Image {
|
|
||||||
/// Write the image in PPM format to a file.
|
|
||||||
pub fn write(&self, mut w: impl Write) -> Result<()> {
|
|
||||||
// Header
|
|
||||||
let header = format!("P3 {} {} 255\n", self.width, self.height);
|
|
||||||
w.write_all(header.as_bytes())?;
|
|
||||||
|
|
||||||
// Pixel data
|
|
||||||
assert_eq!(self.data.len(), self.width * self.height);
|
|
||||||
|
|
||||||
for pixel in self.data.iter() {
|
|
||||||
let pixel = pixel * 256.0;
|
|
||||||
let red = pixel.x as u8;
|
|
||||||
let green = pixel.y as u8;
|
|
||||||
let blue = pixel.z as u8;
|
|
||||||
let pixel = format!("{red} {green} {blue}\n");
|
|
||||||
w.write_all(pixel.as_bytes())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
#![doc = include_str!("../README.md")]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate anyhow;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate derivative;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate tracing;
|
|
||||||
|
|
||||||
pub mod image;
|
|
||||||
pub mod ray;
|
|
||||||
pub mod scene;
|
|
||||||
pub mod utils;
|
|
|
@ -1,138 +0,0 @@
|
||||||
#[macro_use]
|
|
||||||
extern crate tracing;
|
|
||||||
|
|
||||||
use std::fs::File;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use assignment_1b::image::Image;
|
|
||||||
use assignment_1b::ray::Ray;
|
|
||||||
use assignment_1b::scene::Scene;
|
|
||||||
|
|
||||||
use clap::Parser;
|
|
||||||
|
|
||||||
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
|
|
||||||
|
|
||||||
/// Simple raytracer with Blinn-Phong illumination and shadowing.
|
|
||||||
#[derive(Parser)]
|
|
||||||
#[clap(author, version, about, long_about = None)]
|
|
||||||
struct Opt {
|
|
||||||
/// Path to the input file to use.
|
|
||||||
#[clap()]
|
|
||||||
input_path: PathBuf,
|
|
||||||
|
|
||||||
/// Path to the output (defaults to the same file name as the input except
|
|
||||||
/// with an extension of .ppm)
|
|
||||||
#[clap(short = 'o', long = "output")]
|
|
||||||
output_path: Option<PathBuf>,
|
|
||||||
|
|
||||||
/// Force parallel projection to be used
|
|
||||||
#[clap(long = "parallel")]
|
|
||||||
force_parallel: bool,
|
|
||||||
|
|
||||||
/// Override distance from eye
|
|
||||||
#[clap(long = "distance", default_value = "1.0")]
|
|
||||||
distance: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
|
||||||
let opt = Opt::parse();
|
|
||||||
|
|
||||||
// Set up logging
|
|
||||||
tracing_subscriber::fmt()
|
|
||||||
.with_target(false)
|
|
||||||
.with_timer(tracing_subscriber::fmt::time::uptime())
|
|
||||||
.with_level(true)
|
|
||||||
.init();
|
|
||||||
|
|
||||||
// Rename the output file if it's not provided
|
|
||||||
let out_file = opt
|
|
||||||
.output_path
|
|
||||||
.unwrap_or_else(|| opt.input_path.with_extension("ppm"));
|
|
||||||
|
|
||||||
let mut scene = Scene::from_input_file(&opt.input_path)?;
|
|
||||||
let distance = opt.distance;
|
|
||||||
|
|
||||||
// Force-override parallel projection
|
|
||||||
if opt.force_parallel {
|
|
||||||
scene.parallel_projection = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translate image pixels to real-world 3d coords
|
|
||||||
let translate_pixel = scene.pixel_translation_function(distance);
|
|
||||||
|
|
||||||
// Generate a parallel iterator for pixels
|
|
||||||
// The iterator preserves order and uses row-major order
|
|
||||||
let pixels_iter = (0..scene.image_height)
|
|
||||||
.into_par_iter()
|
|
||||||
.flat_map(|y| (0..scene.image_width).into_par_iter().map(move |x| (x, y)));
|
|
||||||
|
|
||||||
// Loop through every single pixel of the output file
|
|
||||||
let pixels = pixels_iter
|
|
||||||
.map(|(px, py)| {
|
|
||||||
let pixel_in_space = translate_pixel(px, py);
|
|
||||||
|
|
||||||
let ray_start = if scene.parallel_projection {
|
|
||||||
// For a parallel projection, we'll just take the view direction and
|
|
||||||
// subtract it from the target point. This means every single
|
|
||||||
// ray will be viewed from a point at infinity, rather than a single eye
|
|
||||||
// position.
|
|
||||||
let n = scene.view_dir.normalize();
|
|
||||||
let view_dir = n * distance;
|
|
||||||
pixel_in_space - view_dir
|
|
||||||
} else {
|
|
||||||
scene.eye_pos
|
|
||||||
};
|
|
||||||
|
|
||||||
let ray = Ray::from_endpoints(ray_start, pixel_in_space);
|
|
||||||
|
|
||||||
let intersections = scene
|
|
||||||
.objects
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(|(i, object)| {
|
|
||||||
match object.kind.intersects_ray_at(&ray) {
|
|
||||||
Ok(Some(t)) => {
|
|
||||||
// Return both the t and the sphere, because we want to sort on
|
|
||||||
// the t but later retrieve attributes from the sphere
|
|
||||||
Some(Ok((i, t, object)))
|
|
||||||
}
|
|
||||||
Ok(None) => None,
|
|
||||||
Err(err) => {
|
|
||||||
error!("Error: {err}");
|
|
||||||
Some(Err(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>>>()?;
|
|
||||||
|
|
||||||
// Sort the list of intersection times by the lowest one.
|
|
||||||
let earliest_intersection =
|
|
||||||
intersections.into_iter().min_by_key(|(_, t, _)| t.time);
|
|
||||||
|
|
||||||
Ok(match earliest_intersection {
|
|
||||||
// Take the object's material color
|
|
||||||
Some((obj_idx, intersection_context, object)) => scene
|
|
||||||
.compute_pixel_color(obj_idx, object.material, intersection_context),
|
|
||||||
|
|
||||||
// There was no intersection, so this should default to the scene's
|
|
||||||
// background color
|
|
||||||
None => scene.bkg_color,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>>>()?;
|
|
||||||
|
|
||||||
// Construct and emit image
|
|
||||||
let image = Image {
|
|
||||||
width: scene.image_width,
|
|
||||||
height: scene.image_height,
|
|
||||||
data: pixels,
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
let file = File::create(out_file)?;
|
|
||||||
image.write(file)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
use nalgebra::Vector3;
|
|
||||||
|
|
||||||
/// A normalized parametric Ray of the form (origin + direction * time)
|
|
||||||
///
|
|
||||||
/// That means at any time t: f64, the point represented by origin + direction *
|
|
||||||
/// time occurs on the ray.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Ray {
|
|
||||||
pub origin: Vector3<f64>,
|
|
||||||
pub direction: Vector3<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ray {
|
|
||||||
/// Construct a ray from endpoints
|
|
||||||
pub fn from_endpoints(start: Vector3<f64>, end: Vector3<f64>) -> Self {
|
|
||||||
let delta = (end - start).normalize();
|
|
||||||
Ray {
|
|
||||||
origin: start,
|
|
||||||
direction: delta,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluate the ray at a certain point in time, yielding a point
|
|
||||||
pub fn eval(&self, time: f64) -> Vector3<f64> {
|
|
||||||
self.origin + self.direction * time
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,204 +0,0 @@
|
||||||
use anyhow::Result;
|
|
||||||
use nalgebra::Vector3;
|
|
||||||
use ordered_float::NotNan;
|
|
||||||
|
|
||||||
use crate::ray::Ray;
|
|
||||||
use crate::utils::compute_rotation_matrix;
|
|
||||||
|
|
||||||
use super::{illumination::IntersectionContext};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Cylinder {
|
|
||||||
pub center: Vector3<f64>,
|
|
||||||
pub direction: Vector3<f64>,
|
|
||||||
pub radius: f64,
|
|
||||||
pub length: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Cylinder {
|
|
||||||
/// Given a cylinder, returns the first time at which this ray intersects the
|
|
||||||
/// cylinder.
|
|
||||||
///
|
|
||||||
/// If there is no intersection point, returns None.
|
|
||||||
pub fn intersects_ray_at(
|
|
||||||
&self,
|
|
||||||
ray: &Ray,
|
|
||||||
) -> Result<Option<IntersectionContext>> {
|
|
||||||
// Determine rotation matrix for turning the cylinder upright along the
|
|
||||||
// Z-axis
|
|
||||||
let target_direction = Vector3::new(0.0, 0.0, 1.0);
|
|
||||||
let rotation_matrix =
|
|
||||||
compute_rotation_matrix(self.direction, target_direction)?;
|
|
||||||
let inverse_rotation_matrix =
|
|
||||||
rotation_matrix.try_inverse().ok_or_else(|| {
|
|
||||||
anyhow!("Rotation matrix for some reason does not have an inverse?")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Transform all parameters according to this rotation matrix
|
|
||||||
let rotated_cylinder_center = rotation_matrix * self.center;
|
|
||||||
let rotated_ray_origin = rotation_matrix * ray.origin;
|
|
||||||
let rotated_ray_direction = rotation_matrix * ray.direction;
|
|
||||||
|
|
||||||
// Now that we know the cylinder is upright, we can start checking against
|
|
||||||
// the formula:
|
|
||||||
//
|
|
||||||
// (ox + t*rx - cx)^2 + (oy + t*ry - cy)^2 = r^2
|
|
||||||
//
|
|
||||||
// where o{xy} is the ray origin, r{xy} is the ray direction, and c{xy} is
|
|
||||||
// the cylinder center. The z will be taken care of after the fact. To
|
|
||||||
// solve, we must put it into the form At^2 + Bt + c = 0. The variables
|
|
||||||
// are:
|
|
||||||
//
|
|
||||||
// A: rx^2 + ry^2
|
|
||||||
// B: 2(rx(ox - cx) + ry(oy - cy))
|
|
||||||
// C: (cx - ox)^2 + (cy - oy)^2 - r^2
|
|
||||||
let (a, b, c) = {
|
|
||||||
let o = rotated_ray_origin;
|
|
||||||
let r = rotated_ray_direction;
|
|
||||||
let c = rotated_cylinder_center;
|
|
||||||
|
|
||||||
(
|
|
||||||
r.x.powi(2) + r.y.powi(2),
|
|
||||||
2.0 * (r.x * (o.x - c.x) + r.y * (o.y - c.y)),
|
|
||||||
(c.x - o.x).powi(2) + (c.y - o.y).powi(2) - self.radius.powi(2),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let discriminant = b * b - 4.0 * a * c;
|
|
||||||
|
|
||||||
let possible_side_solutions = match discriminant {
|
|
||||||
// Discriminant < 0, means the equation has no solutions.
|
|
||||||
d if d < 0.0 => vec![],
|
|
||||||
|
|
||||||
// Discriminant == 0
|
|
||||||
d if d == 0.0 => vec![-b / 2.0 * a],
|
|
||||||
|
|
||||||
// Discriminant > 0, 2 solutions available.
|
|
||||||
d if d > 0.0 => {
|
|
||||||
vec![
|
|
||||||
(-b + discriminant.sqrt()) / (2.0 * a),
|
|
||||||
(-b - discriminant.sqrt()) / (2.0 * a),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Probably hit some NaN or Infinity value due to faulty inputs...
|
|
||||||
_ => bail!("Invalid determinant value: {discriminant}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Filter out solutions that don't have a valid Z position.
|
|
||||||
let side_solutions = possible_side_solutions.into_iter().filter_map(|t| {
|
|
||||||
let ray_point = ray.eval(t);
|
|
||||||
let rotated_ray_point = rotation_matrix * ray_point;
|
|
||||||
let z = rotated_ray_point.z - rotated_cylinder_center.z;
|
|
||||||
|
|
||||||
// Check to see if z is between -len/2 and len/2
|
|
||||||
if z.abs() > self.length / 2.0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let time = NotNan::new(t).ok()?;
|
|
||||||
|
|
||||||
// The point on the center of the cylinder that corresponds to the z-axis
|
|
||||||
// point of the intersection
|
|
||||||
let center_at_z = {
|
|
||||||
let mut center_point = rotation_matrix * ray_point;
|
|
||||||
center_point.x = rotated_cylinder_center.x;
|
|
||||||
center_point.y = rotated_cylinder_center.y;
|
|
||||||
|
|
||||||
inverse_rotation_matrix * center_point
|
|
||||||
};
|
|
||||||
let normal = (ray_point - center_at_z).normalize();
|
|
||||||
|
|
||||||
Some(IntersectionContext {
|
|
||||||
time,
|
|
||||||
point: ray_point,
|
|
||||||
normal,
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
// We also need to add solutions for the two ends of the cylinder, which
|
|
||||||
// uses a similar method except backwards: check intersection points
|
|
||||||
// with the correct z-plane and then see if the points are within the
|
|
||||||
// circle.
|
|
||||||
//
|
|
||||||
// Luckily, this means we only need to care about one dimension at first,
|
|
||||||
// and don't need to perform the quadratic equation method above.
|
|
||||||
//
|
|
||||||
// oz + t * rz = cz +- (len / 2)
|
|
||||||
// t = (-oz + cz +- (len / 2)) / rz
|
|
||||||
let possible_z_intersections = {
|
|
||||||
let o = rotated_ray_origin;
|
|
||||||
let r = rotated_ray_direction;
|
|
||||||
let c = rotated_cylinder_center;
|
|
||||||
|
|
||||||
if r.z == 0.0 {
|
|
||||||
Vec::new() // No solutions here
|
|
||||||
} else {
|
|
||||||
vec![
|
|
||||||
(-o.z + c.z + self.length / 2.0) / r.z,
|
|
||||||
(-o.z + c.z - self.length / 2.0) / r.z,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let end_solutions = possible_z_intersections.into_iter().filter_map(|t| {
|
|
||||||
let ray_point = ray.eval(t);
|
|
||||||
let rotated_point = rotation_matrix * ray_point;
|
|
||||||
|
|
||||||
// Filter out all the solutions where the intersection point does not lie
|
|
||||||
// in the circle
|
|
||||||
if rotated_point.x.powi(2) + rotated_point.y.powi(2) > self.radius.powi(2)
|
|
||||||
{
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let normal_rotated =
|
|
||||||
Vector3::new(0.0, 0.0, rotated_point.z - rotated_cylinder_center.z)
|
|
||||||
.normalize();
|
|
||||||
let normal = inverse_rotation_matrix * normal_rotated;
|
|
||||||
|
|
||||||
let time = NotNan::new(t).ok()?;
|
|
||||||
Some(IntersectionContext {
|
|
||||||
time,
|
|
||||||
point: ray_point,
|
|
||||||
normal,
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let solutions = side_solutions
|
|
||||||
.into_iter()
|
|
||||||
.chain(end_solutions.into_iter())
|
|
||||||
// Remove any t < 0, since that means it's behind the viewer and we
|
|
||||||
// can't see it.
|
|
||||||
.filter(|ctx| *ctx.time >= 0.0);
|
|
||||||
|
|
||||||
// Return the minimum solution
|
|
||||||
Ok(solutions.min_by_key(|ctx| ctx.time))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use nalgebra::Vector3;
|
|
||||||
|
|
||||||
use crate::{ray::Ray};
|
|
||||||
|
|
||||||
use super::Cylinder;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_cylinder() {
|
|
||||||
let cylinder = Cylinder {
|
|
||||||
center: Vector3::new(0.0, 0.0, 0.0),
|
|
||||||
direction: Vector3::new(0.0, 1.0, 0.0),
|
|
||||||
radius: 3.0,
|
|
||||||
length: 4.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let eye = Vector3::new(0.0, 3.0, 3.0);
|
|
||||||
let end = Vector3::new(0.0, 2.0, 2.0);
|
|
||||||
let ray = Ray::from_endpoints(eye, end);
|
|
||||||
|
|
||||||
let res = cylinder.intersects_ray_at(&ray);
|
|
||||||
panic!("Result: {res:?}");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,225 +0,0 @@
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use nalgebra::Vector3;
|
|
||||||
|
|
||||||
use crate::image::Color;
|
|
||||||
use crate::ray::Ray;
|
|
||||||
use crate::utils::cross;
|
|
||||||
|
|
||||||
use super::cylinder::Cylinder;
|
|
||||||
use super::illumination::IntersectionContext;
|
|
||||||
use super::sphere::Sphere;
|
|
||||||
use super::Scene;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ObjectKind {
|
|
||||||
Sphere(Sphere),
|
|
||||||
Cylinder(Cylinder),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObjectKind {
|
|
||||||
/// Determine where the ray intersects this object, returning the earliest
|
|
||||||
/// time this happens. Returns None if no intersection occurs.
|
|
||||||
///
|
|
||||||
/// Also known as Trace_Ray in the slides, except not the part where it calls
|
|
||||||
/// Shade_Ray.
|
|
||||||
pub fn intersects_ray_at(
|
|
||||||
&self,
|
|
||||||
ray: &Ray,
|
|
||||||
) -> Result<Option<IntersectionContext>> {
|
|
||||||
match self {
|
|
||||||
ObjectKind::Sphere(sphere) => sphere.intersects_ray_at(ray),
|
|
||||||
ObjectKind::Cylinder(cylinder) => cylinder.intersects_ray_at(ray),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An object in the scene
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Object {
|
|
||||||
pub kind: ObjectKind,
|
|
||||||
|
|
||||||
/// Index into the scene's material color list
|
|
||||||
pub material: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Rect {
|
|
||||||
pub upper_left: Vector3<f64>,
|
|
||||||
pub upper_right: Vector3<f64>,
|
|
||||||
pub lower_left: Vector3<f64>,
|
|
||||||
pub lower_right: Vector3<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Material {
|
|
||||||
pub diffuse_color: Vector3<f64>,
|
|
||||||
pub specular_color: Vector3<f64>,
|
|
||||||
|
|
||||||
pub k_a: f64,
|
|
||||||
pub k_d: f64,
|
|
||||||
pub k_s: f64,
|
|
||||||
pub exponent: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum LightKind {
|
|
||||||
/// A point light source exists at a point and emits light in all directions
|
|
||||||
Point {
|
|
||||||
location: Vector3<f64>,
|
|
||||||
|
|
||||||
/// Whether light attenuation is enabled for this light
|
|
||||||
attenuation: Option<Attenuation>,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// A directional light source exists at an infinitely far location but emits
|
|
||||||
/// light in a specific direction
|
|
||||||
Directional { direction: Vector3<f64> },
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Light {
|
|
||||||
/// The kind of light source, as well as its associated information
|
|
||||||
pub kind: LightKind,
|
|
||||||
|
|
||||||
/// The color, or intensity, of the light source
|
|
||||||
pub color: Vector3<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Light {
|
|
||||||
/// Get the unit directional vector pointing from the given point to this
|
|
||||||
/// light source
|
|
||||||
pub fn direction_from(&self, point: Vector3<f64>) -> Vector3<f64> {
|
|
||||||
match self.kind {
|
|
||||||
LightKind::Point { location, .. } => location - point,
|
|
||||||
LightKind::Directional { direction } => -direction,
|
|
||||||
}
|
|
||||||
.normalize()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DepthCueing {
|
|
||||||
/// The color to tint (should be the same as the background color, to avoid
|
|
||||||
/// bizarre visual effects)
|
|
||||||
pub color: Color,
|
|
||||||
|
|
||||||
/// Proportion of the color influenced by the depth tint when the distance is
|
|
||||||
/// maxed (caps at 1.0)
|
|
||||||
pub a_max: f64,
|
|
||||||
|
|
||||||
/// Proportion of the color influenced by the depth tint when the distance is
|
|
||||||
/// at the minimum (caps at 1.0)
|
|
||||||
pub a_min: f64,
|
|
||||||
|
|
||||||
/// The max distance that should be affected by the depth tint
|
|
||||||
pub dist_max: f64,
|
|
||||||
|
|
||||||
/// The min distance that should be affected by the depth tint
|
|
||||||
pub dist_min: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A default implementation here needs to simulate what would happen if there
|
|
||||||
/// was no depth cueing. In this case, if we have both a_max and a_min be 1.0,
|
|
||||||
/// then the original color will always apply and there will be no need for
|
|
||||||
/// depth color
|
|
||||||
impl Default for DepthCueing {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
color: Default::default(),
|
|
||||||
a_max: 1.0,
|
|
||||||
a_min: 1.0,
|
|
||||||
dist_max: 0.0,
|
|
||||||
dist_min: 0.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Light attenuation dropoff coefficients
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Attenuation {
|
|
||||||
pub c1: f64,
|
|
||||||
pub c2: f64,
|
|
||||||
pub c3: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A default implementation here needs to simulate what would happen if there
|
|
||||||
/// was no light attenuation specified. In this case, c1 would just be a
|
|
||||||
/// constant of 1 and all the coefficients for anything involving distance would
|
|
||||||
/// be zeroed out
|
|
||||||
impl Default for Attenuation {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
c1: 1.0,
|
|
||||||
c2: 0.0,
|
|
||||||
c3: 0.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Scene {
|
|
||||||
/// Determine the boundaries of the viewing window in world coordinates
|
|
||||||
pub fn compute_viewing_window(&self, distance: f64) -> Rect {
|
|
||||||
// Compute viewing directions
|
|
||||||
let u = cross(self.view_dir, self.up_dir).normalize();
|
|
||||||
let v = cross(u, self.view_dir).normalize();
|
|
||||||
|
|
||||||
// Compute dimensions of viewing window based on field of view
|
|
||||||
let viewing_width = {
|
|
||||||
// Divide the angle in 2 since we are trying to use trig rules so we must
|
|
||||||
// get it from a right triangle
|
|
||||||
let half_hfov = self.hfov.to_radians() / 2.0;
|
|
||||||
|
|
||||||
// tan(hfov / 2) = w / 2d
|
|
||||||
let w_over_2d = half_hfov.tan();
|
|
||||||
|
|
||||||
// To find the viewing width we must multiply by 2d now
|
|
||||||
w_over_2d * 2.0 * distance
|
|
||||||
};
|
|
||||||
|
|
||||||
let aspect_ratio = self.image_width as f64 / self.image_height as f64;
|
|
||||||
let viewing_height = viewing_width / aspect_ratio;
|
|
||||||
|
|
||||||
// Compute viewing window corners
|
|
||||||
let n = self.view_dir.normalize();
|
|
||||||
|
|
||||||
#[rustfmt::skip] // Don't format, or else this line wraps over
|
|
||||||
let view_window = Rect {
|
|
||||||
upper_left: self.eye_pos + n * distance - u * (viewing_width / 2.0) + v * (viewing_height / 2.0),
|
|
||||||
upper_right: self.eye_pos + n * distance + u * (viewing_width / 2.0) + v * (viewing_height / 2.0),
|
|
||||||
lower_left: self.eye_pos + n * distance - u * (viewing_width / 2.0) - v * (viewing_height / 2.0),
|
|
||||||
lower_right: self.eye_pos + n * distance + u * (viewing_width / 2.0) - v * (viewing_height / 2.0),
|
|
||||||
};
|
|
||||||
|
|
||||||
view_window
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a pixel translation function based on the viewing window of the
|
|
||||||
/// current scene
|
|
||||||
pub fn pixel_translation_function(
|
|
||||||
&self,
|
|
||||||
distance: f64,
|
|
||||||
) -> impl Fn(usize, usize) -> Vector3<f64> {
|
|
||||||
let view_window = self.compute_viewing_window(distance);
|
|
||||||
|
|
||||||
let dx = view_window.upper_right - view_window.upper_left;
|
|
||||||
let pixel_base_x = dx / self.image_width as f64;
|
|
||||||
|
|
||||||
let dy = view_window.lower_left - view_window.upper_left;
|
|
||||||
let pixel_base_y = dy / self.image_height as f64;
|
|
||||||
|
|
||||||
// The final function to be returned
|
|
||||||
move |px: usize, py: usize| {
|
|
||||||
let x_component = pixel_base_x * px as f64;
|
|
||||||
let y_component = pixel_base_y * py as f64;
|
|
||||||
|
|
||||||
// Without adding this, we would be getting the top-left of the pixel's
|
|
||||||
// rectangle. We want the center, so add half of the pixel size as
|
|
||||||
// well.
|
|
||||||
let center_offset = (pixel_base_x + pixel_base_y) / 2.0;
|
|
||||||
|
|
||||||
view_window.upper_left + x_component + y_component + center_offset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,276 +0,0 @@
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
use nalgebra::Vector3;
|
|
||||||
use ordered_float::NotNan;
|
|
||||||
use rand::Rng;
|
|
||||||
use rayon::prelude::{
|
|
||||||
IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator,
|
|
||||||
ParallelIterator,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{image::Color, ray::Ray, utils::dot};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
data::{DepthCueing, Light, LightKind, Object},
|
|
||||||
Scene,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl Scene {
|
|
||||||
/// Determine the color that should be used to fill this pixel.
|
|
||||||
///
|
|
||||||
/// - material_idx is the index into the materials list.
|
|
||||||
/// - intersection_context contains information on vectors where the
|
|
||||||
/// intersection occurred
|
|
||||||
///
|
|
||||||
/// Also known as Shade_Ray in the slides.
|
|
||||||
pub fn compute_pixel_color(
|
|
||||||
&self,
|
|
||||||
obj_idx: usize,
|
|
||||||
material_idx: usize,
|
|
||||||
intersection_context: IntersectionContext,
|
|
||||||
) -> Color {
|
|
||||||
// TODO: Does it make sense to make this function fallible from an API
|
|
||||||
// design standpoint?
|
|
||||||
let material = match self.materials.get(material_idx) {
|
|
||||||
Some(v) => v,
|
|
||||||
None => return self.bkg_color,
|
|
||||||
};
|
|
||||||
|
|
||||||
let ambient_component = material.k_a * material.diffuse_color;
|
|
||||||
|
|
||||||
// Diffuse and specular lighting for each separate light
|
|
||||||
let diffuse_and_specular: Vector3<f64> = self
|
|
||||||
.lights
|
|
||||||
.par_iter()
|
|
||||||
.map(|light| {
|
|
||||||
// The vector pointing in the direction of the light
|
|
||||||
let light_direction = light.direction_from(intersection_context.point);
|
|
||||||
|
|
||||||
let normal = intersection_context.normal.normalize();
|
|
||||||
let viewer_direction = self.eye_pos - intersection_context.point;
|
|
||||||
let halfway_direction =
|
|
||||||
((light_direction + viewer_direction) / 2.0).normalize();
|
|
||||||
|
|
||||||
let diffuse_component = material.k_d
|
|
||||||
* material.diffuse_color
|
|
||||||
* dot(normal, light_direction).max(0.0);
|
|
||||||
|
|
||||||
let specular_component = material.k_s
|
|
||||||
* material.specular_color
|
|
||||||
* dot(normal, halfway_direction)
|
|
||||||
.max(0.0)
|
|
||||||
.powf(material.exponent);
|
|
||||||
|
|
||||||
// Shadow coefficient between 0 and 1 to control how bright this pixel
|
|
||||||
// should be from being in the shadow of another object (could be
|
|
||||||
// between 0 and 1 when applying soft shadows)
|
|
||||||
let shadow_coefficient = self.compute_shadow_coefficient(
|
|
||||||
obj_idx,
|
|
||||||
intersection_context.point,
|
|
||||||
light,
|
|
||||||
);
|
|
||||||
|
|
||||||
let attenuation_coefficient = match &light.kind {
|
|
||||||
LightKind::Point {
|
|
||||||
location,
|
|
||||||
attenuation: Some(att),
|
|
||||||
} => {
|
|
||||||
let dist = (location - intersection_context.point).norm();
|
|
||||||
let denom = att.c1 + att.c2 * dist + att.c3 * dist.powi(2);
|
|
||||||
if denom == 0.0 {
|
|
||||||
warn!("Light attenuation coefficients produced a denominator of 0. Check your inputs...");
|
|
||||||
1.0 // Some kind of graceful fallback here
|
|
||||||
} else {
|
|
||||||
1.0 / denom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => 1.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let diffuse_and_specular = diffuse_component + specular_component;
|
|
||||||
|
|
||||||
attenuation_coefficient
|
|
||||||
* shadow_coefficient
|
|
||||||
* light.color.component_mul(&diffuse_and_specular)
|
|
||||||
})
|
|
||||||
.sum();
|
|
||||||
|
|
||||||
let color = ambient_component + diffuse_and_specular;
|
|
||||||
|
|
||||||
// Apply depth cueing to the result
|
|
||||||
let a_dc = {
|
|
||||||
// Distance from the viewer
|
|
||||||
let d_obj = (intersection_context.point - self.eye_pos).norm();
|
|
||||||
let DepthCueing {
|
|
||||||
dist_max,
|
|
||||||
dist_min,
|
|
||||||
a_max,
|
|
||||||
a_min,
|
|
||||||
..
|
|
||||||
} = self.depth_cueing;
|
|
||||||
|
|
||||||
if d_obj < dist_min {
|
|
||||||
a_max
|
|
||||||
} else if d_obj < dist_max {
|
|
||||||
a_min + (a_max - a_min) * (dist_max - d_obj) / (dist_max - dist_min)
|
|
||||||
} else {
|
|
||||||
a_min
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let color = a_dc * color + (1.0 - a_dc) * self.depth_cueing.color;
|
|
||||||
|
|
||||||
// Need to clamp the result so none of the components goes over 1
|
|
||||||
let clamped_result = color.map(|v| v.min(1.0));
|
|
||||||
|
|
||||||
clamped_result
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Perform another ray casting to see if there are any objects obstructing
|
|
||||||
/// the light source to this particular point
|
|
||||||
pub fn compute_shadow_coefficient(
|
|
||||||
&self,
|
|
||||||
obj_idx: usize,
|
|
||||||
point: Vector3<f64>,
|
|
||||||
light: &Light,
|
|
||||||
) -> f64 {
|
|
||||||
let light_direction = light.direction_from(point);
|
|
||||||
let ray = Ray {
|
|
||||||
origin: point,
|
|
||||||
direction: light_direction.normalize(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Small helper for iterating over all of the objects in the scene except
|
|
||||||
// for the current one
|
|
||||||
let other_objects = self
|
|
||||||
.objects
|
|
||||||
.par_iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter(|(i, _)| *i != obj_idx);
|
|
||||||
|
|
||||||
// Get the list of intersections with all the other objects in the scene
|
|
||||||
// This list will be a set of opacities
|
|
||||||
let intersections = other_objects
|
|
||||||
.filter_map(|(_, object)| {
|
|
||||||
let intersection_context = match object.kind.intersects_ray_at(&ray) {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(err) => {
|
|
||||||
error!("Error while performing shadow casting: {err}");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}?;
|
|
||||||
let intersection_time = *intersection_context.time;
|
|
||||||
|
|
||||||
match light.kind {
|
|
||||||
// In the case of point lights, we must check to see if both t > 0 and
|
|
||||||
// t is less than the time it took to even get to the light.
|
|
||||||
LightKind::Point { location, .. } => {
|
|
||||||
let light_time = (location - ray.origin).norm();
|
|
||||||
|
|
||||||
if intersection_time <= 0.0 || intersection_time >= light_time {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let soft_shadow_coefficient =
|
|
||||||
self.compute_soft_shadow_coefficient(location, point, object);
|
|
||||||
Some(soft_shadow_coefficient)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// In the case of directional lights, only t > 0 needs to be checked,
|
|
||||||
// otherwise
|
|
||||||
LightKind::Directional { .. } => {
|
|
||||||
if intersection_time <= 0.0 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(0.0) // complete obstruction
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let average =
|
|
||||||
intersections.iter().cloned().sum::<f64>() / intersections.len() as f64;
|
|
||||||
|
|
||||||
match intersections.is_empty() {
|
|
||||||
true => 1.0,
|
|
||||||
false => average,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_soft_shadow_coefficient(
|
|
||||||
&self,
|
|
||||||
light_location: Vector3<f64>,
|
|
||||||
original_intersection_point: Vector3<f64>,
|
|
||||||
object: &Object,
|
|
||||||
) -> f64 {
|
|
||||||
// Soft shadows: jitter some rays here to somewhere close to the
|
|
||||||
// actual location as well, and measure the proportion
|
|
||||||
// of them that intersect any objects
|
|
||||||
const JITTER_RADIUS: f64 = 1.0;
|
|
||||||
const JITTER_RAYS: usize = 75;
|
|
||||||
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
let locations = iter::repeat_with(|| {
|
|
||||||
let x = rng.gen_range(0.0..JITTER_RADIUS);
|
|
||||||
let y = rng.gen_range(0.0..JITTER_RADIUS);
|
|
||||||
let z = rng.gen_range(0.0..JITTER_RADIUS);
|
|
||||||
let delta = Vector3::new(x, y, z);
|
|
||||||
light_location + delta
|
|
||||||
})
|
|
||||||
.take(JITTER_RAYS)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let num_obstructed_rays = locations
|
|
||||||
.into_par_iter()
|
|
||||||
.filter(|location| {
|
|
||||||
let direction = (location - original_intersection_point).normalize();
|
|
||||||
let ray = Ray {
|
|
||||||
origin: original_intersection_point,
|
|
||||||
direction,
|
|
||||||
};
|
|
||||||
|
|
||||||
let intersection_context = match object.kind.intersects_ray_at(&ray) {
|
|
||||||
Ok(Some(v)) => v,
|
|
||||||
Ok(None) => return false,
|
|
||||||
Err(err) => {
|
|
||||||
error!("Error while performing shadow casting: {err}");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let light_time = (location - ray.origin).norm();
|
|
||||||
let intersection_time = *intersection_context.time;
|
|
||||||
|
|
||||||
0.0 < intersection_time && intersection_time < light_time
|
|
||||||
})
|
|
||||||
.count();
|
|
||||||
|
|
||||||
(JITTER_RAYS - num_obstructed_rays) as f64 / JITTER_RAYS as f64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Information about an intersection
|
|
||||||
#[derive(Derivative)]
|
|
||||||
#[derivative(Debug, PartialEq, PartialOrd, Ord)]
|
|
||||||
pub struct IntersectionContext {
|
|
||||||
/// The time of the intersection in the parametric ray
|
|
||||||
///
|
|
||||||
/// Unfortunately, IEEE floats in Rust don't have total ordering, because
|
|
||||||
/// NaNs violate ordering properties. The way to remedy this is to ensure we
|
|
||||||
/// don't have NaNs by wrapping it into this type, which then implements
|
|
||||||
/// total ordering.
|
|
||||||
pub time: NotNan<f64>,
|
|
||||||
|
|
||||||
/// The intersection point.
|
|
||||||
#[derivative(PartialEq = "ignore", Ord = "ignore")]
|
|
||||||
pub point: Vector3<f64>,
|
|
||||||
|
|
||||||
/// The normal vector protruding from the surface of the object at the
|
|
||||||
/// intersection point
|
|
||||||
#[derivative(PartialEq = "ignore", Ord = "ignore")]
|
|
||||||
pub normal: Vector3<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for IntersectionContext {}
|
|
||||||
|
|
||||||
impl IntersectionContext {}
|
|
|
@ -1,191 +0,0 @@
|
||||||
use std::{fs::File, io::Read, path::Path};
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use nalgebra::Vector3;
|
|
||||||
|
|
||||||
use crate::scene::{
|
|
||||||
cylinder::Cylinder,
|
|
||||||
data::{Attenuation, Light, LightKind, Material, Object},
|
|
||||||
sphere::Sphere,
|
|
||||||
Scene,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::data::{DepthCueing, ObjectKind};
|
|
||||||
|
|
||||||
impl Scene {
|
|
||||||
/// Parse the input file into a scene
|
|
||||||
pub fn from_input_file(path: impl AsRef<Path>) -> Result<Self> {
|
|
||||||
// Scope the read so the file is dropped and closed immediately after the
|
|
||||||
// contents have been read to memory
|
|
||||||
let contents = {
|
|
||||||
let mut contents = String::new();
|
|
||||||
let mut file = File::open(path.as_ref())?;
|
|
||||||
file.read_to_string(&mut contents)?;
|
|
||||||
contents
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut scene = Scene::default();
|
|
||||||
let mut material_color = None;
|
|
||||||
|
|
||||||
for line in contents.lines() {
|
|
||||||
let mut parts = line.split_whitespace();
|
|
||||||
let keyword = match parts.next() {
|
|
||||||
Some(v) => v,
|
|
||||||
None => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
if keyword == "imsize" {
|
|
||||||
let parts = parts
|
|
||||||
.map(|s| s.parse::<usize>().map_err(|e| e.into()))
|
|
||||||
.collect::<Result<Vec<_>>>()?;
|
|
||||||
if let [width, height] = parts[..] {
|
|
||||||
scene.image_width = width;
|
|
||||||
scene.image_height = height;
|
|
||||||
}
|
|
||||||
} else if keyword == "projection" {
|
|
||||||
if let Some("parallel") = parts.next() {
|
|
||||||
scene.parallel_projection = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Do float parsing instead
|
|
||||||
else {
|
|
||||||
let parts = parts
|
|
||||||
.map(|s| s.parse::<f64>().map_err(|e| e.into()))
|
|
||||||
.collect::<Result<Vec<_>>>()?;
|
|
||||||
|
|
||||||
let read_vec3 = |start: usize| {
|
|
||||||
ensure!(parts.len() >= start + 3, "Vec3 requires 3 components.");
|
|
||||||
|
|
||||||
Ok(Vector3::new(
|
|
||||||
parts[start],
|
|
||||||
parts[start + 1],
|
|
||||||
parts[start + 2],
|
|
||||||
))
|
|
||||||
};
|
|
||||||
|
|
||||||
match keyword {
|
|
||||||
"eye" => scene.eye_pos = read_vec3(0)?,
|
|
||||||
"viewdir" => scene.view_dir = read_vec3(0)?,
|
|
||||||
"updir" => scene.up_dir = read_vec3(0)?,
|
|
||||||
|
|
||||||
"hfov" => scene.hfov = parts[0],
|
|
||||||
"bkgcolor" => scene.bkg_color = read_vec3(0)?,
|
|
||||||
|
|
||||||
// light x y z w r g b
|
|
||||||
"light" => {
|
|
||||||
ensure!(parts.len() == 7, "Light requires 7 params");
|
|
||||||
|
|
||||||
let kind = match parts[3] as usize {
|
|
||||||
0 => LightKind::Directional {
|
|
||||||
direction: read_vec3(0)?,
|
|
||||||
},
|
|
||||||
1 => LightKind::Point {
|
|
||||||
location: read_vec3(0)?,
|
|
||||||
attenuation: None,
|
|
||||||
},
|
|
||||||
_ => bail!("Invalid w; must be either 0 or 1"),
|
|
||||||
};
|
|
||||||
let light = Light {
|
|
||||||
kind,
|
|
||||||
color: read_vec3(4)?,
|
|
||||||
};
|
|
||||||
scene.lights.push(light);
|
|
||||||
}
|
|
||||||
|
|
||||||
// attlight x y z w r g b c1 c2 c3
|
|
||||||
"attlight" => {
|
|
||||||
ensure!(parts.len() == 10, "Attenuated light requires 10 params");
|
|
||||||
|
|
||||||
let kind = match parts[3] as usize {
|
|
||||||
// TODO: Is this even defined? Pending TA answer
|
|
||||||
0 => LightKind::Directional {
|
|
||||||
direction: read_vec3(0)?,
|
|
||||||
},
|
|
||||||
1 => LightKind::Point {
|
|
||||||
location: read_vec3(0)?,
|
|
||||||
attenuation: Some(Attenuation {
|
|
||||||
c1: parts[7],
|
|
||||||
c2: parts[8],
|
|
||||||
c3: parts[9],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
_ => bail!("Invalid w; must be either 0 or 1"),
|
|
||||||
};
|
|
||||||
let light = Light {
|
|
||||||
kind,
|
|
||||||
color: read_vec3(4)?,
|
|
||||||
};
|
|
||||||
scene.lights.push(light);
|
|
||||||
}
|
|
||||||
|
|
||||||
// depthcueing dcr dcg dcb amax amin distmax distmin
|
|
||||||
"depthcueing" => {
|
|
||||||
ensure!(parts.len() == 7, "Depth cueing requires 7 params");
|
|
||||||
|
|
||||||
let color = read_vec3(0)?;
|
|
||||||
scene.depth_cueing = DepthCueing {
|
|
||||||
color,
|
|
||||||
a_max: parts[3],
|
|
||||||
a_min: parts[4],
|
|
||||||
dist_max: parts[5],
|
|
||||||
dist_min: parts[6],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// mtlcolor Odr Odg Odb Osr Osg Osb ka kd ks n
|
|
||||||
"mtlcolor" => {
|
|
||||||
ensure!(parts.len() == 10, "Material color requires 10 params");
|
|
||||||
|
|
||||||
let diffuse_color = read_vec3(0)?;
|
|
||||||
let specular_color = read_vec3(3)?;
|
|
||||||
|
|
||||||
let material = Material {
|
|
||||||
diffuse_color,
|
|
||||||
specular_color,
|
|
||||||
k_a: parts[6],
|
|
||||||
k_d: parts[7],
|
|
||||||
k_s: parts[8],
|
|
||||||
exponent: parts[9],
|
|
||||||
};
|
|
||||||
|
|
||||||
let idx = scene.materials.len();
|
|
||||||
material_color = Some(idx);
|
|
||||||
scene.materials.push(material);
|
|
||||||
}
|
|
||||||
|
|
||||||
"sphere" => scene.objects.push(Object {
|
|
||||||
kind: ObjectKind::Sphere(Sphere {
|
|
||||||
center: read_vec3(0)?,
|
|
||||||
radius: parts[3],
|
|
||||||
}),
|
|
||||||
material: match material_color {
|
|
||||||
Some(v) => v,
|
|
||||||
None => {
|
|
||||||
bail!("Each sphere must be preceded by a `mtlcolor` line")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
"cylinder" => scene.objects.push(Object {
|
|
||||||
kind: ObjectKind::Cylinder(Cylinder {
|
|
||||||
center: read_vec3(0)?,
|
|
||||||
direction: read_vec3(3)?,
|
|
||||||
radius: parts[6],
|
|
||||||
length: parts[7],
|
|
||||||
}),
|
|
||||||
material: match material_color {
|
|
||||||
Some(v) => v,
|
|
||||||
None => {
|
|
||||||
bail!("Each sphere must be preceded by a `mtlcolor` line")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
_ => bail!("Unknown keyword {keyword}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(scene)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
pub mod cylinder;
|
|
||||||
pub mod data;
|
|
||||||
pub mod illumination;
|
|
||||||
pub mod input_file;
|
|
||||||
pub mod sphere;
|
|
||||||
|
|
||||||
use nalgebra::Vector3;
|
|
||||||
|
|
||||||
use crate::image::Color;
|
|
||||||
|
|
||||||
use self::data::{DepthCueing, Light, Material, Object, Attenuation};
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct Scene {
|
|
||||||
pub eye_pos: Vector3<f64>,
|
|
||||||
pub view_dir: Vector3<f64>,
|
|
||||||
pub up_dir: Vector3<f64>,
|
|
||||||
|
|
||||||
/// Horizontal field of view (in degrees)
|
|
||||||
pub hfov: f64,
|
|
||||||
pub parallel_projection: bool,
|
|
||||||
|
|
||||||
pub image_width: usize,
|
|
||||||
pub image_height: usize,
|
|
||||||
|
|
||||||
/// Background color
|
|
||||||
pub bkg_color: Color,
|
|
||||||
pub depth_cueing: DepthCueing,
|
|
||||||
pub attenuation: Attenuation,
|
|
||||||
|
|
||||||
pub materials: Vec<Material>,
|
|
||||||
pub lights: Vec<Light>,
|
|
||||||
pub objects: Vec<Object>,
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
use anyhow::Result;
|
|
||||||
use nalgebra::Vector3;
|
|
||||||
use ordered_float::NotNan;
|
|
||||||
|
|
||||||
use crate::{ray::Ray, utils::min_f64};
|
|
||||||
|
|
||||||
use super::illumination::IntersectionContext;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Sphere {
|
|
||||||
pub center: Vector3<f64>,
|
|
||||||
pub radius: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sphere {
|
|
||||||
/// Given a sphere, returns the first time at which this ray intersects the
|
|
||||||
/// sphere.
|
|
||||||
///
|
|
||||||
/// If there is no intersection point, returns None.
|
|
||||||
pub fn intersects_ray_at(
|
|
||||||
&self,
|
|
||||||
ray: &Ray,
|
|
||||||
) -> Result<Option<IntersectionContext>> {
|
|
||||||
let a = ray.direction.norm();
|
|
||||||
let b = 2.0
|
|
||||||
* (ray.direction.x * (ray.origin.x - self.center.x)
|
|
||||||
+ ray.direction.y * (ray.origin.y - self.center.y)
|
|
||||||
+ ray.direction.z * (ray.origin.z - self.center.z));
|
|
||||||
let c = (ray.origin.x - self.center.x).powi(2)
|
|
||||||
+ (ray.origin.y - self.center.y).powi(2)
|
|
||||||
+ (ray.origin.z - self.center.z).powi(2)
|
|
||||||
- self.radius.powi(2);
|
|
||||||
let discriminant = b * b - 4.0 * a * c;
|
|
||||||
|
|
||||||
let time = match discriminant {
|
|
||||||
// Discriminant < 0, means the equation has no solutions.
|
|
||||||
d if d < 0.0 => None,
|
|
||||||
|
|
||||||
// Discriminant == 0
|
|
||||||
d if d == 0.0 => Some(-b / (2.0 * a)),
|
|
||||||
|
|
||||||
d if d > 0.0 => {
|
|
||||||
let solution_1 = (-b + discriminant.sqrt()) / (2.0 * a);
|
|
||||||
let solution_2 = (-b - discriminant.sqrt()) / (2.0 * a);
|
|
||||||
|
|
||||||
let solutions = [solution_1, solution_2]
|
|
||||||
.into_iter()
|
|
||||||
// Remove any t < 0, since that means it's behind the viewer and we
|
|
||||||
// can't see it.
|
|
||||||
.filter(|t| *t >= 0.0);
|
|
||||||
|
|
||||||
// Return the minimum solution
|
|
||||||
min_f64(solutions)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Probably hit some NaN or Infinity value due to faulty inputs...
|
|
||||||
_ => unreachable!("Invalid determinant value: {discriminant}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let time = match time.and_then(|t| NotNan::new(t).ok()) {
|
|
||||||
Some(v) => v,
|
|
||||||
None => return Ok(None),
|
|
||||||
};
|
|
||||||
|
|
||||||
let point = ray.eval(*time);
|
|
||||||
let normal = (point - self.center).normalize();
|
|
||||||
|
|
||||||
Ok(Some(IntersectionContext {
|
|
||||||
time,
|
|
||||||
point,
|
|
||||||
normal,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
use anyhow::Result;
|
|
||||||
use nalgebra::{Matrix3, Vector3};
|
|
||||||
use ordered_float::NotNan;
|
|
||||||
|
|
||||||
/// Finds the minimum of an iterator of f64s, ignoring any NaN values
|
|
||||||
#[inline]
|
|
||||||
pub fn min_f64<I>(i: I) -> Option<f64>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = f64>,
|
|
||||||
{
|
|
||||||
i.filter_map(|i| NotNan::new(i).ok())
|
|
||||||
.min()
|
|
||||||
.map(|i| i.into_inner())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds the minimum of an iterator of f64s using the given predicate, ignoring
|
|
||||||
/// any NaN values
|
|
||||||
#[inline]
|
|
||||||
pub fn min_f64_by_key<I, F>(i: I, f: F) -> Option<f64>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = f64>,
|
|
||||||
F: FnMut(&NotNan<f64>),
|
|
||||||
{
|
|
||||||
i.filter_map(|i| NotNan::new(i).ok())
|
|
||||||
.min_by_key(f)
|
|
||||||
.map(|i| i.into_inner())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Dot-product between two 3D vectors.
|
|
||||||
#[inline]
|
|
||||||
pub fn dot(a: Vector3<f64>, b: Vector3<f64>) -> f64 {
|
|
||||||
a.x * b.x + a.y * b.y + a.z * b.z
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cross-product between two 3D vectors.
|
|
||||||
#[inline]
|
|
||||||
pub fn cross(a: Vector3<f64>, b: Vector3<f64>) -> Vector3<f64> {
|
|
||||||
let x = a.y * b.z - a.z * b.y;
|
|
||||||
let y = a.z * b.x - a.x * b.z;
|
|
||||||
let z = a.x * b.y - a.y * b.x;
|
|
||||||
Vector3::new(x, y, z)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate the rotation matrix between the 2 given vectors
|
|
||||||
///
|
|
||||||
/// Based on the method given [here][1].
|
|
||||||
///
|
|
||||||
/// [1]: https://math.stackexchange.com/a/897677
|
|
||||||
pub fn compute_rotation_matrix(
|
|
||||||
a: Vector3<f64>,
|
|
||||||
b: Vector3<f64>,
|
|
||||||
) -> Result<Matrix3<f64>> {
|
|
||||||
// Special case: if a and b are in the same direction, just return the
|
|
||||||
// identity matrix.
|
|
||||||
if a.normalize() == b.normalize() {
|
|
||||||
return Ok(Matrix3::identity());
|
|
||||||
}
|
|
||||||
|
|
||||||
let cos_t = dot(a, b);
|
|
||||||
let sin_t = cross(a, b).norm();
|
|
||||||
|
|
||||||
let g = Matrix3::new(cos_t, -sin_t, 0.0, sin_t, cos_t, 0.0, 0.0, 0.0, 1.0);
|
|
||||||
|
|
||||||
// New basis vectors
|
|
||||||
let u = a;
|
|
||||||
let v = (b - cos_t * a).normalize();
|
|
||||||
let w = cross(b, a);
|
|
||||||
|
|
||||||
// Not sure if this is required to be invertible?
|
|
||||||
let f_inverse = Matrix3::from_columns(&[u, v, w]);
|
|
||||||
let f = match f_inverse.try_inverse() {
|
|
||||||
Some(v) => v,
|
|
||||||
None => {
|
|
||||||
// So I ran into this case trying to compute the rotation matrix where one
|
|
||||||
// of the vector endpoints was (0, 0, 0). I'm pretty sure this case makes
|
|
||||||
// no sense in reality, which means if I ever encounter this case, I
|
|
||||||
// probably made a mistake somewhere before. So going to just error
|
|
||||||
// out here and screw recovering.
|
|
||||||
//
|
|
||||||
// println!("Failed to compute inverse matrix.");
|
|
||||||
// println!("- Initial: a = {a}, b = {b}");
|
|
||||||
// println!("- cos(t) = {cos_t}, sin(t) = {sin_t}");
|
|
||||||
// println!("- Basis: u = {u}, v = {v}, w = {w}");
|
|
||||||
bail!("Failed to compute inverse matrix of {f_inverse}\na = {a}\nb = {b}")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// if (f_inverse * g * f).norm() != 1.0 {
|
|
||||||
// bail!("WTF {}", (f_inverse * g * f).norm());
|
|
||||||
// }
|
|
||||||
|
|
||||||
Ok(f_inverse * g * f)
|
|
||||||
}
|
|
|
@ -1,173 +0,0 @@
|
||||||
---
|
|
||||||
geometry: margin=2cm
|
|
||||||
output: pdf_document
|
|
||||||
---
|
|
||||||
|
|
||||||
# Raytracer part B
|
|
||||||
|
|
||||||
This project implements a raytracer with Blinn-Phong illumination and shadows
|
|
||||||
implemented. The primary formula that is used by this implementation is:
|
|
||||||
|
|
||||||
\begin{equation}
|
|
||||||
I_{\lambda} =
|
|
||||||
k_a O_{d\lambda} +
|
|
||||||
\sum_{i=1}^{n_\textrm{lights}} \left(
|
|
||||||
f_\textrm{att} \cdot
|
|
||||||
S_i \cdot
|
|
||||||
IL_{i\lambda} \left[
|
|
||||||
k_d O_{d\lambda} \max ( 0, \vec{N} \cdot \vec{L_i} ) +
|
|
||||||
k_s O_{s\lambda} \max ( 0, \vec{N} \cdot \vec{H_i} )^n
|
|
||||||
\right]
|
|
||||||
\right)
|
|
||||||
\end{equation}
|
|
||||||
|
|
||||||
Where:
|
|
||||||
|
|
||||||
- $I_{\lambda}$ is the final illumination of the pixel on an object
|
|
||||||
- $k_a$ is the material's ambient reflectivity
|
|
||||||
- $k_d$ is the material's diffuse reflectivity
|
|
||||||
- $k_s$ is the material's specular reflectivity
|
|
||||||
- $n_\textrm{lights}$ is the number of lights
|
|
||||||
- $f_\textrm{att}$ is the light attenuation factor (1.0 if attenuation is not on)
|
|
||||||
- $S_i$ is the shadow coefficient for light $i$
|
|
||||||
- $IL_{i\lambda}$ is the intensity of light $i$
|
|
||||||
- $O_{d\lambda}$ is the object's diffuse color
|
|
||||||
- $O_{s\lambda}$ is the object's specular color
|
|
||||||
- $\vec{N}$ is the normal vector to the object's surface
|
|
||||||
- $\vec{L_i}$ is the direction from the intersection point to the light $i$
|
|
||||||
- $\vec{H_i}$ is halfway between the direction to the light $i$ and the
|
|
||||||
direction to the viewer
|
|
||||||
- $n$ is the exponent for the specular component
|
|
||||||
|
|
||||||
In this report we will look through how these various factors influence the
|
|
||||||
rendering of the scene. All the images along with their source `.txt` files,
|
|
||||||
rendered `.ppm` files, and converted `.png` files can be found in the `examples`
|
|
||||||
directory of this handin.
|
|
||||||
|
|
||||||
## Varying $k_a$
|
|
||||||
|
|
||||||
$k_a$ is the strength of ambient light. It's used as a coefficient for the
|
|
||||||
object's diffuse color, which keeps a constant value independent of the
|
|
||||||
positions of the object, light, and the viewer. In the image below, I varied
|
|
||||||
$k_a$ between 0.2 and 1. Note how the overall color of the ball increases or
|
|
||||||
decreases in brightness when all other factors remain constant.
|
|
||||||
|
|
||||||
![Varying $k_a$](examples/ka-demo.png){width=360px}
|
|
||||||
\
|
|
||||||
|
|
||||||
## Varying $k_d$
|
|
||||||
|
|
||||||
$k_d$ is the strength of the diffuse component. It also affects an object's
|
|
||||||
diffuse color, but at a strength that's affected by how much of it faces the
|
|
||||||
light. Much like the dark side of the moon, the parts of the object that aren't
|
|
||||||
pointed at the light will not receive as much of the light's influence. In the
|
|
||||||
image below, I varied $k_d$ between 0.2 and 1. Note how the part pointed to the
|
|
||||||
light changes the strength of the brightness as all other factors remain
|
|
||||||
constant.
|
|
||||||
|
|
||||||
![Varying $k_d$](examples/kd-demo.png){width=360px}
|
|
||||||
\
|
|
||||||
|
|
||||||
## Varying $k_s$
|
|
||||||
|
|
||||||
$k_s$ is the specular strength. It uses the object's specular color, which is
|
|
||||||
like its reflective component. When there is a large specular $k_s$, there's a
|
|
||||||
shine that appears on the object with a greater intensity. In the image below, I
|
|
||||||
varied $k_s$ between 0.2 and 1. Note how the whiteness of the light is more
|
|
||||||
reflective in higher $k_s$ values as other factors remain constant.
|
|
||||||
|
|
||||||
![Varying $k_s$](examples/ks-demo.png){width=360px}
|
|
||||||
\
|
|
||||||
|
|
||||||
## Varying $n$
|
|
||||||
|
|
||||||
$n$ is the exponent saying how big the radius of the specular highlight should
|
|
||||||
be. In the equation, increasing the exponent usually leads to smaller shines. In
|
|
||||||
the image below, I varied $n$ between 2 and 100. Note how the size of the shine
|
|
||||||
is the same intensity, but more focused but covers a smaller area as $n$
|
|
||||||
increases.
|
|
||||||
|
|
||||||
![Varying $n$](examples/n-demo.png){width=360px}
|
|
||||||
\
|
|
||||||
|
|
||||||
## Multiple lights
|
|
||||||
|
|
||||||
Multiple lights are handled by multiplying each light against an intensity
|
|
||||||
level, and then added together. Unfortunately, this means that the intensity of
|
|
||||||
each light can't be too bright. We rely on the image to not use lights that are
|
|
||||||
too bright. Because this may result in color values above 1.0, the final value
|
|
||||||
is clamped against 1.0. Below is an example of a scene with two lights; one to
|
|
||||||
the left and one to the right:
|
|
||||||
|
|
||||||
![Multiple lights](examples/multiple-lights-demo.png){width=360px}
|
|
||||||
\
|
|
||||||
|
|
||||||
## Shadows
|
|
||||||
|
|
||||||
Shadows are implemented by pointing a second ray between the intersection point
|
|
||||||
of the original view ray and each light. If the light has something obstructing
|
|
||||||
it in the middle, the light's effect is not used.
|
|
||||||
|
|
||||||
The soft shadow effect is realized by jittering rays across an area. In my
|
|
||||||
implementation, a jitter radius of about 1.0 is used, and 75 rays are shot into
|
|
||||||
uniformly sampled points within that radius. This also has the side effect that
|
|
||||||
rays that are closer to the original ray are sampled more frequently. Each of
|
|
||||||
these rays produces either 0 or 1 depending on if it was obstructed by the
|
|
||||||
object. Taking the proportion of rays that hit as a coefficient for the shadow,
|
|
||||||
we can get some soft shadow effects like this:
|
|
||||||
|
|
||||||
![Soft shadows](examples/soft-shadow-demo.png){width=360px}
|
|
||||||
\
|
|
||||||
|
|
||||||
## Light attenuation
|
|
||||||
|
|
||||||
Light attenuation is when more of the light is applied for objects that are
|
|
||||||
closer to a particular light source. The function that's applied is an inverse
|
|
||||||
quadratic formula with respect to the distance the object is from the light:
|
|
||||||
|
|
||||||
\begin{equation}
|
|
||||||
f_\textrm{att}(d) = \frac{1}{c_1 + c_2 d + c_3 d^2}
|
|
||||||
\end{equation}
|
|
||||||
|
|
||||||
Where:
|
|
||||||
|
|
||||||
- $f_\textrm{att}$ is the attenuation factor
|
|
||||||
- $d$ is the distance the object is from the light
|
|
||||||
- $c_1$, $c_2$, and $c_3$ are user-supplied coefficients
|
|
||||||
|
|
||||||
As you can see below, the effect of the light drops off with the distance from
|
|
||||||
the light (light coming from the left):
|
|
||||||
|
|
||||||
![Light attenuation](examples/attenuation-demo.png){width=360px}
|
|
||||||
\
|
|
||||||
|
|
||||||
## Depth Cueing
|
|
||||||
|
|
||||||
Depth cueing is when the objects further from the viewer have a lower opacity to
|
|
||||||
"fade" into the background in some sense. A good example of this can be seen in
|
|
||||||
the image below; note how the objects are less and less bright the further they
|
|
||||||
are away from the eye.
|
|
||||||
|
|
||||||
![Depth cueing](examples/depth-cueing-demo.png){width=360px}
|
|
||||||
\
|
|
||||||
|
|
||||||
## Shortcomings of the model
|
|
||||||
|
|
||||||
The Phong formula is just a model of how light works, and doesn't actually
|
|
||||||
represent reality. There's not actually rays physically escaping our eyes and
|
|
||||||
hitting objects; it's actually the other way around, but computing it that way
|
|
||||||
would not be efficient since we would be factoring in a lot of rays that don't
|
|
||||||
ever get rendered.
|
|
||||||
|
|
||||||
Also, one needs to take care to use reasonable constants. For example, if using
|
|
||||||
a different specular light color than the diffuse color, then it may produce
|
|
||||||
some bizarre lighting effects that may not actually look right compare to
|
|
||||||
reality.
|
|
||||||
|
|
||||||
# Arbitrary Objects
|
|
||||||
|
|
||||||
Here is an example scene with some objects that demonstrates some of the
|
|
||||||
features of the raytracer.
|
|
||||||
|
|
||||||
![Objects in the scene](examples/objects.png){width=360px}
|
|
||||||
\
|
|
10
assignment-1c/.gitignore
vendored
|
@ -1,10 +0,0 @@
|
||||||
/target
|
|
||||||
/assignment-1c
|
|
||||||
/raytracer1c
|
|
||||||
/examples/*.png
|
|
||||||
*.ppm
|
|
||||||
*.zip
|
|
||||||
*.pdf
|
|
||||||
perf.data*
|
|
||||||
flamegraph.svg
|
|
||||||
showcase.png
|
|
980
assignment-1c/Cargo.lock
generated
|
@ -1,980 +0,0 @@
|
||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "addr2line"
|
|
||||||
version = "0.19.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
|
|
||||||
dependencies = [
|
|
||||||
"gimli",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "adler"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.68"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
|
|
||||||
dependencies = [
|
|
||||||
"backtrace",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "approx"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "assignment-1c"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"base64",
|
|
||||||
"clap",
|
|
||||||
"derivative",
|
|
||||||
"generator",
|
|
||||||
"itertools",
|
|
||||||
"nalgebra",
|
|
||||||
"num",
|
|
||||||
"ordered-float",
|
|
||||||
"rand",
|
|
||||||
"rayon",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "backtrace"
|
|
||||||
version = "0.3.67"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
|
|
||||||
dependencies = [
|
|
||||||
"addr2line",
|
|
||||||
"cc",
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"miniz_oxide",
|
|
||||||
"object",
|
|
||||||
"rustc-demangle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base64"
|
|
||||||
version = "0.21.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytemuck"
|
|
||||||
version = "1.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.79"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap"
|
|
||||||
version = "4.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"clap_derive",
|
|
||||||
"clap_lex",
|
|
||||||
"is-terminal",
|
|
||||||
"once_cell",
|
|
||||||
"strsim",
|
|
||||||
"termcolor",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap_derive"
|
|
||||||
version = "4.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
|
|
||||||
dependencies = [
|
|
||||||
"heck",
|
|
||||||
"proc-macro-error",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap_lex"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
|
|
||||||
dependencies = [
|
|
||||||
"os_str_bytes",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-channel"
|
|
||||||
version = "0.5.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-deque"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-epoch",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.9.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"memoffset",
|
|
||||||
"scopeguard",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-utils"
|
|
||||||
version = "0.8.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derivative"
|
|
||||||
version = "2.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "either"
|
|
||||||
version = "1.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno"
|
|
||||||
version = "0.2.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
|
||||||
dependencies = [
|
|
||||||
"errno-dragonfly",
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno-dragonfly"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "generator"
|
|
||||||
version = "0.7.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d266041a359dfa931b370ef684cceb84b166beb14f7f0421f4a6a3d0c446d12e"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"rustversion",
|
|
||||||
"windows",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.2.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gimli"
|
|
||||||
version = "0.27.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "heck"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.2.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "io-lifetimes"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "is-terminal"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"io-lifetimes",
|
|
||||||
"rustix",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itertools"
|
|
||||||
version = "0.10.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.139"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-raw-sys"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log"
|
|
||||||
version = "0.4.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "matrixmultiply"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84"
|
|
||||||
dependencies = [
|
|
||||||
"rawpointer",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memoffset"
|
|
||||||
version = "0.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miniz_oxide"
|
|
||||||
version = "0.6.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
|
|
||||||
dependencies = [
|
|
||||||
"adler",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nalgebra"
|
|
||||||
version = "0.32.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f6515c882ebfddccaa73ead7320ca28036c4bc84c9bcca3cc0cbba8efe89223a"
|
|
||||||
dependencies = [
|
|
||||||
"approx",
|
|
||||||
"matrixmultiply",
|
|
||||||
"nalgebra-macros",
|
|
||||||
"num-complex",
|
|
||||||
"num-rational",
|
|
||||||
"num-traits",
|
|
||||||
"simba",
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nalgebra-macros"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nu-ansi-term"
|
|
||||||
version = "0.46.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
|
||||||
dependencies = [
|
|
||||||
"overload",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
|
|
||||||
dependencies = [
|
|
||||||
"num-bigint",
|
|
||||||
"num-complex",
|
|
||||||
"num-integer",
|
|
||||||
"num-iter",
|
|
||||||
"num-rational",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-bigint"
|
|
||||||
version = "0.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-complex"
|
|
||||||
version = "0.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-integer"
|
|
||||||
version = "0.1.45"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-iter"
|
|
||||||
version = "0.1.43"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-rational"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-bigint",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-traits"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_cpus"
|
|
||||||
version = "1.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "object"
|
|
||||||
version = "0.30.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "once_cell"
|
|
||||||
version = "1.17.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ordered-float"
|
|
||||||
version = "3.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d84eb1409416d254e4a9c8fa56cc24701755025b458f0fcd8e59e1f5f40c23bf"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "os_str_bytes"
|
|
||||||
version = "6.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "overload"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "paste"
|
|
||||||
version = "1.0.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project-lite"
|
|
||||||
version = "0.2.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ppv-lite86"
|
|
||||||
version = "0.2.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error-attr",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error-attr"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.50"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rawpointer"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon"
|
|
||||||
version = "1.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"rayon-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon-core"
|
|
||||||
version = "1.10.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-channel",
|
|
||||||
"crossbeam-deque",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"num_cpus",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-demangle"
|
|
||||||
version = "0.1.21"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustix"
|
|
||||||
version = "0.36.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"errno",
|
|
||||||
"io-lifetimes",
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustversion"
|
|
||||||
version = "1.0.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "safe_arch"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scopeguard"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.152"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sharded-slab"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "simba"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4"
|
|
||||||
dependencies = [
|
|
||||||
"approx",
|
|
||||||
"num-complex",
|
|
||||||
"num-traits",
|
|
||||||
"paste",
|
|
||||||
"wide",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smallvec"
|
|
||||||
version = "1.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strsim"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "1.0.107"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termcolor"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thread_local"
|
|
||||||
version = "1.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"once_cell",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing"
|
|
||||||
version = "0.1.37"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"pin-project-lite",
|
|
||||||
"tracing-attributes",
|
|
||||||
"tracing-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-attributes"
|
|
||||||
version = "0.1.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-core"
|
|
||||||
version = "0.1.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
|
||||||
dependencies = [
|
|
||||||
"once_cell",
|
|
||||||
"valuable",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-log"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
"log",
|
|
||||||
"tracing-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-subscriber"
|
|
||||||
version = "0.3.16"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
|
||||||
dependencies = [
|
|
||||||
"nu-ansi-term",
|
|
||||||
"sharded-slab",
|
|
||||||
"smallvec",
|
|
||||||
"thread_local",
|
|
||||||
"tracing-core",
|
|
||||||
"tracing-log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typenum"
|
|
||||||
version = "1.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-ident"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "valuable"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wide"
|
|
||||||
version = "0.7.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ae41ecad2489a1655c8ef8489444b0b113c0a0c795944a3572a0931cf7d2525c"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
"safe_arch",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows"
|
|
||||||
version = "0.39.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_msvc 0.39.0",
|
|
||||||
"windows_i686_gnu 0.39.0",
|
|
||||||
"windows_i686_msvc 0.39.0",
|
|
||||||
"windows_x86_64_gnu 0.39.0",
|
|
||||||
"windows_x86_64_msvc 0.39.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.42.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm",
|
|
||||||
"windows_aarch64_msvc 0.42.1",
|
|
||||||
"windows_i686_gnu 0.42.1",
|
|
||||||
"windows_i686_msvc 0.42.1",
|
|
||||||
"windows_x86_64_gnu 0.42.1",
|
|
||||||
"windows_x86_64_gnullvm",
|
|
||||||
"windows_x86_64_msvc 0.42.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.39.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.39.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.39.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.39.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.39.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.42.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
|
|
@ -1,24 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "assignment-1c"
|
|
||||||
authors = ["Michael Zhang <zhan4854@umn.edu>"]
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "raytracer1c"
|
|
||||||
path = "src/main.rs"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
|
||||||
base64 = "0.21.0"
|
|
||||||
clap = { version = "4.1.4", features = ["cargo", "derive"] }
|
|
||||||
derivative = "2.2.0"
|
|
||||||
generator = "0.7.2"
|
|
||||||
itertools = "0.10.5"
|
|
||||||
nalgebra = "0.32.1"
|
|
||||||
num = { version = "0.4.0", features = ["serde"] }
|
|
||||||
ordered-float = "3.4.0"
|
|
||||||
rand = "0.8.5"
|
|
||||||
rayon = "1.6.1"
|
|
||||||
tracing = "0.1.37"
|
|
||||||
tracing-subscriber = "0.3.16"
|
|
|
@ -1,46 +0,0 @@
|
||||||
.PHONY: all clean
|
|
||||||
|
|
||||||
.PRECIOUS: $(EXAMPLES_PPM)
|
|
||||||
|
|
||||||
RAYTRACER_FLAGS :=
|
|
||||||
DOCKER := docker
|
|
||||||
ZIP := zip
|
|
||||||
PANDOC := pandoc
|
|
||||||
CONVERT := convert
|
|
||||||
|
|
||||||
HANDIN := ./hw1c.michael.zhang.zip
|
|
||||||
BINARY := ./raytracer1c
|
|
||||||
SOURCES := Cargo.toml $(shell find -name "*.rs")
|
|
||||||
|
|
||||||
EXAMPLES := $(shell find examples -name "*.txt")
|
|
||||||
EXAMPLES_PPM := $(patsubst %.txt,%.ppm,$(EXAMPLES))
|
|
||||||
EXAMPLES_PNG := $(patsubst %.txt,%.png,$(EXAMPLES))
|
|
||||||
|
|
||||||
all: $(HANDIN)
|
|
||||||
|
|
||||||
$(BINARY): $(SOURCES)
|
|
||||||
mkdir -p target/docker
|
|
||||||
$(DOCKER) run \
|
|
||||||
--rm \
|
|
||||||
-v "$(shell pwd)":/usr/src/myapp \
|
|
||||||
-v cargo-registry:/usr/local/cargo \
|
|
||||||
--user "$(shell id -u)":"$(shell id -g)" \
|
|
||||||
-w /usr/src/myapp \
|
|
||||||
-e CARGO_TARGET_DIR=/usr/src/myapp/target/docker \
|
|
||||||
rust \
|
|
||||||
cargo build --profile release-handin
|
|
||||||
mv target/docker/release-handin/raytracer1c $@
|
|
||||||
|
|
||||||
$(HANDIN): $(BINARY) Makefile Cargo.toml Cargo.lock README.md $(EXAMPLES_PNG) $(EXAMPLES_PPM)
|
|
||||||
$(ZIP) -r $@ src examples $^
|
|
||||||
|
|
||||||
examples/%.ppm: examples/%.txt $(SOURCES)
|
|
||||||
cargo run --release -- -o $@ $(RAYTRACER_FLAGS) $<
|
|
||||||
|
|
||||||
examples/%.png: examples/%.ppm
|
|
||||||
convert $< $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf target/docker \
|
|
||||||
$(HANDIN) $(BINARY) \
|
|
||||||
$(EXAMPLES_PPM) $(EXAMPLES_PNG)
|
|
|
@ -1,29 +0,0 @@
|
||||||
# Raycaster
|
|
||||||
|
|
||||||
## Bundle contents
|
|
||||||
|
|
||||||
Writeup is located at `/writeup.pdf`.
|
|
||||||
|
|
||||||
The binary can be found at `/raytracer1b`. Run `./raytracer1b --help` to see
|
|
||||||
how to use it. The binary has been built using the Rust Docker image, which
|
|
||||||
should have an environment similar to CSELabs. If there is trouble running the
|
|
||||||
binary, try building from source, as documented below.
|
|
||||||
|
|
||||||
Examples are found in the `examples` directory. The text files are the input
|
|
||||||
sources, and the ppm files are the corresponding outputs. They have been
|
|
||||||
generated by running this program. For convenience, pngs have also been provided
|
|
||||||
using imagemagick.
|
|
||||||
|
|
||||||
## Showcase image
|
|
||||||
|
|
||||||
The showcase image can be found at `/showcase.png`.
|
|
||||||
|
|
||||||
## Building from source
|
|
||||||
|
|
||||||
The Makefile currently uses Docker to produce a more consistent build. If you
|
|
||||||
have a Rust+Cargo toolchain installed locally, it's also possible to build the
|
|
||||||
source using just:
|
|
||||||
|
|
||||||
cargo build --release
|
|
||||||
|
|
||||||
The binary will be found in `target/release`.
|
|
2
assignment-1c/examples/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
||||||
# Necessary files
|
|
||||||
!/earthtexture.ppm
|
|
|
@ -1,17 +0,0 @@
|
||||||
eye 0 0 0
|
|
||||||
viewdir 0 0 -1
|
|
||||||
updir 0 1 0
|
|
||||||
hfov 60
|
|
||||||
imsize 512 256
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
light -2 1 0 1 1 1 1
|
|
||||||
mtlcolor 1 0 1 1 1 1 0.1 0.4 0.4 20
|
|
||||||
|
|
||||||
|
|
||||||
v -2 1 -5
|
|
||||||
v -1 -1 -4
|
|
||||||
v 1 -1 -4
|
|
||||||
v 2 1 -6
|
|
||||||
|
|
||||||
f 1 2 3
|
|
||||||
f 1 3 4
|
|
|
@ -1,21 +0,0 @@
|
||||||
eye 0 0 0
|
|
||||||
viewdir 0 0 -1
|
|
||||||
updir 0 1 0
|
|
||||||
hfov 60
|
|
||||||
imsize 512 256
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
light -2 1 0 1 1 1 1
|
|
||||||
mtlcolor 1 0 1 1 1 1 0.1 0.4 0.4 20
|
|
||||||
|
|
||||||
|
|
||||||
v -2 1 -5
|
|
||||||
v -1 -1 -4
|
|
||||||
v 1 -1 -4
|
|
||||||
v 2 1 -6
|
|
||||||
|
|
||||||
vn -2 1 1
|
|
||||||
vn -1 -1 1
|
|
||||||
vn 2 1 1
|
|
||||||
|
|
||||||
f 1//1 2//2 3//3
|
|
||||||
f 1 3 4
|
|
|
@ -1,10 +0,0 @@
|
||||||
eye 2 -6 1
|
|
||||||
viewdir -1 3 -0.5
|
|
||||||
updir 0 0 1
|
|
||||||
hfov 50
|
|
||||||
imsize 512 512
|
|
||||||
bkgcolor 0.5 0.7 0.9
|
|
||||||
light 0 1 -1 0 1 1 1
|
|
||||||
mtlcolor 0 1 0 1 1 1 0.2 0.8 0.1 20
|
|
||||||
texture earthtexture.ppm
|
|
||||||
sphere 0 0 0 2
|
|
Before Width: | Height: | Size: 9.9 KiB |
|
@ -1,14 +0,0 @@
|
||||||
eye 0 0 0
|
|
||||||
viewdir 0 0 -1
|
|
||||||
updir 0 1 0
|
|
||||||
hfov 60
|
|
||||||
imsize 512 256
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
light -2 1 0 1 1 1 1
|
|
||||||
mtlcolor 0 1 0 1 1 1 0.2 0.6 0.2 20
|
|
||||||
v 0 1 -4
|
|
||||||
v -1 -1 -4
|
|
||||||
v 1 -1 -4
|
|
||||||
v 2 1 -6
|
|
||||||
f 1 2 3
|
|
||||||
f 1 3 4
|
|
Before Width: | Height: | Size: 12 KiB |
|
@ -1,18 +0,0 @@
|
||||||
eye 0 0 0
|
|
||||||
viewdir 0 0 -1
|
|
||||||
updir 0 1 0
|
|
||||||
hfov 60
|
|
||||||
imsize 512 256
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
light -2 1 0 1 1 1 1
|
|
||||||
mtlcolor 0 0 1 1 1 1 0.2 0.6 0.2 20
|
|
||||||
v -1 1 -4
|
|
||||||
v -1 -1 -4
|
|
||||||
v 1 -1 -4
|
|
||||||
v 1 1 -4
|
|
||||||
vn -1 1 1
|
|
||||||
vn -1 -1 1
|
|
||||||
vn 1 -1 1
|
|
||||||
vn 1 1 1
|
|
||||||
f 1//1 2//2 3//3
|
|
||||||
f 1//1 3//3 4//4
|
|
Before Width: | Height: | Size: 105 KiB |
|
@ -1,10 +0,0 @@
|
||||||
eye 2 -6 1
|
|
||||||
viewdir -1 3 -0.5
|
|
||||||
updir 0 0 1
|
|
||||||
hfov 50
|
|
||||||
imsize 512 512
|
|
||||||
bkgcolor 0.5 0.7 0.9
|
|
||||||
light 0 1 -1 0 1 1 1
|
|
||||||
mtlcolor 0 1 0 1 1 1 0.2 0.8 0.1 20
|
|
||||||
texture earthtexture.ppm
|
|
||||||
sphere 0 0 0 2
|
|
Before Width: | Height: | Size: 28 KiB |
|
@ -1,19 +0,0 @@
|
||||||
eye 0 0 0
|
|
||||||
viewdir 0 0 -1
|
|
||||||
updir 0 1 0
|
|
||||||
hfov 60
|
|
||||||
imsize 512 256
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
light -2 1 0 1 1 1 1
|
|
||||||
mtlcolor 0 0 1 1 1 1 0.2 0.6 0.2 20
|
|
||||||
texture umn.ppm
|
|
||||||
v -1 1 -4
|
|
||||||
v -1 -1 -4
|
|
||||||
v 1 -1 -4
|
|
||||||
v 1 1 -4
|
|
||||||
vt 0 0
|
|
||||||
vt 0 1
|
|
||||||
vt 1 1
|
|
||||||
vt 1 0
|
|
||||||
f 1/1 2/2 3/3
|
|
||||||
f 1/1 3/3 4/4
|
|
Before Width: | Height: | Size: 25 KiB |
|
@ -1,25 +0,0 @@
|
||||||
eye 0 0 0
|
|
||||||
viewdir 0 0 -1
|
|
||||||
updir 0 1 0
|
|
||||||
hfov 60
|
|
||||||
imsize 512 256
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
light -2 1 0 1 1 1 1
|
|
||||||
mtlcolor 0 0 1 1 1 1 0.2 0.6 0.2 20
|
|
||||||
texture umn.ppm
|
|
||||||
v -1 1 -4
|
|
||||||
v -1 -1 -4
|
|
||||||
v 1 -1 -4
|
|
||||||
v 1 1 -4
|
|
||||||
vn -1 1 1
|
|
||||||
vn -1 -1 1
|
|
||||||
vn 1 -1 1
|
|
||||||
vn 1 1 1
|
|
||||||
vt 0 0
|
|
||||||
vt 0 1
|
|
||||||
vt 1 1
|
|
||||||
vt 1 0
|
|
||||||
f 1/1/1 2/2/2 3/3/3
|
|
||||||
f 1/1/1 3/3/3 4/4/4
|
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 640 KiB |
|
@ -1,56 +0,0 @@
|
||||||
eye 12.5 5 2.5
|
|
||||||
viewdir -2 -0.5 2
|
|
||||||
updir 0 1 0
|
|
||||||
hfov 60
|
|
||||||
imsize 900 600
|
|
||||||
bkgcolor 0.5 0.7 0.9
|
|
||||||
light 1 -1 1 0 1 1 1
|
|
||||||
mtlcolor 0 1 0 1 1 1 0.2 0.8 0 20
|
|
||||||
v 10 0 5
|
|
||||||
v -10 0 5
|
|
||||||
v -10 0 25
|
|
||||||
v 10 0 25
|
|
||||||
v 5 0 12.5
|
|
||||||
v -5 0 12.5
|
|
||||||
v -5 5 12.5
|
|
||||||
v 5 5 12.5
|
|
||||||
v 5 0 17.5
|
|
||||||
v -5 0 17.5
|
|
||||||
v -5 5 17.5
|
|
||||||
v 5 5 17.5
|
|
||||||
v 5 7.5 15
|
|
||||||
v -5 7.5 15
|
|
||||||
v 5 4.5 12
|
|
||||||
v -5 4.5 12
|
|
||||||
v 5 4.5 18
|
|
||||||
v -5 4.5 18
|
|
||||||
vt 0 0
|
|
||||||
vt 0 1
|
|
||||||
vt 1 1
|
|
||||||
vt 1 0
|
|
||||||
vt 2 0
|
|
||||||
vt 2 1
|
|
||||||
vt 0.5 0
|
|
||||||
vt 4 0
|
|
||||||
vt 4 1
|
|
||||||
texture grass.ppm
|
|
||||||
f 1/2 2/3 3/4
|
|
||||||
f 1/2 3/4 4/1
|
|
||||||
texture wood.ppm
|
|
||||||
f 5/2 6/6 7/5
|
|
||||||
f 5/2 7/5 8/1
|
|
||||||
f 9/2 11/5 10/6
|
|
||||||
f 9/2 12/1 11/5
|
|
||||||
f 6/2 10/3 11/4
|
|
||||||
f 6/2 11/4 7/1
|
|
||||||
f 5/3 12/1 9/2
|
|
||||||
f 5/3 8/4 12/1
|
|
||||||
f 7/2 11/3 14/7
|
|
||||||
f 8/3 13/7 12/2
|
|
||||||
texture redwood.ppm
|
|
||||||
f 13/1 15/2 16/9
|
|
||||||
f 13/1 16/9 14/8
|
|
||||||
f 13/8 14/1 18/2
|
|
||||||
f 13/8 18/2 17/9
|
|
||||||
texture soccerball.ppm
|
|
||||||
sphere -2.5 0.5 9 0.5
|
|
Before Width: | Height: | Size: 46 KiB |
|
@ -1,20 +0,0 @@
|
||||||
eye 0 0 0
|
|
||||||
viewdir 0 0 -1
|
|
||||||
updir 0 1 0
|
|
||||||
hfov 60
|
|
||||||
imsize 512 256
|
|
||||||
bkgcolor 0.1 0.1 0.1
|
|
||||||
light -2 1 0 1 1 1 1
|
|
||||||
mtlcolor 1 1 1 1 1 1 0.2 0.6 0.2 20 1 0
|
|
||||||
bump normalmap.ppm
|
|
||||||
sphere -1.6 0 -4 0.5
|
|
||||||
v -1 1 -4
|
|
||||||
v -1 -1 -4
|
|
||||||
v 1 -1 -4
|
|
||||||
v 1 1 -4
|
|
||||||
vt 0 0
|
|
||||||
vt 0 1
|
|
||||||
vt 1 1
|
|
||||||
vt 1 0
|
|
||||||
f 1/1 2/2 3/3
|
|
||||||
f 1/1 3/3 4/4
|
|