Example #1
0
func main() {
	plane := geometry.YAxisAlignedPlane{0}
	cube1 := geometry.MakeCuboid(geometry.MakeVector(-2, 0, 0), geometry.MakeVector(0.5, 0.5, 0.5))
	sphere := geometry.MakeSphere(geometry.MakeVector(2, 0, 0), 2.0)
	sphere2 := geometry.MakeSphere(geometry.MakeVector(-2, 2, 0), 0.5)
	//cube2 := geometry.MakeCuboid(geometry.MakeVector(1,0,0),geometry.MakeVector(0.5, 0.5, 0.5))
	n := geometry.MakeTreeNode(sphere2, cube1)
	scene := geometry.MakeTreeNode(plane, n)
	scene = geometry.MakeTreeNode(sphere, scene)
	//cube := geometry.MakeCuboid(geometry.MakeVector(-2,0,0),geometry.MakeVector(0.5, 0.5, 0.5))
	//scene := geometry.MakeTreeNode(sphere, cube)

	img := render.RenderImage(1366, 768, scene)
	f, err := os.Create("out.png")
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
	png.Encode(f, img)
}
func MakeViewRay(u, v, k float64) geometry.Ray {
	//var d1 float64 = math.Sqrt(1/(2+4*sinθ2))
	// = math.Sqrt(5/14)
	const d1 float64 = 0.5976143046671968
	//var d2 float64 = -2*sinθ*d1
	const d2 float64 = -2 * sinθ * d1
	// = -math.Sqrt(2/7)
	d := geometry.MakeVector(d1, d2, d1)

	bu := geometry.MakeVector(1.0/math.Sqrt(2), 0, -1.0/math.Sqrt(2))
	var bv1 float64 = math.Sqrt(1.0 / 7.0) //math.Sqrt(1/(2 + 1/sinθ2))
	var bv2 float64 = math.Sqrt(5.0 / 7.0) //bv1/sinθ
	bv := geometry.MakeVector(bv1, bv2, bv1)

	//fmt.Println(bu.Dot(d), bv.Dot(d), bu.Dot(bv))

	o := (bu.Mul(u)).Add(bv.Mul(v)).Add(d.Mul(k))

	return geometry.MakeRay(o, d)
}
func castRay(r geometry.Ray, scene geometry.Object, recursionLimit uint) (bool, geometry.Vector) {
	if scene.Collides(r) {
		depth, object, objectColour := scene.Collision(r)
		// if depth < 0 {
		// 	return false, geometry.MakeVector(0,0,0)
		// }
		// if recursionLimit == 4 {
		// 	fmt.Println("Reflected")
		// }
		return true, calculateColour(r, depth, scene, object, objectColour, recursionLimit)
	}
	return false, geometry.MakeVector(0, 0, 0)
}
func RenderImage(width, height uint32, scene geometry.Object) *image.RGBA {
	distance := -10.0
	const scale float64 = 7.0
	const subsamples int = 8

	img := image.NewRGBA(image.Rect(0, 0, int(width), int(height)))
	b := img.Bounds()
	for y := b.Min.Y; y <= b.Max.Y; y++ {
		for x := b.Min.X; x <= b.Max.X; x++ {
			x_range := b.Max.X - b.Min.X
			y_range := b.Max.Y - b.Min.Y

			fxr := float64(x_range)
			fyr := float64(y_range)

			colour := geometry.MakeVector(0, 0, 0)
			for i := 0; i < subsamples; i++ {
				xjitter := 0.5*rand.Float64() - 0.25
				yjitter := 0.5*rand.Float64() - 0.25

				if i == 0 { //Always cast a ray through the middle
					xjitter = 0
					yjitter = 0
				}
				u := (scale / fxr) * (fxr / fyr) * (float64(x-x_range/2) + xjitter)
				v := -(scale / fyr) * (float64(y-y_range/2) + yjitter)

				r := MakeViewRay(u, v, distance)
				//r := MakeViewRay(math.Abs(distance)*u, math.Abs(distance)*v, distance)

				collision, c := castRay(r, scene, 5)
				if collision {
					colour = colour.Add(c)
				}
			}
			colour = colour.Apply(func(x float64) float64 {
				return math.Abs(x) / float64(subsamples)
			})
			//if colour.y != 0{
			//fmt.Println(colour.y)
			//}
			c := colour.ToArray()
			img.Set(x, y, color.RGBA{uint8(c[0]), uint8(c[1]), uint8(c[2]), 255})
		}
	}
	return img
}