Documentation ¶
Overview ¶
Package mesh provides a triangle mesh implementation using a K-D tree
Index ¶
- Constants
- func IntersectTriangle(ray *ray.Ray, A, B, C *maths.Vec3) (bool, float64)
- type BoundingBox
- func (b *BoundingBox) AddPoint(point *maths.Vec3)
- func (b *BoundingBox) Inside(point *maths.Vec3) bool
- func (b *BoundingBox) Intersect(ray *ray.Ray) bool
- func (b *BoundingBox) IntersectAxis(ray *ray.Ray, axis int) bool
- func (b *BoundingBox) IntersectTriangle(A, B, C *maths.Vec3) bool
- func (b *BoundingBox) IntersectWall(axis int, median float64, ray *ray.Ray) bool
- func (b *BoundingBox) Split(axis int, median float64) (*BoundingBox, *BoundingBox)
- func (b *BoundingBox) String() string
- type KDtree
- type Mesh
- type Triangle
- type Vertex
Examples ¶
Constants ¶
const ( MaxTreeDepth = 10 TrianglesPerLeaf = 20 )
If the depth of the KDtree reaches MaxTreeDepth, the node becomes leaf whith node.Triangles the remaining triangles
Variables ¶
This section is empty.
Functions ¶
Types ¶
type BoundingBox ¶
type BoundingBox struct {
MaxVolume, MinVolume [3]float64
}
BoundingBox represents a cuboid which surrounds a part of the mesh. The points in the cuboid are those (x, y, z), for which is true: MinVolume[0] < x < MaxVolume[0] MinVolume[1] < y < MaxVolume[1] MinVolume[2] < z , MaxVolume[2]
func NewBoundingBox ¶
func NewBoundingBox() *BoundingBox
NewBoundingBox creates a bounding box with no volume (min > max)
func (*BoundingBox) AddPoint ¶
func (b *BoundingBox) AddPoint(point *maths.Vec3)
AddPoint expands the volume of the box, if the point isn't already in the box
Example ¶
box := NewBoundingBox() box.AddPoint(maths.NewVec3(-1, -1, -1)) box.AddPoint(maths.NewVec3(0, 5, -0.5)) box.AddPoint(maths.NewVec3(1, 0, 2)) fmt.Printf("%s\n", box)
Output: bbox[min: (-1, -1, -1), max: (1, 5, 2)]
func (*BoundingBox) Inside ¶
func (b *BoundingBox) Inside(point *maths.Vec3) bool
Inside checks if a point is inside the box
Example ¶
box := &BoundingBox{ MinVolume: [3]float64{-1, -1, -1}, MaxVolume: [3]float64{1, 1, 1}, } fmt.Printf("0, 0, 0: %v\n", box.Inside(maths.NewVec3(0, 0, 0))) fmt.Printf("0, 0, 2: %v\n", box.Inside(maths.NewVec3(0, 0, 2)))
Output: 0, 0, 0: true 0, 0, 2: false
func (*BoundingBox) Intersect ¶
func (b *BoundingBox) Intersect(ray *ray.Ray) bool
Intersect check if a ray intersects the bounding box
Example ¶
box := &BoundingBox{ MinVolume: [3]float64{-1, -1, -1}, MaxVolume: [3]float64{1, 1, 1}, } ray1 := &ray.Ray{ Start: *maths.NewVec3(0, 0, 0), Direction: *maths.NewVec3(1, 0, 0), } ray2 := &ray.Ray{ Start: *maths.NewVec3(-5, 0, 0.5), Direction: *maths.NewVec3(1, 0, 0), } ray3 := &ray.Ray{ Start: *maths.NewVec3(-5, 0, 0.5), Direction: *maths.NewVec3(-1, 0, 0), } ray4 := &ray.Ray{ Start: *maths.NewVec3(-5, 0, 0), Direction: *maths.NewVec3(1, 0, 5), } ray1.Init() ray2.Init() ray3.Init() ray4.Init() fmt.Printf("ray 1: %v\n", box.Intersect(ray1)) fmt.Printf("ray 2: %v\n", box.Intersect(ray2)) fmt.Printf("ray 3: %v\n", box.Intersect(ray3)) fmt.Printf("ray 4: %v\n", box.Intersect(ray4))
Output: ray 1: true ray 2: true ray 3: false ray 4: false
func (*BoundingBox) IntersectAxis ¶
func (b *BoundingBox) IntersectAxis(ray *ray.Ray, axis int) bool
IntersectAxis checks whether there's interaction between the ray and the box.
func (*BoundingBox) IntersectTriangle ¶
func (b *BoundingBox) IntersectTriangle(A, B, C *maths.Vec3) bool
IntersectTriangle checks if the bounding box intersects with a triangle 1) To have a vertex in the box 2) The edge of the triangle intersects with the box 3) The middle of the triangle to be inside the box, while the vertices aren't
func (*BoundingBox) IntersectWall ¶
IntersectWall checks if a ray intersects a wall inside the bounding box (the wall is defined by the axis and median, as with Split)
func (*BoundingBox) Split ¶
func (b *BoundingBox) Split(axis int, median float64) (*BoundingBox, *BoundingBox)
Split returns two new bounding boxes which are the result of spliting the original on the given axis and median
func (*BoundingBox) String ¶
func (b *BoundingBox) String() string
String returns the string representation of the boundingBox in the form of bbox[min: _, max: _]
type KDtree ¶
KDtree represents a node in a KD tree
func NewLeaf ¶
NewLeaf returns a new KDtree with triangles - the list of the given triangles and sets the axis to leaf
type Mesh ¶
type Mesh struct { Vertices []Vertex `json:"vertices"` Faces []Triangle `json:"faces"` BoundingBox *BoundingBox // contains filtered or unexported fields }
Mesh is a triangle mesh
func (*Mesh) GetBoundingBox ¶
func (m *Mesh) GetBoundingBox() *BoundingBox
GetBoundingBox returns the boundig box of the mesh, adding every vertex to the box
func (*Mesh) Init ¶
func (m *Mesh) Init()
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 (*Mesh) Intersect ¶
func (m *Mesh) Intersect(incoming *ray.Ray) *ray.Intersection
Intersect finds the intersection between a ray and the mesh and returns their intersection and the surface material. Returns nil and -1 if they don't intersect Has O(log(n)) amortised complexity.
Example ¶
meshData := []byte(`{ "vertices": [ { "normal": [0, 0, 1], "coordinates": [0, 0, 0], "uv": [0, 0] }, { "normal": [0, 0, 1], "coordinates": [1, 0, 0], "uv": [1, 0] }, { "normal": [0, 0, 1], "coordinates": [0, 1, 0], "uv": [0, 1] } ], "faces": [ { "vertices": [0, 1, 2], "material": 42 } ] }`) mesh := &Mesh{} err := json.Unmarshal(meshData, &mesh) if err != nil { fmt.Printf("Error reading json: %s\n", err) return } mesh.Init() testRay := &ray.Ray{ Start: *maths.NewVec3(0.15, 0.11, 1), Direction: *maths.NewVec3(0, 0, -1), } var ( intersection *ray.Intersection ) intersection = mesh.Intersect(testRay) if intersection == nil { fmt.Printf("no intersection\n") } else { fmt.Printf("intersection point: %s\n", intersection.Point) fmt.Printf("caused by ray: %s\n", intersection.Incoming) fmt.Printf("at a distance: %.3g\n", intersection.Distance) fmt.Printf("with surface coordinates: (%.3g, %.3g)\n", intersection.U, intersection.V) fmt.Printf("surface normal: %s\n", intersection.Normal) fmt.Printf("surface coordinate system: Ox: %s, Oy: %s\n", intersection.SurfaceOx, intersection.SurfaceOy) fmt.Printf("surface material: %d\n", intersection.Material) }
Output: intersection point: (0.15, 0.11, 0) caused by ray: (0.15, 0.11, 1) -> (0, 0, -1) at a distance: 1 with surface coordinates: (0.15, 0.11) surface normal: (0, 0, 1) surface coordinate system: Ox: (1, 0, 0), Oy: (0, 1, 0) surface material: 42
func (*Mesh) IntersectKD ¶
func (m *Mesh) IntersectKD(ray *ray.Ray, boundingBox *BoundingBox, node *KDtree, intersectionInfo *ray.Intersection) bool
IntersectKD returns whether there's an intersection with the ray. The the current node is leaf we check each of its triangles and divide the bounding box and check for each child
func (*Mesh) SlowIntersect ¶
func (m *Mesh) SlowIntersect(incoming *ray.Ray) *ray.Intersection
SlowIntersect finds the intersection between a ray and the mesh and returns their intersection and the surface material. Returns nil and -1 if they don't intersect Has O(n) complexity.