Bläddra i källkod

A space-stretch locomotion example

This locomotion method is used by Tilt Brush and other similar editors.
The scene can be scaled, rotated and positioned by grabbing with both
controllers and moving them around in intuitive way.
Josip Miskovic 3 år sedan
förälder
incheckning
bab2792544
2 ändrade filer med 88 tillägg och 0 borttagningar
  1. 87 0
      examples/Locomotion/Space_Stretch/main.lua
  2. 1 0
      examples/init.lua

+ 87 - 0
examples/Locomotion/Space_Stretch/main.lua

@@ -0,0 +1,87 @@
+-- left grip + right grip: grab VR space and move / stretch / rotate
+-- left grip + right grip + right trigger: reset the view
+
+local motion = {
+  pose = lovr.math.newMat4(0,0,0, 1,1,1, 0, 0,1,0),
+  left_anchor_vr = lovr.math.newVec3(),
+  right_anchor_vr = lovr.math.newVec3(),
+}
+
+local palette = {0x0d2b45, 0x203c56, 0x544e68, 0x8d697a, 0xd08159, 0xffaa5e, 0xffd4a3, 0xffecd6}
+
+
+function lovr.update(dt)
+  local left_vr  = vec3(motion.pose:mul(lovr.headset.getPosition('hand/left')))
+  local right_vr = vec3(motion.pose:mul(lovr.headset.getPosition('hand/right')))
+  if lovr.headset.wasPressed('hand/left', 'grip') then
+    motion.left_anchor_vr:set(left_vr)
+  end
+  if lovr.headset.wasPressed('hand/right', 'grip') then
+    motion.right_anchor_vr:set(right_vr)
+  end
+  if lovr.headset.isDown('hand/left',  'grip') and
+     lovr.headset.isDown('hand/right', 'grip') then
+    local x, y, z, scale, _, _, angle, ax, ay, az = motion.pose:unpack()
+    -- Scale: get the ratio of distances between anchors over current controllers distance
+    local offset_scale = motion.left_anchor_vr:distance(motion.right_anchor_vr) / left_vr:distance(right_vr)
+    offset_scale = 1 + (offset_scale - 1)
+    scale = scale * offset_scale
+    -- the change of scale must also affect the viewpoint location
+    x, y, z = x * offset_scale, y * offset_scale, z * offset_scale
+    -- Position: the mid-point of anchors is compared to midpoint of current controllers position
+    local midpoint_anchor     = vec3(motion.left_anchor_vr):lerp(motion.right_anchor_vr, 0.5)
+    local midpoint_controller = vec3(left_vr):lerp(right_vr, 0.5)
+    local offset_position = vec3(midpoint_anchor):sub(midpoint_controller)
+    x, y, z = x + offset_position.x, y + offset_position.y, z + offset_position.z
+    motion.pose:set(x, y, z, scale, scale, scale, angle, ax, ay, az)  -- apply transition and scaling
+    -- Rotation: get angle between current controllers and anchors in XZ
+    local l_to_r_anchor = vec3(motion.right_anchor_vr):sub(motion.left_anchor_vr)
+    local l_to_r_controller = vec3(right_vr):sub(left_vr)
+    local sign = 1
+    if vec3(l_to_r_controller):cross(vec3(l_to_r_anchor)):dot(vec3(0, 1, 0)) < 0 then
+      sign = -1
+    end
+    l_to_r_anchor = l_to_r_anchor.xz:normalize()
+    l_to_r_controller = l_to_r_controller.xz:normalize()
+    local cos_angle = l_to_r_controller:dot(l_to_r_anchor)
+    cos_angle = math.max(-1, math.min(1, cos_angle))
+    local offset_rotation = math.acos(cos_angle) * sign
+    motion.pose:rotate(offset_rotation, 0,1,0) -- apply rotation
+    -- pose & anchor reset
+    if lovr.headset.isDown('hand/right', 'trigger') then
+      motion.pose:set()
+      motion.left_anchor_vr:set(left_vr)
+      motion.right_anchor_vr:set(right_vr)
+    end
+  end
+end
+
+
+function lovr.draw()
+  lovr.graphics.setBackgroundColor(palette[1])
+  lovr.graphics.transform(mat4(motion.pose):invert())
+  -- Render hands
+  for _, hand in ipairs(lovr.headset.getHands()) do
+    -- Whenever pose of hand or head is used, need to account for VR movement
+    local poseRW = mat4(lovr.headset.getPose(hand))
+    local poseVR = mat4(motion.pose):mul(poseRW)
+    if lovr.headset.isDown(hand, 'grip') then
+      lovr.graphics.setColor(palette[6])
+    else
+      lovr.graphics.setColor(palette[8])
+    end
+    poseVR:scale(0.02)
+    lovr.graphics.sphere(poseVR)
+  end
+  -- An example scene
+  local t = lovr.timer.getTime()
+  lovr.graphics.setCullingEnabled(true)
+  local step = 0.5
+  for x = -5, 5, step do
+    for z = -5, 5, step do
+      local y = 0.5 * math.sin(t * 0.2 + (x * 0.5)^2 + (z * 0.5)^2)
+      lovr.graphics.setColor(palette[2 + math.floor(y * 10) % (#palette - 1)])
+      lovr.graphics.sphere(x, y, z, step / 2)
+    end
+  end
+end

+ 1 - 0
examples/init.lua

@@ -17,6 +17,7 @@ return {
   'Locomotion/Teleportation_Flat',
   'Locomotion/Teleportation_Colliders',
   'Locomotion/Walking_In_Place',
+  'Locomotion/Space_Stretch',
   'Environment/Grid',
   'Environment/Skybox',
   'Environment/Terrain_-_Heightmap',