Browse Source

Merge pull request #88 from jmiskovic/add/terraincollider

API and example for newTerrainCollider
Bjorn 2 years ago
parent
commit
a5b4f23a7e

+ 2 - 1
api/lovr/graphics/Pass/mesh.lua

@@ -63,7 +63,8 @@ return {
     },
     },
     base = {
     base = {
       type = 'number',
       type = 'number',
-      default = 'A base offset to apply to vertex indices.'
+      default = '0',
+      description = 'A base offset to apply to vertex indices.'
     }
     }
   },
   },
   returns = {},
   returns = {},

+ 2 - 1
api/lovr/physics/World/newBoxCollider.lua

@@ -53,6 +53,7 @@ return {
     'World:newCapsuleCollider',
     'World:newCapsuleCollider',
     'World:newCylinderCollider',
     'World:newCylinderCollider',
     'World:newMeshCollider',
     'World:newMeshCollider',
-    'World:newSphereCollider'
+    'World:newSphereCollider',
+    'World:newTerrainCollider'
   }
   }
 }
 }

+ 2 - 1
api/lovr/physics/World/newCapsuleCollider.lua

@@ -48,6 +48,7 @@ return {
     'World:newBoxCollider',
     'World:newBoxCollider',
     'World:newCylinderCollider',
     'World:newCylinderCollider',
     'World:newMeshCollider',
     'World:newMeshCollider',
-    'World:newSphereCollider'
+    'World:newSphereCollider',
+    'World:newTerrainCollider'
   }
   }
 }
 }

+ 1 - 0
api/lovr/physics/World/newCollider.lua

@@ -64,6 +64,7 @@ return {
     'World:newCylinderCollider',
     'World:newCylinderCollider',
     'World:newMeshCollider',
     'World:newMeshCollider',
     'World:newSphereCollider',
     'World:newSphereCollider',
+    'World:newTerrainCollider',
     'Collider',
     'Collider',
     'Shape'
     'Shape'
   }
   }

+ 2 - 1
api/lovr/physics/World/newCylinderCollider.lua

@@ -48,6 +48,7 @@ return {
     'World:newBoxCollider',
     'World:newBoxCollider',
     'World:newCapsuleCollider',
     'World:newCapsuleCollider',
     'World:newMeshCollider',
     'World:newMeshCollider',
-    'World:newSphereCollider'
+    'World:newSphereCollider',
+    'World:newTerrainCollider'
   }
   }
 }
 }

+ 1 - 0
api/lovr/physics/World/newMeshCollider.lua

@@ -44,6 +44,7 @@ return {
     'World:newCapsuleCollider',
     'World:newCapsuleCollider',
     'World:newCylinderCollider',
     'World:newCylinderCollider',
     'World:newSphereCollider',
     'World:newSphereCollider',
+    'World:newTerrainCollider',
     'Model:getTriangles'
     'Model:getTriangles'
   }
   }
 }
 }

+ 2 - 1
api/lovr/physics/World/newSphereCollider.lua

@@ -43,6 +43,7 @@ return {
     'World:newBoxCollider',
     'World:newBoxCollider',
     'World:newCapsuleCollider',
     'World:newCapsuleCollider',
     'World:newCylinderCollider',
     'World:newCylinderCollider',
-    'World:newMeshCollider'
+    'World:newMeshCollider',
+    'World:newTerrainCollider'
   }
   }
 }
 }

+ 87 - 0
api/lovr/physics/World/newTerrainCollider.lua

@@ -0,0 +1,87 @@
+return {
+  tag = 'colliders',
+  summary = 'Add a Collider with a TerrainShape to the World.',
+  description = 'Adds a new Collider to the World with a TerrainShape already attached.',
+  arguments = {
+    scale = {
+      type = 'number',
+      description = 'Horizontal dimension of the terrain square'
+    },
+    heightmap = {
+      type = 'Image',
+      description = [[
+        An heightmap image describing the terrain elevation at different points.
+        Red channel brightness of each pixel determines the elevation at corresponding coordinates.
+      ]]
+    },
+    stretch = {
+      type = 'number',
+      description = [[
+        A vertical multiplier for heightmap values to obtain terrain height.
+        Used for heightmap image formats that have pixel values only in range from 0 to 1.
+      ]]
+    },
+    callback = {
+      type = 'function',
+      arguments = {
+        {
+          name = 'x',
+          type = 'number'
+        },
+        {
+          name = 'z',
+          type = 'number'
+        }
+      },
+      returns = {
+        name = 'height',
+        type = 'number'
+      },
+      description = [[
+        A function that computes terrain height for set of coordinates. Range of x and z coordinates
+        is from `-scale / 2` to `scale / 2`.'
+      ]]
+    },
+    samples = {
+      type = 'number',
+      description = [[
+        Number of samples taken per x and z dimensions. More samples result in higher terrain
+        fidelity using more CPU and memory resources.'
+      ]],
+      default = '100'
+    }
+  },
+  returns = {
+    collider = {
+      type = 'Collider',
+      description = 'The new Collider.'
+    }
+  },
+  variants = {
+    {
+      description = 'Create a flat floor collider',
+      arguments = { 'scale' },
+      returns = { 'collider' }
+    },
+    {
+      description = 'Create terrain from heightmap image',
+      arguments = { 'scale', 'heightmap', 'stretch' },
+      returns = { 'collider' }
+    },
+    {
+      description = 'Create terrain defined with a callback function',
+      arguments = { 'scale', 'callback', 'samples' },
+      returns = { 'collider' }
+    }
+  },
+  related = {
+    'Collider',
+    'World:newCollider',
+    'World:newBoxCollider',
+    'World:newCapsuleCollider',
+    'World:newCylinderCollider',
+    'World:newSphereCollider',
+    'World:newMeshCollider',
+    'lovr.data.newImage'
+  }
+}

+ 61 - 0
examples/Physics/Terrain/main.lua

@@ -0,0 +1,61 @@
+local function grid(size, subdivisions)
+  local vertices = {}
+  local indices  = {}
+  local step = size / (subdivisions - 1)
+  for z = -size / 2, size / 2, step do
+    for x = -size / 2, size / 2, step do
+      table.insert(vertices, {x, 0, z})
+      table.insert(vertices, {x, 0, z + step})
+      table.insert(vertices, {x + step, 0, z})
+      table.insert(vertices, {x, 0, z + step})
+      table.insert(vertices, {x + step, 0, z + step})
+      table.insert(vertices, {x + step, 0, z})
+    end
+  end
+  return vertices
+end
+
+local function terrain_fn(x, z)
+  return 4 * (lovr.math.noise(x * 0.05, z * 0.05) - 0.5)
+end
+
+function lovr.load()
+  size = 50
+  world = lovr.physics.newWorld(0, -9.81, 0, false)
+  lovr.graphics.setBackgroundColor(0.208, 0.208, 0.275)
+  local vertices, indices = grid(size, 100)
+  for vi = 1, #vertices do
+    local x,y,z = unpack(vertices[vi])
+    vertices[vi][2] = terrain_fn(x, z) -- elevate grid to terrain height
+  end
+  vertexBuffer = lovr.graphics.newBuffer(vertices, 'vec3')
+  world:newTerrainCollider(size, terrain_fn) -- use callback to define elevations
+  box_colliders = {}
+end
+
+function lovr.update(dt)
+  if lovr.timer.getTime() % 1 < dt then -- spawn new box each second
+    local collider = world:newBoxCollider(
+      lovr.math.randomNormal(size / 10, 0),
+      lovr.math.randomNormal(1, 20),
+      lovr.math.randomNormal(size / 10, 0),
+      1)
+    table.insert(box_colliders, collider)
+  end
+  world:update(1 / 60)
+end
+
+function lovr.draw(pass)
+  pass:setColor(0.925, 0.745, 0.137)
+  for _, collider in ipairs(box_colliders) do
+    pass:box(mat4(collider:getPose()))
+  end
+  pass:setColor(0.565, 0.404, 0.463)
+  pass:setDepthOffset(-10000) -- Ensure wireframe stays on top
+  pass:mesh(vertexBuffer)
+  pass:setDepthOffset()
+
+  pass:setWireframe(true)
+  pass:setColor(0.388, 0.302, 0.412, 0.1)
+  pass:mesh(vertexBuffer)
+end

+ 1 - 0
examples/init.lua

@@ -33,6 +33,7 @@ return {
   'Physics/Hand_Physics',
   'Physics/Hand_Physics',
   'Physics/Newtons_Cradle',
   'Physics/Newtons_Cradle',
   'Physics/Saloon_Door',
   'Physics/Saloon_Door',
+  'Physics/Terrain',
   'Physics/Wrecking_Ball',
   'Physics/Wrecking_Ball',
   'Physics/Zip_Line',
   'Physics/Zip_Line',
   'Audio/Playback',
   'Audio/Playback',