Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion render/world_to_screen/example.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,35 @@ thumbnail: thumbnail.png

This example shows how to convert world positions to screen coordinates for UI positioning. It features:

* A `world_to_screen()` function that transforms 3D world positions to 2D screen coordinates using the camera's view and projection matrices.
* Use of the built-in `camera.world_to_screen()` API to transform 3D world positions to 2D screen coordinates.
* A reference Lua `world_to_screen()` implementation (below) kept as an example to help understand how the conversion works internally.
* A ghost character that rotates around a crypt in 3D space while floating up and down.
* A player name label in the GUI that follows the character's world position by converting it to screen coordinates.
* Demonstrates practical use of world-to-screen conversion for positioning UI elements relative to 3D objects.

Note: The reference Lua version does not preserve depth information and always returns `z = 0` to keep the code simpler.

```lua
--- Converts a world position to screen coordinates.
-- This function transforms a 3D world position to 2D screen coordinates using the camera's
-- view and projection matrices. The resulting coordinates are in screen space where (0,0)
-- is the bottom-left corner of the screen.
--
-- @param world_position vector3 The world position to convert.
-- @param camera_url url|string The camera component URL to use for the transformation.
-- @return number screen_x The X coordinate in screen space.
-- @return number screen_y The Y coordinate in screen space.
-- @return number screen_z Always returns 0 (depth information is not preserved).
local function world_to_screen(world_position, camera_url)
local proj = camera.get_projection(camera_url)
local view = camera.get_view(camera_url)

local view_proj = proj * view
local scr_coord = view_proj * vmath.vector4(world_position.x, world_position.y, world_position.z, 1)
local w, h = window.get_size()
scr_coord.x = (scr_coord.x / scr_coord.w + 1) * 0.5 * w
scr_coord.y = (scr_coord.y / scr_coord.w + 1) * 0.5 * h

return vmath.vector3(scr_coord.x, scr_coord.y, 0)
end
```
1 change: 1 addition & 0 deletions render/world_to_screen/example/hud.gui_script
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ function on_message(self, message_id, message, sender)
if message_id == hash("update_data") then
local screen_position = message.screen_position
-- Use screen position to set the position of the player name node
screen_position.z = 0 -- "z" should be reset to 0.
gui.set_screen_position(self.name_node, screen_position)
end
end
27 changes: 2 additions & 25 deletions render/world_to_screen/example/player.script
Original file line number Diff line number Diff line change
@@ -1,30 +1,7 @@
go.property("camera_url", msg.url("/camera#camera"))
go.property("camera_url", msg.url("/camera#camera")) -- URL of the camera component
go.property("hud_url", msg.url("/ui#hud"))
go.property("angle", -45) -- we use this property to animate the rotation of the player around the center of the scene

--- Converts a world position to screen coordinates.
-- This function transforms a 3D world position to 2D screen coordinates using the camera's
-- view and projection matrices. The resulting coordinates are in screen space where (0,0)
-- is the bottom-left corner of the screen.
--
-- @param world_position vector3 The world position to convert.
-- @param camera_url url|string The camera component URL to use for the transformation.
-- @return number screen_x The X coordinate in screen space.
-- @return number screen_y The Y coordinate in screen space.
-- @return number screen_z Always returns 0 (depth information is not preserved).
local function world_to_screen(world_position, camera_url)
local proj = camera.get_projection(camera_url)
local view = camera.get_view(camera_url)

local view_proj = proj * view
local scr_coord = view_proj * vmath.vector4(world_position.x, world_position.y, world_position.z, 1)
local w, h = window.get_size()
scr_coord.x = (scr_coord.x / scr_coord.w + 1) * 0.5 * w
scr_coord.y = (scr_coord.y / scr_coord.w + 1) * 0.5 * h

return vmath.vector3(scr_coord.x, scr_coord.y, 0)
end

function init(self)
-- Get the IDs of the player view and UI objects
self.player_view_id = go.get_id("player_view")
Expand Down Expand Up @@ -54,7 +31,7 @@ function update(self, dt)
-- Update the world transform of the player UI object and convert the world position to screen coordinates
go.update_world_transform(self.player_ui_id)
local world_pos = go.get_world_position(self.player_ui_id)
local screen_pos = world_to_screen(world_pos, self.camera_url)
local screen_pos = camera.world_to_screen(world_pos, self.camera_url)
-- Send the screen position to the HUD script
msg.post(self.hud_url, "update_data", { screen_position = screen_pos })
end