From e93eee4bb96bd2d81e422dc9d453da6138fd6ba2 Mon Sep 17 00:00:00 2001 From: Martin Lehoux Date: Sun, 5 Apr 2020 22:46:01 -0700 Subject: misc - Doc --- .gitignore | 2 ++ camera.go | 6 +++-- color.go | 49 +++++++++++++++++++++---------------- image.go | 7 ++++-- main.go | 83 +++++++++++++++++++++++++++++++++++++++----------------------- ray.go | 2 ++ utils.go | 9 +++++++ 7 files changed, 103 insertions(+), 55 deletions(-) create mode 100644 .gitignore create mode 100644 utils.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f90281d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +frames +.DS_Store \ No newline at end of file diff --git a/camera.go b/camera.go index 6575390..6cc3391 100644 --- a/camera.go +++ b/camera.go @@ -1,15 +1,17 @@ package main +// Camera handle view position and screen type Camera struct { - lower_left_corner Vec3D + lowerLeftCorner Vec3D origin, horizontal, vertical Vec3D } +// GetRay computes Ray given screen params func (camera Camera) GetRay(u float64, v float64) Ray { return Ray{ camera.origin, AddVec3D(AddVec3D( - camera.lower_left_corner, + camera.lowerLeftCorner, ScalarProduct(u, camera.horizontal)), ScalarProduct(v, camera.vertical), ), diff --git a/color.go b/color.go index bb7318a..70c65f1 100644 --- a/color.go +++ b/color.go @@ -2,14 +2,17 @@ package main import "math" +// Color in RGB, each val being between 0 and 1 type Color struct { r, g, b float64 } +// ToPixel converts a 0-1 color to a 0-255 pixel func (color Color) ToPixel() Pixel { return Pixel{int(color.r * 255), int(color.g * 255), int(color.b * 255)} } +// LinearBlend mixes two colors with a float param func LinearBlend(color1 Color, color2 Color, param float64) Color { return Color{ param*color1.r + (1.0-param)*color2.r, @@ -18,6 +21,7 @@ func LinearBlend(color1 Color, color2 Color, param float64) Color { } } +// AttenuateColor multiplies two colors func AttenuateColor(attenuation Color, color Color) Color { return Color{ attenuation.r * color.r, @@ -26,37 +30,40 @@ func AttenuateColor(attenuation Color, color Color) Color { } } -func RayColor(ray Ray, hitable_list HitableList, depth int) Color { - if depth > MAX_DEPTH { +// RayColor finds a hit for a ray, scatters the ray and return the ray color +func RayColor(ray Ray, hitableList HitableList, depth int) Color { + if depth > MaxDepth { return Color{0.0, 0.0, 0.0} } - hit := hitable_list.Hit(ray, T_MIN, T_MAX) + hit := hitableList.Hit(ray, TMin, TMax) if hit.time > 0.0 { scattered, attenuation := hit.material.Scatter(ray, hit) - return AttenuateColor(attenuation, RayColor(scattered, hitable_list, depth+1)) + return AttenuateColor(attenuation, RayColor(scattered, hitableList, depth+1)) } param := 0.5 * (ray.direction.Unit().y + 1) return LinearBlend(Color{0.5, 0.7, 1.0}, Color{1.0, 1.0, 1.0}, param) } -func ColorMean(color_list [RAY_PER_PIXEL]Color) Color { - length := float64(len(color_list)) - mean_color := Color{} - for _, color := range color_list { - mean_color.r += color.r - mean_color.g += color.g - mean_color.b += color.b +// ColorMean computes the mean color of a color list +func ColorMean(colorList [RaysPerPixel]Color) Color { + length := float64(len(colorList)) + meanColor := Color{} + for _, color := range colorList { + meanColor.r += color.r + meanColor.g += color.g + meanColor.b += color.b } - mean_color.r /= length - mean_color.g /= length - mean_color.b /= length - return mean_color + meanColor.r /= length + meanColor.g /= length + meanColor.b /= length + return meanColor } -func ColorMeanSquare(color_list [RAY_PER_PIXEL]Color) Color { - mean_color := ColorMean(color_list) - mean_color.r = math.Sqrt(mean_color.r) - mean_color.g = math.Sqrt(mean_color.g) - mean_color.b = math.Sqrt(mean_color.b) - return mean_color +// ColorMeanSquare is a more realistic color mean +func ColorMeanSquare(colorList [RaysPerPixel]Color) Color { + meanColor := ColorMean(colorList) + meanColor.r = math.Sqrt(meanColor.r) + meanColor.g = math.Sqrt(meanColor.g) + meanColor.b = math.Sqrt(meanColor.b) + return meanColor } diff --git a/image.go b/image.go index fe9b67f..df9039a 100644 --- a/image.go +++ b/image.go @@ -5,19 +5,22 @@ import ( "os" ) +// Pixel contains color between 0 and 255 type Pixel struct { r, g, b int } -type Frame [HEIGHT][WIDTH]Pixel +// Frame contains image data +type Frame [Height][Width]Pixel +// Save saves frame to PPM file func (frame Frame) Save(filename string) { f, err := os.Create(filename) if err != nil { panic(nil) } defer f.Close() - f.WriteString(fmt.Sprintf("P3\n%d %d\n255\n", WIDTH, HEIGHT)) + f.WriteString(fmt.Sprintf("P3\n%d %d\n255\n", Width, Height)) for _, row := range frame { for _, pixel := range row { f.WriteString(fmt.Sprintf("%d %d %d ", pixel.r, pixel.g, pixel.b)) diff --git a/main.go b/main.go index 316ebff..7211f8e 100644 --- a/main.go +++ b/main.go @@ -7,46 +7,69 @@ import ( "github.com/schollz/progressbar" ) -const HEIGHT = 100 -const WIDTH = 200 -const T_MIN = 0.001 -const T_MAX = 1000 -const RAY_PER_PIXEL = 100 -const MAX_DEPTH = 50 +const ( + // Height of frame + Height = 1000 + // Width of frame + Width = 2000 + // TMin is the minimal no zero time + TMin = 0.001 + // TMax limits time + TMax = 1000 + // RaysPerPixel for anti-aliasing + RaysPerPixel = 10 + // MaxDepth for ray boucing + MaxDepth = 50 + // FPS Frames per second for movies + FPS = 60 +) func main() { - LOWER_LEFT_CORNER := Vec3D{-2.0, -1.0, -1.0} - ORIGIN := Vec3D{0.0, 0.0, 0.0} - HORIZONTAL := Vec3D{4.0, 0.0, 0.0} - VERTICAL := Vec3D{0.0, 2.0, 0.0} - CAMERA := Camera{LOWER_LEFT_CORNER, ORIGIN, HORIZONTAL, VERTICAL} + // Scene + lowerLeftCorner := Vec3D{-2.0, -1.0, -1.0} + origin := Vec3D{0.0, 0.0, 0.0} + horizontal := Vec3D{4.0, 0.0, 0.0} + vertical := Vec3D{0.0, 2.0, 0.0} + camera := Camera{lowerLeftCorner, origin, horizontal, vertical} - MAT_RED := Lambertian{Color{0.7, 0.3, 0.3}} - MAT_GREEN := Lambertian{Color{0.8, 0.8, 0.0}} - METAL_GREY := Metal{Color{0.8, 0.8, 0.8}, 0.3} - METAL_BROWN := Metal{Color{0.8, 0.6, 0.2}, 1.0} + matRed := Lambertian{Color{0.7, 0.3, 0.3}} + matGreen := Lambertian{Color{0.8, 0.8, 0.0}} + metalGrey := Metal{Color{0.8, 0.8, 0.8}, 0.3} + // metalBrown := Metal{Color{0.8, 0.6, 0.2}, 1.0} + glass := Dielectric{1.5} WORLD := HitableList{ - Sphere{Vec3D{0.0, 0.0, -1.0}, 0.5, MAT_RED}, - Sphere{Vec3D{-1.0, 0.0, -1.0}, 0.5, METAL_GREY}, - Sphere{Vec3D{1.0, 0.0, -1.0}, 0.5, METAL_BROWN}, - Sphere{Vec3D{0.0, -100.5, -1.0}, 100.0, MAT_GREEN}, + Sphere{Vec3D{0.0, 0.0, -1.0}, 0.5, glass}, + Sphere{Vec3D{-1.0, 0.0, -1.0}, 0.5, metalGrey}, + Sphere{Vec3D{1.0, 0.0, -1.0}, 0.5, matRed}, + Sphere{Vec3D{0.0, -100.5, -1.0}, 100.0, matGreen}, } + + // Program + // start := AddVec3D(Origin, Vec3D{-1.0, 0.0, 0.0}) + // move := Vec3D{2.0, 0.0, 0.0} frame := Frame{} - bar := progressbar.New(HEIGHT) - for x := 0; x < HEIGHT; x++ { - for y := 0; y < WIDTH; y++ { - var color_list [RAY_PER_PIXEL]Color - for it := 0; it < RAY_PER_PIXEL; it++ { - u := (float64(y) + rand.Float64()) / float64(WIDTH) - v := (float64(x) + rand.Float64()) / float64(HEIGHT) - ray := CAMERA.GetRay(u, v) - color_list[it] = RayColor(ray, WORLD, 0) + bar := progressbar.New(Height) + bar.RenderBlank() + // for k := 0; k < FPS*DURATION; k++ { + // origin := AddVec3D(start, ScalarProduct(float64(k)/float64(FPS*DURATION), move)) + // camera.origin = origin + for x := 0; x < Height; x++ { + for y := 0; y < Width; y++ { + var colorList [RaysPerPixel]Color + for it := 0; it < RaysPerPixel; it++ { + u := (float64(y) + rand.Float64()) / float64(Width) + v := (float64(x) + rand.Float64()) / float64(Height) + ray := camera.GetRay(u, v) + colorList[it] = RayColor(ray, WORLD, 0) } - color := ColorMeanSquare(color_list) - frame[HEIGHT-1-x][y] = color.ToPixel() + color := ColorMeanSquare(colorList) + frame[Height-1-x][y] = color.ToPixel() } bar.Add(1) } frame.Save("img.ppm") + // frame.Save(fmt.Sprintf("frames/frame_%06d.ppm", k)) } + +// } diff --git a/ray.go b/ray.go index c874e31..a3f78f8 100644 --- a/ray.go +++ b/ray.go @@ -1,9 +1,11 @@ package main +// Ray contains a ray data type Ray struct { origin, direction Vec3D } +// PointAt computes ray position at a time func (ray Ray) PointAt(time float64) Vec3D { return AddVec3D(ray.origin, ScalarProduct(time, ray.direction)) } diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..ca40e87 --- /dev/null +++ b/utils.go @@ -0,0 +1,9 @@ +package main + +// FMin return mins of floats +func FMin(a float64, b float64) float64 { + if a >= b { + return a + } + return b +} -- cgit v1.3