Created
October 2, 2023 18:09
-
-
Save jmiskovic/18ab90ac29e4ff5bd117f7f84fd04fe8 to your computer and use it in GitHub Desktop.
Example for dragging physics colliders with mouse in LÖVR
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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