| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- --
- -- Dynamic bounding box - it tracks the bounding box of the objects in the scene
- --
- --- Create a new instance
- -- @return table - the bounding box instance
- local function bbox_new()
- return {
- objects = {}, -- dict for iteration
- count = 0,
- min = vmath.vector3(),
- max = vmath.vector3()
- }
- end
- --- Add an object to the bounding box
- -- @param bbox table - the bounding box instance
- -- @param obj_id hash - the object id
- -- @param aabb table - the aabb of the object
- local function bbox_add(bbox, obj_id, aabb)
- if not aabb then
- aabb = model.get_aabb(msg.url(nil, obj_id, "model"))
- else
- assert(types.is_vector3(aabb.min) and types.is_vector3(aabb.max), "AABB is not valid")
- end
- local entry = {
- id = obj_id,
- position = go.get_position(obj_id),
- aabb = aabb
- }
- bbox.objects[obj_id] = entry
- bbox.count = bbox.count + 1
- end
- --- Remove an object from the bounding box
- -- @param bbox table - the bounding box instance
- -- @param obj_id hash - the object id
- local function bbox_remove(bbox, obj_id)
- bbox.objects[obj_id] = nil
- bbox.count = bbox.count - 1
- end
- --- Update the bounding box
- -- @param bbox table - the bounding box instance
- local function bbox_update_all(bbox)
- bbox.min = vmath.vector3()
- bbox.max = vmath.vector3()
- for _, entry in pairs(bbox.objects) do
- local pos = go.get_position(entry.id)
- entry.position = pos
- bbox.min.x = math.min(bbox.min.x, entry.aabb.min.x + pos.x)
- bbox.min.y = math.min(bbox.min.y, entry.aabb.min.y + pos.y)
- bbox.min.z = math.min(bbox.min.z, entry.aabb.min.z + pos.z)
- bbox.max.x = math.max(bbox.max.x, entry.aabb.max.x + pos.x)
- bbox.max.y = math.max(bbox.max.y, entry.aabb.max.y + pos.y)
- bbox.max.z = math.max(bbox.max.z, entry.aabb.max.z + pos.z)
- end
- end
- --- Compute the bounding box
- -- @param bbox table - the bounding box instance
- -- @return table - result with {center, min, max, radius}
- local function bbox_compute(bbox)
- local center = (bbox.min + bbox.max) * 0.5
- local radius = vmath.length(bbox.max - bbox.min) * 0.5
- return {
- center = center,
- min = bbox.min,
- max = bbox.max,
- radius = radius
- }
- end
- --
- -- Helper functions
- --
- --- Add a cube to the scene
- -- @param self table - the script instance
- -- @param x number - the x coordinate
- -- @param y number - the y coordinate
- -- @param z number - the z coordinate
- -- @param color string - the color of the cube - "red" or "white"
- local function add_cube(self, x, y, z, color)
- if self.bbox.count >= sys.get_config_int("model.max_count") then
- print("Increase `model.max_count` and `physics.max_collision_object_count` values!")
- return
- end
- local url = color == "red" and "#factory_box2" or "#factory_box1"
- local obj_id = factory.create(url, vmath.vector3(x, y, z))
- bbox_add(self.bbox, obj_id)
- go.animate(msg.url(nil, obj_id, "model"), "tint.w", go.PLAYBACK_ONCE_BACKWARD, 3, go.EASING_INQUAD, 0.5)
- end
- --
- -- Main script
- --
- function init(self)
- -- Acquire input focus to receive input events
- msg.post(".", "acquire_input_focus")
- -- Get the camera default rotation
- self.camera_euler = go.get("/camera", "euler")
- -- Create a new dynamic bounding box instance
- self.bbox = bbox_new()
- -- Add some cubes to the scene at (0, 1-5, 0) coordinates
- for i = 1, 10 do
- local cube_color = i % 2 == 0 and "red" or "white"
- add_cube(self, (math.random() - 0.5) * 0.1, i / 2, (math.random() - 0.5) * 0.1, cube_color)
- end
- bbox_update_all(self.bbox)
- -- Compute the initial bounding box data
- self.view = bbox_compute(self.bbox)
- end
- function update(self, dt)
- bbox_update_all(self.bbox)
- -- Current bounding box data
- local current = bbox_compute(self.bbox)
- -- Animate the values for smooth camera movement
- local t = 0.05
- self.view.center = vmath.lerp(t, self.view.center, current.center)
- self.view.radius = vmath.lerp(t, self.view.radius, current.radius)
- -- Calculate camera position and rotation
- local camera_yaw = vmath.quat_rotation_y(math.rad(self.camera_euler.y))
- local camera_pitch = vmath.quat_rotation_x(math.rad(self.camera_euler.x))
- local camera_rotation = camera_yaw * camera_pitch
- local camera_zoom = 1.05 * self.view.radius / math.tan(0.5 * go.get("/camera#camera", "fov"))
- local camera_position = self.view.center + vmath.rotate(camera_rotation, vmath.vector3(0, 0, camera_zoom))
- go.set("/camera", "position", camera_position)
- go.set("/camera", "rotation", camera_rotation)
- -- Uncomment to benchmark
- -- add_cube(self, math.random(-3, 3), 10, math.random(-3, 3))
- -- add_cube(self, math.random(-3, 3), 10, math.random(-3, 3), "red")
- end
- function on_input(self, action_id, action)
- -- Add a cube to the scene when the mouse button / space key is pressed
- if (action_id == hash("touch") or action_id == hash("key_space")) and action.pressed then
- local colors = {"red", "white"}
- add_cube(self, (math.random() - 0.5) * 0.5, 10, (math.random() - 0.5) * 0.5, colors[math.random(1, 2)])
- end
- end
|