You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Mesh queries answer "exactly where on this model did a ray or point land?" at
triangle precision. Where physics raycasts hit collision shapes, mesh queries
hit the rendered geometry itself, returning the triangle, barycentric weights,
interpolated UVs, and surface point. That is what you need to place a bullet hole
on a wall, let a player click a specific panel of a control console, or sample
which texel of a paintable surface was struck. Queries against a skinned
MeshInstance3D use the live skeleton pose, so hits track an animated character.
Use Cases
Click-to-place / click-to-select on a 3D model: build a pointer ray with ctx.run.Nodes().camera_screen_ray_3d(camera_id, pixel, viewport_size) and hit the mesh via instance_surface_on_global_ray.
Stick a decal or bullet hole precisely on a surface: use the returned hit point (and paint_uv) to spawn the decal exactly where the ray landed.
Damage zones / paintable surfaces: read the hit's paint_uv or instance_material_regions to know which material or texel was struck.
Animated hitboxes: raycast a posed skeletal character so hits follow the current animation instead of the rest pose.
Reconstruct a stored hit under the current pose: save triangle_index + barycentric, later resolve the authoritative point with instance_surface_global_point.
Tool / procedural sampling: query raw mesh data in local space with data_surface_on_local_ray or data_surface_at_local_point.
Hit Data and Rays
MeshSurfaceHit3D includes triangle_index, (a, b, c)barycentric
weights, interpolated uv0, and paint_uv. paint_uv reads glTF UV1 and
falls back to UV0 for runtime meshes, built-ins, and PMESH assets.
MeshInstance3D queries linked to Skeleton3D use current bone poses. Hit
triangle IDs and UVs keep original mesh topology. Posed queries cap at
1,000,000 vertices; larger posed meshes return no hit.
Resolve a saved hit without a second ray via
instance_surface_global_point(node_id, triangle_index, barycentric).
It uses the same query triangle numbering and live skeleton pose. It rejects
non-finite or non-unit barycentric values, non-MeshInstance3D nodes, and
meshes over 1,000,000 vertices.
Build pointer rays with
ctx.run.Nodes().camera_screen_ray_3d(camera_id, pixel, viewport_size).
Pixels use a top-left origin. The result supports perspective, orthographic,
and off-axis frustum cameras and passes directly to
instance_surface_on_global_ray.
Context
Script context path: ctx.run
Module access: ctx.run.MeshQuery()
Lifecycle examples stay inside lifecycle! because script hooks get API from the macro expansion.
Practical Example
Click-to-inspect: cast a ray from the camera through the mouse pixel, hit the
rendered mesh, and read back the exact surface point where the player clicked.
#[State]structPickState{#[default = NodeID::nil()]pubcamera:NodeID,#[default = NodeID::nil()]pubmesh:NodeID,}lifecycle!({fn on_update(&self, ctx:&mutScriptContext<'_,API>){let camera = with_state!(ctx.run,PickState, ctx.id, |s| s.camera).unwrap_or_default();let target = with_state!(ctx.run,PickState, ctx.id, |s| s.mesh).unwrap_or_default();let pixel = mouse_position!(ctx.ipt);let viewport = viewport_size!(ctx.ipt);ifletSome(ray) = ctx.run.Nodes().camera_screen_ray_3d(camera, pixel, viewport){let hit = ctx.run.MeshQuery().instance_surface_on_global_ray(
target,
ray.origin,
ray.direction,
ray.max_distance,);ifletSome(hit) = hit {// hit.triangle_index / hit.paint_uv identify what was struck;// resolve the world point to place a decal there.let _ = ctx.run.MeshQuery().instance_surface_global_point(
target,
hit.triangle_index,
hit.barycentric,);}}}});
Use instance_surface_at_global_point to instance surface at global point; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Returns None when instance_surface_at_global_point cannot produce a value for the supplied target or inputs.
Use instance_surface_on_global_ray to instance surface on global ray; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Returns None when instance_surface_on_global_ray cannot produce a value for the supplied target or inputs.
Use instance_surfaces_on_global_rays to instance surfaces on global rays; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Returns None when instance_surfaces_on_global_rays cannot produce a value for the supplied target or inputs.
Use instance_material_regions to instance material regions; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Returns an empty vector when instance_material_regions finds no values; callers must treat zero results as normal.
Use data_surface_at_local_point to data surface at local point; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Returns None when data_surface_at_local_point cannot produce a value for the supplied target or inputs.
Use data_surface_on_local_ray to data surface on local ray; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Returns None when data_surface_on_local_ray cannot produce a value for the supplied target or inputs.
Use mesh_instance_surface_at_global_point_3d to mesh instance surface at global point 3d; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Uses the backing mesh_instance_surface_at_global_point_3d return and failure behavior unchanged; the wrapper adds no coercion or fallback.
Use mesh_instance_surface_on_global_ray_3d to mesh instance surface on global ray 3d; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Uses the backing mesh_instance_surface_on_global_ray_3d return and failure behavior unchanged; the wrapper adds no coercion or fallback.
Use mesh_instance_surfaces_on_global_rays_3d to mesh instance surfaces on global rays 3d; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Uses the backing mesh_instance_surfaces_on_global_rays_3d return and failure behavior unchanged; the wrapper adds no coercion or fallback.
Use mesh_instance_material_regions_3d to mesh instance material regions 3d; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Uses the backing mesh_instance_material_regions_3d return and failure behavior unchanged; the wrapper adds no coercion or fallback.
Use mesh_data_surface_at_local_point_3d to mesh data surface at local point 3d; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Uses the backing mesh_data_surface_at_local_point_3d return and failure behavior unchanged; the wrapper adds no coercion or fallback.
Use mesh_data_surface_on_local_ray_3d to mesh data surface on local ray 3d; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Uses the backing mesh_data_surface_on_local_ray_3d return and failure behavior unchanged; the wrapper adds no coercion or fallback.
Use mesh_data_surface_regions_3d to mesh data surface regions 3d; choose instance/global or mesh-data/local form based on which coordinate space owns the input.
Fails when / edge behavior
Uses the backing mesh_data_surface_regions_3d return and failure behavior unchanged; the wrapper adds no coercion or fallback.