Add writeup
This commit is contained in:
parent
00000170e4
commit
00000180d3
9 changed files with 114 additions and 19 deletions
2
assignment-1/.gitignore
vendored
2
assignment-1/.gitignore
vendored
|
@ -1,3 +1,5 @@
|
|||
/target
|
||||
/assignment-1
|
||||
*.ppm
|
||||
*.zip
|
||||
*.pdf
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
# Raycaster
|
BIN
assignment-1/doc/fov.jpg
Normal file
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
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
BIN
assignment-1/doc/rot.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
|
@ -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
73
assignment-1/writeup.md
Normal 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)
|
24
flake.nix
24
flake.nix
|
@ -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";
|
||||
};
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue