Skip to content

pointing_mesh.kt

src/jvmMain/kotlin/afield/geometry/mesh/pointing_mesh.kt · 90 lines

package and imports — 54 lines, from line 1
@file:afield.runtime.completion.CompletionCategory("Graphics")

package afield.geometry.mesh

import afield.animation.keyframes.h
import afield.data.collections.get
import afield.data.collections.invoke
import afield.data.collections.s
import afield.data.collections.times
import afield.data.graph.main
import afield.document.graph.minusAssign
import afield.document.graph.named
import afield.document.graph.plusAssign
import afield.document.properties.compareTo
import afield.document.workspace.file
import afield.graphics.interaction.PickScene
import afield.graphics.interaction.Pointer
import afield.graphics.interaction.RayCamera
import afield.graphics.interaction.rayCamera
import afield.graphics.interaction.rayCameraFor
import afield.graphics.render.rangeTo
import afield.graphics.render.rect
import afield.graphics.shader.mesh
import afield.io.osc.main
import afield.lang.stacksl.h
import afield.math.autodiff.compareTo
import afield.math.autodiff.div
import afield.math.autodiff.minus
import afield.math.autodiff.plus
import afield.math.autodiff.times
import afield.math.control.main
import afield.math.linalg.invoke
import afield.math.linalg.remAssign
import afield.math.linalg.set
import afield.math.linalg.times
import afield.math.linalg.x
import afield.math.statistics.main
import afield.math.units.div
import afield.math.units.minus
import afield.math.units.plus
import afield.math.units.times
import afield.media.video.image
import afield.runtime.lifecycle.Once
import afield.simulation.agents.step
import afield.simulation.automata.main
import afield.simulation.automata.step
import afield.ui.output.h

import afield.audio.synth.*
import afield.graphics.interaction.Ray
import afield.graphics.visionos.VisionGeometryPreview
import afield.math.linalg.Matrix4f
import kotlin.math.abs
import kotlin.math.sqrt

Pointing a Ray at a mesh and asking what it hits.

One extension lives here, because the two halves of this question are in different packages. Rays are made in afield.graphics.interaction: Pointer is what a person points with, and the unprojection behind RayCamera turns the pixel or the pose it reports into a Ray. The structure that answers which triangle a ray meets is MeshBvh, which belongs with the meshes and takes an origin and a direction as two separate Vec3 arguments. The overload below unpacks a Ray into them.

Two things follow from that hop and are easier to state here than at the call site. A Ray normalises its direction when it is constructed, so the distance in the RayHit that comes back is in world units however the caller built the ray. And a Ray holds its origin and direction in double precision while Vec3 is float, so both narrow at this call before the intersection test widens them again and runs in double.

For ray to named part rather than ray to triangle, see PickScene.

Rays

fun MeshBvh.raycast

Convenience: MeshBvh.raycast down a Ray. Distances come back in world units.

fun MeshBvh.raycast(
    ray: Ray,
    maxDistance: Double = Double.MAX_VALUE,
    cullBackFaces: Boolean = false,
): RayHit? = raycast(ray.origin, ray.direction, maxDistance, cullBackFaces)

Cameras, running backwards