Skip to content

Instantly share code, notes, and snippets.

@weberc2
Created April 25, 2019 20:23
Show Gist options
  • Save weberc2/2aed4f8d3189d09067d56444836772da to your computer and use it in GitHub Desktop.
Save weberc2/2aed4f8d3189d09067d56444836772da to your computer and use it in GitHub Desktop.
Modified https://github.com/niofis/raybench/blob/master/gorb.go to pass by reference; improves performance considerably
package main
import (
"fmt"
"math"
"os"
)
const (
Width = 1280
Height = 720
Samples = 50
MaxDepth = 5
)
type v3 struct {
x float32
y float32
z float32
}
var zero = v3{x: 0, y: 0, z: 0}
func v3_add(dst, a, b *v3) {
dst.x = a.x + b.x
dst.y = a.y + b.y
dst.z = a.z + b.z
}
func v3_mul(dst, a, b *v3) {
dst.x = a.x * b.x
dst.y = a.y * b.y
dst.z = a.z * b.z
}
func v3_sub(dst, a, b *v3) {
dst.x = a.x - b.x
dst.y = a.y - b.y
dst.z = a.z - b.z
}
func v3_dot(a, b *v3) float32 {
return a.x*b.x + a.y*b.y + a.z*b.z
}
func v3_muls(dst, a *v3, s float32) {
dst.x = a.x * s
dst.y = a.y * s
dst.z = a.z * s
}
func v3_divs(dst, a *v3, s float32) {
dst.x = a.x / s
dst.y = a.y / s
dst.z = a.z / s
}
func v3_norm(v *v3) float32 {
return float32(math.Sqrt(float64(v.x*v.x + v.y*v.y + v.z*v.z)))
}
func v3_unit(dst *v3, v *v3) {
n := v3_norm(v)
dst.x = v.x / n
dst.y = v.y / n
dst.z = v.z / n
}
type ray struct {
origin v3
direction v3
}
func ray_point(dst *v3, r *ray, t float32) {
dst.x = r.origin.x + r.direction.x*t
dst.y = r.origin.y + r.direction.y*t
dst.z = r.origin.z + r.direction.z*t
}
type camera struct {
eye v3
lt v3
rt v3
lb v3
}
type sphere struct {
center v3
radius float32
color v3
is_light bool
}
type world struct {
camera camera
spheres []sphere
}
func world_new() world {
w := world{}
w.camera = camera{
eye: v3{x: 0, y: 4.5, z: 75},
lt: v3{x: -8, y: 9, z: 50},
rt: v3{x: 8, y: 9, z: 50},
lb: v3{x: -8, y: 0, z: 50}}
w.spheres = make([]sphere, 8)
w.spheres[0] = sphere{center: v3{x: 0, y: -10002, z: 0},
radius: 9999, color: v3{x: 1, y: 1, z: 1}, is_light: false}
w.spheres[1] = sphere{center: v3{x: -10012, y: 0, z: 0},
radius: 9999, color: v3{x: 1, y: 0, z: 0}, is_light: false}
w.spheres[2] = sphere{center: v3{x: 10012, y: 0, z: 0},
radius: 9999, color: v3{x: 0, y: 1, z: 0}, is_light: false}
w.spheres[3] = sphere{center: v3{x: 0, y: 0, z: -10012},
radius: 9999, color: v3{x: 1, y: 1, z: 1}, is_light: false}
w.spheres[4] = sphere{center: v3{x: 0, y: 10012, z: 0},
radius: 9999, color: v3{x: 1, y: 1, z: 1}, is_light: true}
w.spheres[5] = sphere{center: v3{x: -5, y: 0, z: 2},
radius: 2, color: v3{x: 1, y: 1, z: 0}, is_light: false}
w.spheres[6] = sphere{center: v3{x: 0, y: 5, z: -1},
radius: 4, color: v3{x: 1, y: 0, z: 0}, is_light: false}
w.spheres[7] = sphere{center: v3{x: 8, y: 5, z: -1},
radius: 2, color: v3{x: 0, y: 0, z: 1}, is_light: false}
return w
}
type hit struct {
distance float32
point v3
normal v3
}
var nohit = hit{distance: 1e16}
func sphit(sp *sphere, ray *ray, hit *hit) bool {
var oc v3
v3_sub(&oc, &ray.origin, &sp.center)
a := v3_dot(&ray.direction, &ray.direction)
b := v3_dot(&oc, &ray.direction)
c := v3_dot(&oc, &oc) - (sp.radius * sp.radius)
dis := b*b - a*c
if dis > 0.0 {
var e float32 = float32(math.Sqrt(float64(dis)))
var t float32 = (-b - e) / a
if t > 0.007 {
hit.distance = t
ray_point(&hit.point, ray, t)
v3_sub(&hit.normal, &hit.point, &sp.center)
v3_unit(&hit.normal, &hit.normal)
return true
}
t = (-b + e) / a
if t > 0.007 {
hit.distance = t
ray_point(&hit.point, ray, t)
v3_sub(&hit.normal, &hit.point, &sp.center)
v3_unit(&hit.normal, &hit.normal)
return true
}
return false
}
return false
}
func rnd_dome(normal v3) v3 {
var d float32
var p v3
d = -1
for d < 0 {
p.x = 2.0*randf() - 1.0
p.y = 2.0*randf() - 1.0
p.z = 2.0*randf() - 1.0
v3_unit(&p, &p)
d = v3_dot(&p, &normal)
}
return p
}
//https://codingforspeed.com/using-faster-psudo-random-generator-xorshift/
func xor128() uint32 {
var x uint32 = 123456789
var y uint32 = 362436069
var z uint32 = 521288629
var w uint32 = 88675123
var t uint32
t = x ^ (x << 11)
x = y
y = z
z = w
w = w ^ (w >> 19) ^ (t ^ (t >> 8))
return w
}
const UINT32_MAX = 4294967295
func randf() float32 {
return float32(xor128()) / float32(UINT32_MAX)
}
func trace(w world, r ray, depth int) v3 {
did_hit := false
h := nohit
color := zero
var sp sphere
for _, s := range w.spheres {
var lh hit
if sphit(&s, &r, &lh) {
sp = s
did_hit = true
color = s.color
h = lh
}
}
if did_hit && depth < MaxDepth {
if sp.is_light == false {
nray := ray{origin: h.point, direction: rnd_dome(h.normal)}
ncolor := trace(w, nray, depth+1)
at := v3_dot(&nray.direction, &h.normal)
var tmp v3
v3_muls(&tmp, &ncolor, at)
v3_mul(&color, &color, &tmp)
}
}
if did_hit == false || depth >= MaxDepth {
color = zero
}
return color
}
func writeppm(data [][]v3) {
ppm, _ := os.Create("gorb.ppm")
defer ppm.Close()
ppm.WriteString(fmt.Sprintf("P3\n%d %d\n255\n", Width, Height))
for _, row := range data {
for _, c := range row {
//fmt.Printf("%#v\n", c)
r := int(math.Floor(float64(c.x * 255.99)))
g := int(math.Floor(float64(c.y * 255.99)))
b := int(math.Floor(float64(c.z * 255.99)))
ppm.WriteString(fmt.Sprintf("%d %d %d ", r, g, b))
}
ppm.WriteString("\n")
}
ppm.Sync()
}
func main() {
data := [][]v3{}
world := world_new()
var tmp0, tmp1 v3
v3_sub(&tmp0, &world.camera.rt, &world.camera.lt)
v3_sub(&tmp1, &world.camera.lb, &world.camera.lt)
var vdu, vdv v3
v3_divs(&vdu, &tmp0, Width)
v3_divs(&vdv, &tmp0, Height)
data = make([][]v3, Height)
for y := 0; y < Height; y++ {
data[y] = make([]v3, Width)
for x := 0; x < Width; x++ {
color := zero
ray := ray{}
ray.origin = world.camera.eye
for i := 0; i < Samples; i++ {
var tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 v3
v3_muls(&tmp2, &vdu, float32(x)+randf())
v3_muls(&tmp3, &vdv, float32(y)+randf())
v3_add(&tmp4, &tmp2, &tmp3)
v3_add(&tmp5, &world.camera.lt, &tmp4)
v3_sub(&tmp6, &tmp5, &world.camera.eye)
v3_unit(&ray.direction, &tmp6)
//ray.direction = v3_unit(
// v3_sub(
// v3_add(
// world.camera.lt,
// v3_add(v3_muls(vdu, float32(x)+randf()),
// v3_muls(vdv, float32(y)+randf()))),
// world.camera.eye))
tmp7 = trace(world, ray, 0)
v3_add(&color, &color, &tmp7)
// color = v3_add(color, trace(world, ray, 0))
}
v3_divs(&color, &color, Samples)
data[y][x] = color
}
}
writeppm(data)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment