Stingray Forum (Read Only)
Welcome to Autodesk’s Stingray Forums. Share your knowledge, ask questions, and explore popular Stingray topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Lua Cameras & Appkit

6 REPLIES 6
SOLVED
Reply
Message 1 of 7
kainevg
795 Views, 6 Replies

Lua Cameras & Appkit

Hi everyone,

 

I've been attempting to start my game with the Appkit as the basis for all my Lua. However, I've found that trying to work out anything to do with the Appkit is extremely tedious. I'll use what I'm currently trying to do as an example, which is set up my own Camera system as it needs a lot more functionality than what you recieve from the Appkit out of the box. I've been looking at how to create a new camera with Lua, and then set it as the active camera. Tracing the path in which the free_cam_player is created in the Appkit has left me quite confused.

 

I think I've narrowed down the main functions to do with creating the free_cam_player. The first is the PlayerUtil.spawn_free_cam_player() function in player_util:

function PlayerUtil.spawn_free_cam_player(level, camera_unit, camera_index, position, rotation, input_mapper)
	-- A container for the freecam objects
	local free_cam_player = {}
	free_cam_player.unit = camera_unit

	-- Camera
	local camera = CameraWrapper(free_cam_player, camera_unit, camera_index)
	camera:set_local_position(position)
	camera:set_local_rotation(rotation)
	camera:enable()

	-- Add camera input movement. Starts enabled.
	local controller = UnitController(free_cam_player, camera_unit, input_mapper)
	controller:set_move_speed(free_cam_move_speed:unbox())
	controller:set_yaw_speed(free_cam_yaw_speed)
	controller:set_pitch_speed(free_cam_pitch_speed)

	return free_cam_player
end

Obviously the next important function being the CameraWrapper() function it calls when it creates the local variable 'camera' above.. this one is from the camera_wrapper.lua:

 

function CameraWrapper:init(entity, unit, camera_index)
	self.entity = entity -- object this component is associated with, can be used to access other components
	self.unit = unit
	self.camera = Unit.camera(unit, camera_index)
	self.world = Unit.world(unit)

	self.is_enabled = false

	CameraWrapper.manager:add_component(entity, self, Unit.level(unit))
end

(took out a few irrelevant lines from the function above)

 

1) Why is the first parameter that the init function takes named 'entity'? This confuses me as I believe they're using the term to just describe a table that they've stored information in, however that's in conflict with an actual namespace 'stingray.Entity'  which can just make it confusing to read.

 

2) When passing the 'entity' into this function, it's also passing the camera_unit as it was added to the table being passed in in the previous function here:

-- A container for the freecam objects
	local free_cam_player = {}
	free_cam_player.unit = camera_unit

so wouldn't you then just retrieve the camera_unit information from the 'entity'?

 

3) What IS the camera_unit? I can see it references an actual .unit file in the Appkit.. is this camera_unit used for all cameras you create? They all reference the same unit? How do you create/can you create a camera without using this?

 

4) The line:

self.camera = Unit.camera(unit, camera_index)

Does this just retrieve the actual Camera? i.e. the stingray.Camera object?

 

5) I can't see anywhere in here that the camera is actually created, only that you've made a table, storing the location of a .unit file which you then use to somehow get a camera.. but where does that camera come from? This reverts to questions 3.. what is the camera_unit?

 

6) How do you set the active camera?  I understand the camera_wrapper.lua has this function:

function CameraWrapper:enable()
	if self.enabled == true then return end

	local world_wrapper = Appkit.managed_world
	if world_wrapper and world_wrapper.world == self.world then
		world_wrapper:set_camera_enabled(self.camera, self.unit, true)
		self.is_enabled = true
	end
end

which calls this function from the world_wrapper.lua script:

 

function WorldWrapper:set_camera_enabled(camera, unit, enabled)
	if not camera then return end

	if enabled == true then
		self.enabled_cameras[camera] = unit
	else
		self.enabled_cameras[camera] = nil
	end
end

which sets a 'camera' variable of the 'enabled_cameras' table to be the unit you pass in.. in the WorldWrapper:render() function above it, it then has this for loop:

 

for camera, _ in pairs(self.enabled_cameras) do
		Application.render_world(world, camera, viewport, shading_env)
	end

So I take it this means every frame you tell the renderer which camera to use, but I'm also confused because in the set_camera_enabled function we made the camera variable equal the unit.. not the actual stingray.Camera instance even though the 'Application.render_world()' function only accepts a stingray.Camera object.. Ahhh my head!! I can obviously guess since it works that somehow it actually is passing the camera instance and not a unit in but I can't figure it out.. Also, since this is for loop is running through every named key in the enabled_cameras table.. if you had multiple cameras what would happen?

 

I do apologise for such a long thread however answers to these questions will greatly increase my understanding of how the Appkit and Lua are working in Stingray, and I'm sure other people who are new to Stingray will also find it equally as helpful!

 

Thank you so much for all your help!

 

Cheers,

Kaine

 

 

6 REPLIES 6
Message 2 of 7
dan.matlack
in reply to: kainevg

Hi Kaine,

All great questions! The appkit can be a bit confusing and we are continually iterating on the functionality. To answer your questions on the appkit functionality, I am going to pass this along to the person who implemented it -- also you may reference the docs here: http://help.autodesk.com/view/Stingray/ENU/?guid=__stingray_help_creating_gameplay_scripting_with_lu...

If you like, may also not use the appkit or its camera at all. In your boot.lua file you've defined, you can add in a game camera:

 

function init()

Game.camera_unit = World.spawn_unit(Game.world, "core/units/camera")

end

You can then control your camera in update, for example setting the position every tick ...

 

        camera_pos.y = camera_pos.y + 0.5;
        stingray.Unit.set_local_position(Game.camera_unit, 1, camera_pos);

and in render 

 

-- Called once every frame.
function render()
	local camera = Unit.camera(Game.camera_unit, "camera")
	Application.render_world(Game.world, camera, Game.viewport, Game.shading_environment)
end

I will reach out and get some further clarification on the appkit questions for you as well.

 

 

______________________________________
Dan Matlack
Senior Content Manager || Games Solutions
Autodesk, Inc.
Message 3 of 7
kainevg
in reply to: dan.matlack

Hi Dan!

 

Thanks for the response! I will probably end up using a custom boot script without the Appkit when I begin a project properly, however it's a good intro to Stingray I think, and will help me to stop thinking about programming in a context I'm used to, and more in a Lua mindset..

 

Look forward to hearing from them.

 

Cheers,

Kaine

Message 4 of 7
t_livee
in reply to: kainevg

Hi Kaine! Some answers:

 

1. (Regarding why `CameraWrapper` arg 1 is called entity)

 

It's true this is a temporary system that will eventually be replaced by the stingray.Entity system. The CameraWrapper is an appkit component, that gets associated with an entity. An entity in the appkit is just a lua reference that we attach various components to. It could be a table, it could be userdata, it could be a number.

 

Please read the appkit docs for component_manager:

 

http://help.autodesk.com/cloudhelp/ENU/Stingray-Help/stingray_help/creating_gameplay/scripting_with_...

 

2. (regarding the camera unit argument)

 

There is no requirement that the `entity` object parameter must have a camera unit available on it somehow. The entity is just something we attach things to. So the camera_unit must be passed separately.

 

3. Yes the camera unit is the .unit file in core/appkit/units. A Camera is actually a sub-object within a Unit. A unit can have 0-n cameras in it. The Appkit camera unit has one camera in it. Cameras can be added to any unit in the Unit Editor via the Create menu, with a mesh hierarchy node selected.

 

4. Yes this retrieves the `Camera` engine object from the `Unit` engine object, at the given index (cameras are index from 1 to N in the unit)

 

5. The camera_unit for the template-based projects is created in core/appkit/lua/simple_project.lua. Then the Player scripts grab it from SimpleProject.

 

6. Yes engine World objects are told per render call what Camera to draw with. The Appkit offers glue (via the appkit WorldWrapper, LevelWrapper, CameraWrapper, and appkit flow nodes) to couple Cameras with Worlds so that they can be set as active either via lua or via level flow. The WorldWrapper calls render on each active camera in its list, so this can be used to do multiple viewports and other effects, but this is not used in any of our template projects.

Message 5 of 7
kainevg
in reply to: t_livee

Hey t_livee,

 

Thanks for the answers 🙂 I was wondering if you could clarify line 63 of the world_wrapper for me:

 

self.enabled_cameras[camera] = unit

Doesn't this set the variable enabled_cameras[camera] to be the unit? Not the actual camera object? How does it get the camera object when it runs through the for loop above it to call the render_world() function?

 

 

This second one is a bit of a tangent but while I've got you, are there any cases where I wouldn't use the Appkit.class script to create an 'instance' of my custom scripts, rather than just having the straight script run? Would it be good practice to always use this because then I can think of the whole program in more of an OOP sense?

 

Cheers,

Kaine

 

Edit: Is there any information out on when we can expect the entity system, or features etc that are being worked on? I think it would be great to keep hype up.

Message 6 of 7
t_livee
in reply to: kainevg

Hi Kaine!

 

Sorry for the delay. The WorldWrapper stores the `camera` object as the key in the table and the `camera_unit` as the value.

 

When the WorldWrapper iterates for rendering, it uses the camera key (and ignores the values):

 

for camera, _ in pairs(self.enabled_cameras) do
Application.render_world(world, camera, viewport, shading_env)
end

In regards to when *not* to use the class helper: when only a single instance of something is needed and the inheritance features of the class utility are not needed. It doesn't hurt much to use the class helper often however.

 

The exact timing on the Entity system rollout across different areas of the engine is not clear yet. There will be many systems and editor features to update.

Message 7 of 7
kainevg
in reply to: t_livee

Hey t_livee 🙂

 

No problem! Oh wow I can't believe I didn't see that........ thanks!

 

Yeah I figured there wouldn't be too much harm. I've just basically been using it for everything so I can think of the whole program in OOP terms as that's what I'm used to.

 

Cheers,
Kaine

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums