Skip to content

Instantly share code, notes, and snippets.

@jmiskovic
Created October 2, 2023 18:09
Show Gist options
  • Save jmiskovic/18ab90ac29e4ff5bd117f7f84fd04fe8 to your computer and use it in GitHub Desktop.
Save jmiskovic/18ab90ac29e4ff5bd117f7f84fd04fe8 to your computer and use it in GitHub Desktop.
Example for dragging physics colliders with mouse in LÖVR
-- Creates a few hundred colliders which can be dragged around with right mouse button
-- Uses phywire.lua from https://github.com/jmiskovic/lovr-phywire
local phywire = require'phywire'
local world = lovr.physics.newWorld(0,0,0, false)
world:setLinearDamping(0.1)
world:setAngularDamping(0.1)
local mouse_collider = world:newSphereCollider(0,0,0, 0.001)
mouse_collider:setKinematic(true)
mouse_collider:getShapes()[1]:setSensor(true)
local is_orthographic = false
local world_from_screen = lovr.math.newMat4()
function getWorldFromScreen(pass)
local w, h = pass:getDimensions()
local clip_from_screen = mat4(-1, -1, 0):scale(2 / w, 2 / h, 1)
local view_pose = mat4(pass:getViewPose(1))
local view_proj = pass:getProjection(1, mat4())
is_orthographic = view_proj[16] == 1
return view_pose:mul(view_proj:invert()):mul(clip_from_screen)
end
local hovered = {}
local function randomQuaternion(q)
q = q or quat()
local u,v,w = math.random(), math.random(), math.random()
-- from "Uniform random rotations" in Graphic Gems III by K. Shoemake
q:set(math.sqrt(1-u)*math.sin(2*v*math.pi),
math.sqrt(1-u)*math.cos(2*v*math.pi),
math.sqrt(u)*math.sin(2*w*math.pi),
math.sqrt(u)*math.cos(2*w*math.pi),
true ) -- Raw components
return q
end
for i=1,500 do
local c = world:newBoxCollider(
lovr.math.randomNormal(50, 0),
lovr.math.randomNormal(50, 0),
lovr.math.randomNormal(50, 0),
2,
2,
2 + 3 * lovr.math.random())
c:setOrientation(randomQuaternion())
local c = world:newSphereCollider(
lovr.math.randomNormal(50, 0),
lovr.math.randomNormal(50, 0),
lovr.math.randomNormal(50, 0),
1,
2 + 3 * lovr.math.random())
c:setOrientation(randomQuaternion())
end
function getRay(distance)
local NEAR_PLANE = 0.01
distance = distance or 1e3
local z
local ray = {}
local x, y = lovr.system.getMousePosition()
ray.origin = vec3(world_from_screen:mul(x, y, NEAR_PLANE / NEAR_PLANE))
ray.target = vec3(world_from_screen:mul(x, y, NEAR_PLANE / distance))
if is_orthographic then
-- this breaks othographic projections if camera is not looking down the -Z :(
ray.origin.z = distance -- positive sign, so that ray crosses the XY plane
ray.target.z = -1000
end
return ray
end
function lovr.update(dt)
world:update(1/60)
mouse_collider:setPose(lovr.headset.getPose('left'))
end
function lovr.draw(pass)
world_from_screen:set(
getWorldFromScreen(pass))
phywire.draw(pass, world, phywire.render_shapes)
local ray = getRay()
world:raycast(ray.origin, ray.target,
function(shape, x, y, z)
local minx, maxx, miny, maxy, minz, maxz = shape:getAABB()
local cx, wx = (minx + maxx) / 2, maxx - minx
local cy, wy = (miny + maxy) / 2, maxy - miny
local cz, wz = (minz + maxz) / 2, maxz - minz
pass:box(cx, cy, cz, wx, wy, wz, 0, 0,0,0, 'line')
hovered.x, hovered.y, hovered.z = x, y, z
hovered.collider = shape:getCollider()
end)
end
function lovr.mousepressed(x, y, button)
if button == 2 and hovered.collider then
lovr.physics.newBallJoint(mouse_collider, hovered.collider, hovered.x, hovered.y, hovered.z)
end
end
function lovr.mousereleased(x, y, button)
for _, joint in ipairs(mouse_collider:getJoints()) do
joint:destroy()
end
hovered = {}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment