aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Lehoux <martin@lehoux.net>2020-04-05 22:46:01 -0700
committerMartin Lehoux <martin@lehoux.net>2020-04-05 22:46:01 -0700
commite93eee4bb96bd2d81e422dc9d453da6138fd6ba2 (patch)
tree0ef600be27a5bcde32d04283563c7b9fb8dd50d5
parent8730659596dbfdb9625c0fc413625b261f7d6d70 (diff)
misc - Doc
-rw-r--r--.gitignore2
-rw-r--r--camera.go6
-rw-r--r--color.go49
-rw-r--r--image.go7
-rw-r--r--main.go83
-rw-r--r--ray.go2
-rw-r--r--utils.go9
7 files changed, 103 insertions, 55 deletions
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
+}