Last active
April 5, 2024 09:55
-
-
Save jmiskovic/0f85da8132912c5ef0134449aa4f559c to your computer and use it in GitHub Desktop.
Example of 3rd person camera setup
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
local cam = require'cam' -- https://github.com/jmiskovic/lovr-cam | |
local player_pos = Vec3() | |
local player_vel = Vec3(0, 0, -0.01) | |
local 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()) | |
return view_pose:mul(view_proj:invert()):mul(clip_from_screen) | |
end | |
local function getRay(world_from_screen, distance) | |
local NEAR_PLANE = 0.01 | |
distance = distance or 1e3 | |
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)) | |
return ray | |
end | |
local function mouseOnGround(ray) | |
if ray.origin:distance(ray.target) < 1e-2 then | |
return vec3(0, 0, 0) | |
end | |
local ray_direction = (ray.target - ray.origin):normalize() | |
-- intersect the ray onto ground plane | |
local plane_direction = vec3(0, 1, 0) | |
local dot = ray_direction:dot(plane_direction) | |
if dot == 0 then | |
return vec3(0, 0, 0) | |
end | |
local ray_length = (-ray.origin):dot(plane_direction) / dot | |
local hit_spot = ray.origin + ray_direction * ray_length | |
return hit_spot | |
end | |
function lovr.draw(pass) | |
pass:text('Hold right\nmouse button\nto move\ntoward it', -2, 0.05, 0, 0.5, -math.pi/2, 1,0,0) | |
if lovr.system.isMouseDown(2) then | |
local world_from_screen = getWorldFromScreen(pass) | |
local ray = getRay(world_from_screen) | |
local spot = mouseOnGround(ray) | |
local dt = lovr.timer.getDelta() | |
player_vel:add((spot - player_pos) * dt) | |
player_pos:add(player_vel * dt) | |
player_vel:mul(0.95) | |
end | |
pass:setColor(0x101010) | |
pass:plane(0, 0, 0, 20, 20, -math.pi/2, 1,0,0) | |
pass:setColor(0x505050) | |
pass:plane(0, 0.01, 0, 20, 20, -math.pi/2, 1,0,0, 'line', 100, 100) | |
pass:setColor(0xD0A010) | |
pass:capsule(player_pos, player_pos + vec3(0, 0.4, 0), 0.3) | |
local player_azimuth = math.atan2(player_vel.z, player_vel.x) | |
pass:setColor(0x804000) | |
pass:cone(player_pos, 0.4, 0.5, -player_azimuth - math.pi/2, 0,1,0) | |
cam.center:lerp(player_pos, 0.1) | |
d_azimuth = player_azimuth - cam.azimuth + math.pi | |
-- add sign to angle, so that it's faster way around to reach the player's azimuth | |
d_azimuth = (d_azimuth + math.pi) % (2 * math.pi) - math.pi | |
cam.nudge(d_azimuth * 0.005) | |
end | |
cam.integrate() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment