func (p Box) Intersect(ray, origin glm.Vec3) (b bool, raylen float64, normal glm.Vec3) { min := p.Pos max := p.Pos.Add(glm.NewVec3(p.Rad, p.Rad, p.Rad)) raylen_near := -100000.0 raylen_far := 100000.0 // Assume parallel intersections are not a thing. for i, raydir := range ray.Elem { if math.Abs(raydir) < Epsilon && (origin.Elem[i] < min.Elem[i] || origin.Elem[i] > max.Elem[i]) { return false, 0, glm.Vec3{} } t1 := (min.Elem[i] - origin.Elem[i]) / raydir t2 := (max.Elem[i] - origin.Elem[i]) / raydir flip := false if t1 > t2 { t := t1 t1 = t2 t2 = t flip = true } if t1 > raylen_near { raylen_near = t1 normal = *glm.NewVec3(0.0, 0.0, 0.0) if flip { normal.Elem[i] = p.Rad } else { normal.Elem[i] = -p.Rad } } raylen_far = math.Min(raylen_far, t2) if raylen_far < raylen_near || raylen_far < Epsilon { return false, 0, normal } } return true, raylen_near, normal }
func NewMesh(verts [][3]float64, faces [][3]int, mat Material) *Mesh { vec_verts := make([]glm.Vec3, len(verts)) m := &Mesh{} min := [3]float64{verts[0][0], verts[0][1], verts[0][2]} max := [3]float64{verts[0][0], verts[0][1], verts[0][2]} for i, v := range verts { for j := 0; j < 3; j++ { min[j] = math.Min(min[j], v[j]) max[j] = math.Max(max[j], v[j]) } vec_verts[i] = *glm.NewVec3(v[0], v[1], v[2]) } m.Verts = vec_verts m.Faces = faces // Generate plane normals for all faces. m.Normals = make([]glm.Vec3, len(faces)) for i, f := range faces { v1 := vec_verts[f[0]].Subtract(&vec_verts[f[1]]) v2 := vec_verts[f[0]].Subtract(&vec_verts[f[2]]) m.Normals[i] = *v1.Cross(v2) } m.Bound.Pos = *glm.NewVec3(min[0], min[1], min[2]) diff := glm.NewVec3(max[0], max[1], max[2]).Subtract(&m.Bound.Pos) m.Bound.Rad = math.Max(math.Max(diff.Elem[0], diff.Elem[1]), diff.Elem[2]) m.Bound.Mat = mat m.Mat = mat return m }
func drop_axis(v glm.Vec3, axis int) (ret glm.Vec3) { switch axis { case 0: ret = *glm.NewVec3(v.Elem[1], v.Elem[2], 0.0) case 1: ret = *glm.NewVec3(v.Elem[0], v.Elem[2], 0.0) case 2: ret = *glm.NewVec3(v.Elem[0], v.Elem[1], 0.0) } return }
func trace(root []scene.Primitive, ambient glm.Vec3, ray, origin *glm.Vec3, lights []scene.Light, depth int) (*glm.Vec3, bool) { if hit, node, raylen, normal := intersectNodes(root, ray, origin); hit { // ambient silhouette mat := root[node].GetMaterial() colour := glm.NewVec3(ambient.Elem[0]*mat.Ambient.Elem[0], ambient.Elem[1]*mat.Ambient.Elem[1], ambient.Elem[2]*mat.Ambient.Elem[2]) // setup for casting secondary (shadow) rays. intersection := origin.Add(ray.Scale(raylen)) diffuse := glm.Vec3{} specular := glm.Vec3{} ray.Normalize() normal.Normalize() // cast shadow ray. for _, light := range lights { shadow_ray := light.Pos.Subtract(intersection) if hit, _, _, _ = intersectNodes(root, shadow_ray, intersection); !hit { shadow_ray.Normalize() // add diffuse/specular components. diffuse_coef := normal.Dot(shadow_ray) if diffuse_coef > 0.00001 { fmt.Println(diffuse_coef) diffuse_tmp := mat.Diffuse.Scale(diffuse_coef) diffuse.Iadd(glm.NewVec3(diffuse_tmp.Elem[0]*light.Colour.Elem[0], diffuse_tmp.Elem[1]*light.Colour.Elem[1], diffuse_tmp.Elem[2]*light.Colour.Elem[2])) } reflected_shadow_ray := shadow_ray.Subtract(normal.Scale(2 * diffuse_coef)) specular_coef := math.Abs(math.Pow(reflected_shadow_ray.Dot(ray), mat.Shininess)) if specular_coef > 0.00001 { specular_tmp := mat.Specular.Scale(specular_coef) specular.Iadd(glm.NewVec3(specular_tmp.Elem[0]*light.Colour.Elem[0], specular_tmp.Elem[1]*light.Colour.Elem[1], specular_tmp.Elem[2]*light.Colour.Elem[2])) } } } colour.Iadd(&diffuse).Iadd(&specular) // cast reflectance ray. if REFLECTIONS { reflected := ray.Subtract(normal.Scale(2 * normal.Dot(ray))) if depth < MAX_DEPTH { if reflected_color, hit := trace(root, ambient, reflected, intersection, lights, depth+1); hit { colour.Iscale(1 - mat.Mirror).Iadd(reflected_color.Scale(mat.Mirror)) } } } return colour, true } return &glm.Vec3{}, false }
func CreateScene() (scene *Scene, err error) { scene = &Scene{} scene.Lights = []Light{ Light{*glm.NewVec3(-100.0, 150.0, 400.0), *glm.NewVec3(0.7, 0.7, 0.7), *glm.NewVec3(1.0, 0.0, 0.0)}, Light{*glm.NewVec3(400.0, 100.0, 150.0), *glm.NewVec3(0.7, 0.0, 0.7), *glm.NewVec3(1.0, 0.0, 0.0)}, } mat1 := Material{ *glm.NewVec3(0.7, 1.0, 0.7), *glm.NewVec3(0.7, 1.0, 0.7), *glm.NewVec3(0.5, 0.7, 0.5), 25.0, 0.3, } mat2 := Material{ *glm.NewVec3(0.5, 0.5, 0.5), *glm.NewVec3(0.5, 0.5, 0.5), *glm.NewVec3(0.5, 0.7, 0.5), 25.0, 0.3, } mat3 := Material{ *glm.NewVec3(1.0, 0.6, 0.1), *glm.NewVec3(1.0, 0.6, 0.1), *glm.NewVec3(0.5, 0.7, 0.5), 25.0, 0.3, } mat4 := Material{ *glm.NewVec3(0.7, 0.6, 1.0), *glm.NewVec3(0.7, 0.6, 1.0), *glm.NewVec3(0.5, 0.4, 0.8), 25.0, 0.3, } scene.Primitives = make([]Primitive, 7) scene.Primitives[0] = Sphere{*glm.NewVec3(0.0, 0.0, -400.0), 100.0, mat1} scene.Primitives[1] = Sphere{*glm.NewVec3(200.0, 50.0, -100.0), 150.0, mat1} scene.Primitives[2] = Sphere{*glm.NewVec3(0.0, -1200.0, -500.0), 1000.0, mat2} scene.Primitives[3] = Sphere{*glm.NewVec3(-100.0, 25.0, -300.0), 50.0, mat3} scene.Primitives[4] = Sphere{*glm.NewVec3(0.0, 100.0, -250.0), 25.0, mat1} scene.Primitives[5] = Box{*glm.NewVec3(-200.0, -125.0, 0.0), 100, mat4} steldodec.Mat = mat3 scene.Primitives[6] = *steldodec scene.Eye = *glm.NewVec3(0.0, 0.0, 800.0) scene.View = *glm.NewVec3(0.0, 0.0, -1.0) scene.Up = *glm.NewVec3(0.0, 1.0, 0.0) scene.Ambient = *glm.NewVec3(0.3, 0.3, 0.3) scene.FOV = 50 scene.Width = 512 scene.Height = 512 fmt.Println("Here we go!") return scene, nil }
func ray_epsilon_check(raylen float64, ray glm.Vec3, line glm.Vec3) (b bool, retlen float64, normal glm.Vec3) { if raylen > Epsilon { return true, raylen, *ray.Scale(raylen).Subtract(&line) } return false, 0, *glm.NewVec3(0, 0, 0) }
func background() *glm.Vec3 { return glm.NewVec3(0.1, 0.1, 0.1) }