Пример #1
0
// Shade returns the emitted colour after intersecting the material
func (m *RefractiveMaterial) Shade(intersection *ray.Intersection, raytracer Raytracer) *hdrcolour.Colour {
	incoming := &intersection.Incoming.Direction
	normal := intersection.Normal
	ior := m.IOR.GetFac(intersection)
	colour := m.Colour.GetColour(intersection)
	refracted := &maths.Vec3{}
	startPoint := &maths.Vec3{}

	if maths.DotProduct(incoming, normal) < 0 {
		refracted = maths.Refract(incoming, normal, 1/ior)
	} else {
		refracted = maths.Refract(incoming, normal.Negative(), ior)
	}

	if refracted != nil {
		// regular refraction - push the starting point a tiny bit
		// through the surface
		startPoint = maths.MinusVectors(
			intersection.Point, normal.FaceForward(incoming).Scaled(maths.Epsilon),
		)
	} else {
		// total inner reflection
		refracted = incoming.Reflected(normal.FaceForward(incoming))
		// push the starting point a tiny bit away from the surface
		startPoint = maths.AddVectors(
			intersection.Point, normal.FaceForward(incoming).Scaled(maths.Epsilon),
		)
	}

	newRay := &ray.Ray{Depth: intersection.Incoming.Depth + 1}
	newRay.Start = *startPoint
	newRay.Direction = *refracted
	return hdrcolour.MultiplyColours(raytracer.Raytrace(newRay), colour)

}
Пример #2
0
// Shade returns the emitted colour after intersecting the material
func (m *LambertMaterial) Shade(intersection *ray.Intersection, raytracer Raytracer) *hdrcolour.Colour {
	randomRayDir := *raytracer.RandomGen().Vec3HemiCos(intersection.Normal)
	randomRayStart := *maths.AddVectors(intersection.Point, intersection.Normal.Scaled(maths.Epsilon))
	ray := &ray.Ray{Start: randomRayStart, Direction: randomRayDir, Depth: intersection.Incoming.Depth + 1}
	colour := raytracer.Raytrace(ray)
	colour.MultiplyBy(m.Colour.GetColour(intersection))
	return colour
}
Пример #3
0
// Shade returns the emitted colour after intersecting the material
func (m *ReflectiveMaterial) Shade(intersection *ray.Intersection, raytracer Raytracer) *hdrcolour.Colour {
	incoming := intersection.Incoming
	colour := m.Colour.GetColour(intersection)
	reflectedRay := &ray.Ray{Depth: incoming.Depth + 1}
	reflectedRay.Direction = *incoming.Direction.Reflected(intersection.Normal)
	reflectedRay.Start = *maths.AddVectors(intersection.Point, intersection.Normal.Scaled(maths.Epsilon))
	return hdrcolour.MultiplyColours(raytracer.Raytrace(reflectedRay), colour)
}
Пример #4
0
// Init  of Mesh sets the Triangle indices in the Faces array, calculates the bounding box
// and KD tree, sets the surfaceOx and Oy and Cross Products of the sides of each triangle
func (m *Mesh) Init() {
	allIndices := make([]int, len(m.Faces))
	for i := range allIndices {
		allIndices[i] = i
	}

	m.BoundingBox = m.GetBoundingBox()
	m.tree = m.newKDtree(m.BoundingBox, allIndices, 0)
	for i := range m.Faces {
		triangle := &m.Faces[i]

		A := &m.Vertices[triangle.Vertices[0]].Coordinates
		B := &m.Vertices[triangle.Vertices[1]].Coordinates
		C := &m.Vertices[triangle.Vertices[2]].Coordinates

		AB := maths.MinusVectors(B, A)
		AC := maths.MinusVectors(C, A)

		triangle.AB = AB
		triangle.AC = AC
		triangle.ABxAC = maths.CrossProduct(AB, AC)

		surfaceA := &m.Vertices[triangle.Vertices[0]].UV
		surfaceB := &m.Vertices[triangle.Vertices[1]].UV
		surfaceC := &m.Vertices[triangle.Vertices[2]].UV

		surfaceAB := maths.MinusVectors(surfaceB, surfaceA)
		surfaceAC := maths.MinusVectors(surfaceC, surfaceA)

		// Solve using Cramer:
		// |surfaceAB.X * px + surfaceAX.X *qx + 1 = 0
		// |surfaceAB.Y * px + surfaceAX.Y *qx = 0
		// and
		// surfaceAB.X * py + surfaceAX.X *qy = 0
		// surfaceAB.X * py + surfaceAX.X *qy + 1 = 0

		px, qx := maths.SolveEquation(surfaceAB, surfaceAC, maths.NewVec3(1, 0, 0))
		py, qy := maths.SolveEquation(surfaceAB, surfaceAC, maths.NewVec3(0, 1, 0))

		triangle.surfaceOx = maths.AddVectors(AB.Scaled(px), AC.Scaled(qx))
		triangle.surfaceOy = maths.AddVectors(AB.Scaled(py), AC.Scaled(qy))
	}
}
Пример #5
0
// IntersectTriangle returns whether there's an intersection between the ray and the triangle,
// using barycentric coordinates and takes the point only if it's closer to the
// previously found intersection and the point is within the bounding box
func (m *Mesh) intersectTriangle(ray *ray.Ray, triangle *Triangle, intersection *ray.Intersection, boundingBox *BoundingBox) bool {
	// lambda2 * AB + lambda3 * AC - intersectDist*rayDir = distToA
	// If the triangle is ABC, this gives you A
	A := &m.Vertices[triangle.Vertices[0]].Coordinates
	distToA := maths.MinusVectors(&ray.Start, A)
	rayDir := ray.Direction
	ABxAC := triangle.ABxAC
	// We will find the barycentric coordinates using Cramer's formula, so we'll need the determinant
	// det is (AB^AC)*dir of the ray, but we're gonna use 1/det, so we find the recerse:
	det := -maths.DotProduct(ABxAC, &rayDir)
	if math.Abs(det) < maths.Epsilon {
		return false
	}
	reverseDet := 1 / det
	intersectDist := maths.DotProduct(ABxAC, distToA) * reverseDet
	if intersectDist < 0 || intersectDist > intersection.Distance {
		return false
	}
	// lambda2 = (dist^dir)*AC / det
	// lambda3 = -(dist^dir)*AB / det
	lambda2 := maths.MixedProduct(distToA, &rayDir, triangle.AC) * reverseDet
	lambda3 := -maths.MixedProduct(distToA, &rayDir, triangle.AB) * reverseDet
	if lambda2 < 0 || lambda2 > 1 || lambda3 < 0 || lambda3 > 1 || lambda2+lambda3 > 1 {
		return false
	}

	ip := maths.AddVectors(&ray.Start, (&rayDir).Scaled(intersectDist))

	// If we aren't inside the bounding box, there could be a closer intersection
	// within the bounding box
	if boundingBox != nil && !boundingBox.Inside(ip) {
		return false
	}
	intersection.Point = ip
	intersection.Distance = intersectDist
	if triangle.Normal != nil {
		intersection.Normal = triangle.Normal
	} else {
		// We solve intersection.normal = Anormal + AB normal * lambda2 + ACnormal * lambda 3
		Anormal := &m.Vertices[triangle.Vertices[0]].Normal
		Bnormal := &m.Vertices[triangle.Vertices[1]].Normal
		Cnormal := &m.Vertices[triangle.Vertices[2]].Normal
		ABxlambda2 := maths.MinusVectors(Bnormal, Anormal).Scaled(lambda2)
		ACxlambda3 := maths.MinusVectors(Cnormal, Anormal).Scaled(lambda3)
		intersection.Normal = maths.AddVectors(Anormal, maths.AddVectors(ABxlambda2, ACxlambda3))
	}
	uvA := &m.Vertices[triangle.Vertices[0]].UV
	uvB := &m.Vertices[triangle.Vertices[1]].UV
	uvC := &m.Vertices[triangle.Vertices[2]].UV

	// We solve intersection.uv = uvA + uvAB * lambda2 + uvAC * lambda 3
	uvABxlambda2 := maths.MinusVectors(uvB, uvA).Scaled(lambda2)
	uvACxlambda3 := maths.MinusVectors(uvC, uvA).Scaled(lambda3)
	uv := maths.AddVectors(uvA, maths.AddVectors(uvABxlambda2, uvACxlambda3))

	intersection.U = uv.X
	intersection.V = uv.Y

	intersection.SurfaceOx = triangle.surfaceOx
	intersection.SurfaceOy = triangle.surfaceOy

	intersection.Incoming = ray
	intersection.Material = triangle.Material
	return true
}