Raycasting
Raycasting shoots a ray through the scene and returns what it hits. Use it for object picking (click-to-select), collision queries, and spatial analysis.
local ray = pl.raycastHit Result
Section titled “Hit Result”All ray functions return a hit table (or nil if nothing was hit):
{ node = Node, -- the node that was hit point = vec3, -- world-space intersection point normal = vec3, -- surface normal at the hit point distance = number, -- distance from ray origin to hit}from_screen
Section titled “from_screen”Cast a ray from a camera through a screen pixel — ideal for mouse/touch picking.
local cam = scene:get_active_camera()local hit = ray.from_screen(cam, screen_x, screen_y)
if hit then print("Clicked on: " .. hit.node.name) print("Distance: " .. hit.distance)endscreen_x and screen_y are pixel coordinates relative to the viewport.
Cast a ray from a point in a direction in world space.
local origin = { x = 0, y = 5, z = 0 }local direction = { x = 0, y = -1, z = 0 } -- straight down
local hit = ray.cast(origin, direction, 100) -- max distance = 100The max_distance parameter is optional. If omitted, the ray extends infinitely.
cast_node
Section titled “cast_node”Cast against a specific node (and its children) only — useful for targeted hit testing.
local character = scene:find_node("Character")local hit = ray.cast_node(origin, direction, character)
if hit then print("Hit " .. hit.node.name .. " at " .. hit.distance .. "m")endcast_all
Section titled “cast_all”Return all intersections along a ray, sorted by distance (nearest first).
local hits = ray.cast_all(origin, direction, 200)
for i, hit in ipairs(hits) do print(string.format( "#%d: %s at %.2fm", i, hit.node.name, hit.distance ))endExample: Click-to-Select
Section titled “Example: Click-to-Select”local ray = pl.raycastlocal cam = scene:get_active_camera()
-- Highlight the clicked objectlocal hit = ray.from_screen(cam, mouse_x, mouse_y)if hit then -- Reset previous selection if selected then selected:get_mesh():get_material().emissive = { r=0, g=0, b=0 } end
-- Highlight new selection selected = hit.node local mat = selected:get_mesh():get_material() mat.emissive = { r = 0.3, g = 0.5, b = 1.0 } mat.emissive_strength = 0.5
print("Selected: " .. selected.name)endExample: Ground Placement
Section titled “Example: Ground Placement”-- Cast downward to find the ground position below a pointlocal function snap_to_ground(node) local pos = node.world_position local hit = ray.cast( { x = pos.x, y = pos.y + 10, z = pos.z }, -- start above { x = 0, y = -1, z = 0 }, -- cast down 50 ) if hit then node.position = hit.point endend