Add writeup

This commit is contained in:
Michael Zhang 2023-02-01 16:13:48 -06:00
parent 00000170e4
commit 00000180d3
9 changed files with 114 additions and 19 deletions

View file

@ -1,3 +1,5 @@
/target
/assignment-1
*.ppm
*.zip
*.pdf

View file

@ -1,13 +1,18 @@
.PHONY: clean
.PHONY: all clean
DOCKER := docker
ZIP := zip
PANDOC := pandoc
HANDIN := hw1a.michael.zhang.zip
BINARY := target/release/assignment-1
BINARY := assignment-1
WRITEUP := writeup.pdf
SOURCES := $(shell find -name "*.rs")
all: $(HANDIN)
$(BINARY):
docker run \
$(BINARY): $(SOURCES)
$(DOCKER) run \
--rm \
-v "$(shell pwd)":/usr/src/myapp \
-v cargo-registry:/usr/local/cargo \
@ -15,9 +20,13 @@ $(BINARY):
-w /usr/src/myapp \
rust \
cargo build --release
mv target/release/assignment-1 $@
$(HANDIN): $(BINARY) Cargo.toml Cargo.lock README.md
zip -r $@ src $<
$(HANDIN): $(BINARY) $(WRITEUP) Cargo.toml Cargo.lock README.md
$(ZIP) -r $@ src $<
writeup.pdf: writeup.md
$(PANDOC) -o $@ $<
clean:
rm -f $(HANDIN) $(BINARY)
rm -f $(HANDIN) $(BINARY) $(WRITEUP)

View file

@ -1 +0,0 @@
# Raycaster

BIN
assignment-1/doc/fov.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
assignment-1/doc/map.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
assignment-1/doc/rot.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -59,7 +59,13 @@ fn main() -> Result<()> {
move |px: usize, py: usize| {
let x_component = pixel_base_x * px as f64;
let y_component = pixel_base_y * py as f64;
view_window.upper_left + x_component + y_component
// 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
}
};

73
assignment-1/writeup.md Normal file
View file

@ -0,0 +1,73 @@
---
geometry: margin=2cm
output: pdf_document
---
# Raycaster
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.
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}
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)

View file

@ -12,16 +12,22 @@
toolchain = pkgs.fenix.stable;
in rec {
devShell = pkgs.mkShell {
packages =
(with pkgs; [ cargo-watch cargo-deny cargo-edit zip unzip ])
++ (with toolchain; [
cargo
rustc
clippy
packages = (with pkgs; [
cargo-watch
cargo-deny
cargo-edit
pandoc
zip
unzip
texlive.combined.scheme-full
]) ++ (with toolchain; [
cargo
rustc
clippy
# Get the nightly version of rustfmt so we can wrap comments
pkgs.fenix.default.rustfmt
]);
# Get the nightly version of rustfmt so we can wrap comments
pkgs.fenix.default.rustfmt
]);
CARGO_UNSTABLE_SPARSE_REGISTRY = "true";
};
});