 # CameraCon

#1

Thanks to the new mesh features I’m inspired to work with 3D again and relearning / making useful things for me. Here is a very basic camera view movement and rotation script. If you setup the proper keys in input and attach this script to a GO which has our camera on you can use it to move around a 3D scene in a way useful for general inspection.

V1 because it’s a first fresh attempt and I intend to make it fancier in future versions. If you have a similar kind of script please contribute! I would like to make versions of every popular camera style. I’ll turn this into a proper project later.

V1

``````local turn_speed = 0.01
local move_speed = 0.25

local forward = vmath.vector3(0,0,-1)
local backward = vmath.vector3(0,0,1)
local left = vmath.vector3(-1,0,0)
local right = vmath.vector3(1,0,0)

local function move(v)
local position = go.get_position()
local rotation = go.get_rotation()
local direction =  vmath.rotate(rotation, v)
position = position + direction * move_speed
go.set_position(position)
end

function init(self)
msg.post(".", "acquire_input_focus")
end

function final(self)
-- Remove this function if not needed
end

function update(self, dt)
-- Remove this function if not needed
end

function on_message(self, message_id, message, sender)
-- Remove this function if not needed
end

function on_input(self, action_id, action)
if action_id == hash("touch") and action.released == false then
local rotation = go.get_rotation()
local direction_x
local direction_y
if action.dx then
if action.dx > 0 then
rotation = rotation * vmath.quat_axis_angle(vmath.vector3(0,-1,0), turn_speed * math.abs(action.dx))
else
rotation = rotation * vmath.quat_axis_angle(vmath.vector3(0,1,0), turn_speed * math.abs(action.dx))
end
end

if action.dy then
if action.dy > 0 then
rotation = rotation * vmath.quat_axis_angle(vmath.vector3(1,0,0), turn_speed * math.abs(action.dy))
else
rotation = rotation * vmath.quat_axis_angle(vmath.vector3(-1,0,0), turn_speed * math.abs(action.dy))
end
end
go.set_rotation(rotation)
end

if action_id == hash("key_w") and action.released == false then
move(forward)
end
if action_id == hash("key_s") and action.released == false then
move(backward)
end
if action_id == hash("key_a") and action.released == false then
move(left)
end
if action_id == hash("key_d") and action.released == false then
move(right)
end
end

-- Remove this function if not needed
end

``````
11 Likes

#2

V2 adds camera smoothing and removes roll from rotation. I’m not yet sure how to remote the general unwanted (in this case) roll introduced from rotating while in rotations outside of a normal FPS camera view?

Next version will be a rewrite using euler angles for setting roll / pitch / yaw so it’s easier to control.

``````local turn_speed = 0.6
local move_speed = 0.25

local FORWARD = vmath.vector3(0,0,-1)
local BACKWARD = vmath.vector3(0,0,1)
local LEFT = vmath.vector3(-1,0,0)
local RIGHT = vmath.vector3(1,0,0)
local UP = vmath.vector3(0,1,0)
local DOWN = vmath.vector3(0,-1,0)

local function move(v)
local position = go.get_position()
local rotation = go.get_rotation()
local direction =  vmath.rotate(rotation, v)
position = position + direction * move_speed
go.set_position(position)
end

function init(self)
msg.post(".", "acquire_input_focus")
self.rotation = go.get_rotation()

end

function final(self)
-- Remove this function if not needed
end

function update(self, dt)
-- print(self.touch_dx, self.touch_dy)
if self.touch_released == false then
local rotation = go.get_rotation()
local direction_x
local direction_y

if self.touch_dx then
if self.touch_dx > 0 then
rotation = vmath.quat_axis_angle(DOWN, dt * turn_speed * math.abs(self.touch_dx)) * rotation
else
rotation = vmath.quat_axis_angle(UP, dt * turn_speed * math.abs(self.touch_dx)) * rotation
end
end

if self.touch_dy then
if self.touch_dy > 0 then
rotation = rotation * vmath.quat_axis_angle(RIGHT, dt * turn_speed * math.abs(self.touch_dy))
else
rotation = rotation * vmath.quat_axis_angle(LEFT, dt * turn_speed * math.abs(self.touch_dy))
end
end
self.rotation = rotation
go.set_rotation(vmath.slerp(0.30, go.get_rotation(), self.rotation))
else
go.set_rotation(vmath.slerp(0.90, go.get_rotation(), self.rotation))
end

self.touch_released = false
self.touch_dx = nil
self.touch_dy = nil
end

function on_message(self, message_id, message, sender)
-- Remove this function if not needed
end

function on_input(self, action_id, action)

if action_id == hash("touch") then
self.touch = true
-- pprint(action)
self.touch_dx = action.dx
self.touch_dy = action.dy
-- print(self.touch_dx, self.touch_dy)
if action.released == false then
self.touch_released = false
else
self.touch_released = true
end
else
self.touch = false
end

if action_id == hash("key_w") and action.released == false then
move(FORWARD)
end
if action_id == hash("key_s") and action.released == false then
move(BACKWARD)
end
if action_id == hash("key_a") and action.released == false then
move(LEFT)
end
if action_id == hash("key_d") and action.released == false then
move(RIGHT)
end
end

-- Remove this function if not needed
end

``````
7 Likes

#3

V3 changes rotation method to euler angles, and moves movement into update instead of input. It also now constrains up/down rotation view. It’s a bit hacky at the moment.

Next version will add pseudo physics to the movement?

``````-- 90
-- 75
-- 54-68 viewmodel

local turn_speed = 0.6
local move_speed = 0.25
local run_mod = 2.5

local FORWARD = vmath.vector3(0,0,-1)
local BACKWARD = vmath.vector3(0,0,1)
local LEFT = vmath.vector3(-1,0,0)
local RIGHT = vmath.vector3(1,0,0)
local UP = vmath.vector3(0,1,0)
local DOWN = vmath.vector3(0,-1,0)

local function wrap(number, bound)
if (number < 0) then
return bound - (math.fmod(-number, bound))
else
return math.fmod(number, bound)
end
end

local function bound(number, min, max)
if number < min then
number = min
elseif number > max then
number = max
end
return number
end

local function quat_from_euler_vector(vect)
return zy * zx * zq
end

local function move(v, if_run)
local position = go.get_position()
local rotation = go.get_rotation()
local direction =  vmath.rotate(rotation, v)
if not if_run then
position = position + direction * move_speed
else
position = position + direction * move_speed * run_mod
end
go.set_position(position)
end

function init(self)
msg.post(".", "acquire_input_focus")
self.rotation = go.get_rotation()
self.euler_rotation = vmath.vector3(0,0,0)
self.rotation = quat_from_euler_vector(self.euler_rotation)
self.move_vector = vmath.vector3(0,0,0)
go.set_rotation(vmath.slerp(0.90, go.get_rotation(), self.rotation))
end

function final(self)
-- Remove this function if not needed
end

function update(self, dt)
if self.touch_released == false then
if self.touch_dx then
self.euler_rotation.y = self.euler_rotation.y + self.touch_dx * -turn_speed
if self.euler_rotation.y > 360 then
self.euler_rotation.y = self.euler_rotation.y - 360
end
if self.euler_rotation.y < -360 then
self.euler_rotation.y = self.euler_rotation.y + 360
end
end

if self.touch_dy then
self.euler_rotation.x = self.euler_rotation.x + self.touch_dy * turn_speed
self.euler_rotation.x = bound(self.euler_rotation.x, -90, 90)
end
self.rotation = quat_from_euler_vector(self.euler_rotation)
go.set_rotation(vmath.slerp(0.30, go.get_rotation(), self.rotation))
else
go.set_rotation(vmath.slerp(0.90, go.get_rotation(), self.rotation))
end

if vmath.length(self.move_vector) > 0 then
move(vmath.normalize(self.move_vector), self.key_shift)
end

self.touch_released = false
self.touch_dx = nil
self.touch_dy = nil
self.key_shift = false
self.move_vector.x = 0
self.move_vector.y = 0
self.move_vector.z = 0
end

function on_message(self, message_id, message, sender)
-- Remove this function if not needed
end

function on_input(self, action_id, action)

if action_id == hash("touch") then
self.touch = true
-- pprint(action)
self.touch_dx = action.dx
self.touch_dy = action.dy
-- print(self.touch_dx, self.touch_dy)
if action.released == false then
self.touch_released = false
else
self.touch_released = true
end
else
self.touch = false
end

if action_id == hash("key_shift") and action.released == false then
self.key_shift = true
end

if action_id == hash("key_w") and action.released == false then
self.move_vector.z = self.move_vector.z - 1
end
if action_id == hash("key_s") and action.released == false then
self.move_vector.z = self.move_vector.z + 1
end
if action_id == hash("key_a") and action.released == false then
self.move_vector.x = self.move_vector.x - 1
end
if action_id == hash("key_d") and action.released == false then
self.move_vector.x = self.move_vector.x + 1
end

end

-- Remove this function if not needed
end

``````
5 Likes

#4

Should be local?

1 Like

#5

Here is a sample of this script in action.

I will be working on making CameraCon into an accessible independent module with examples along with a new first person and third person example projects in the future with samples of various types of interaction. One issue that I will be waiting on is https://github.com/defold/defold/issues/4819 but when that happens I will go full steam ahead on many 3D resources for the community.

3 Likes