Skip to content

Commit 161a7ff

Browse files
authored
Update world-to-screen example to use built-in camera API (#141)
1 parent 25b8f05 commit 161a7ff

3 files changed

Lines changed: 32 additions & 26 deletions

File tree

render/world_to_screen/example.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,35 @@ thumbnail: thumbnail.png
99

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

12-
* A `world_to_screen()` function that transforms 3D world positions to 2D screen coordinates using the camera's view and projection matrices.
12+
* Use of the built-in `camera.world_to_screen()` API to transform 3D world positions to 2D screen coordinates.
13+
* A reference Lua `world_to_screen()` implementation (below) kept as an example to help understand how the conversion works internally.
1314
* A ghost character that rotates around a crypt in 3D space while floating up and down.
1415
* A player name label in the GUI that follows the character's world position by converting it to screen coordinates.
1516
* Demonstrates practical use of world-to-screen conversion for positioning UI elements relative to 3D objects.
17+
18+
Note: The reference Lua version does not preserve depth information and always returns `z = 0` to keep the code simpler.
19+
20+
```lua
21+
--- Converts a world position to screen coordinates.
22+
-- This function transforms a 3D world position to 2D screen coordinates using the camera's
23+
-- view and projection matrices. The resulting coordinates are in screen space where (0,0)
24+
-- is the bottom-left corner of the screen.
25+
--
26+
-- @param world_position vector3 The world position to convert.
27+
-- @param camera_url url|string The camera component URL to use for the transformation.
28+
-- @return number screen_x The X coordinate in screen space.
29+
-- @return number screen_y The Y coordinate in screen space.
30+
-- @return number screen_z Always returns 0 (depth information is not preserved).
31+
local function world_to_screen(world_position, camera_url)
32+
local proj = camera.get_projection(camera_url)
33+
local view = camera.get_view(camera_url)
34+
35+
local view_proj = proj * view
36+
local scr_coord = view_proj * vmath.vector4(world_position.x, world_position.y, world_position.z, 1)
37+
local w, h = window.get_size()
38+
scr_coord.x = (scr_coord.x / scr_coord.w + 1) * 0.5 * w
39+
scr_coord.y = (scr_coord.y / scr_coord.w + 1) * 0.5 * h
40+
41+
return vmath.vector3(scr_coord.x, scr_coord.y, 0)
42+
end
43+
```

render/world_to_screen/example/hud.gui_script

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ function on_message(self, message_id, message, sender)
1212
if message_id == hash("update_data") then
1313
local screen_position = message.screen_position
1414
-- Use screen position to set the position of the player name node
15+
screen_position.z = 0 -- "z" should be reset to 0.
1516
gui.set_screen_position(self.name_node, screen_position)
1617
end
1718
end
Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,7 @@
1-
go.property("camera_url", msg.url("/camera#camera"))
1+
go.property("camera_url", msg.url("/camera#camera")) -- URL of the camera component
22
go.property("hud_url", msg.url("/ui#hud"))
33
go.property("angle", -45) -- we use this property to animate the rotation of the player around the center of the scene
44

5-
--- Converts a world position to screen coordinates.
6-
-- This function transforms a 3D world position to 2D screen coordinates using the camera's
7-
-- view and projection matrices. The resulting coordinates are in screen space where (0,0)
8-
-- is the bottom-left corner of the screen.
9-
--
10-
-- @param world_position vector3 The world position to convert.
11-
-- @param camera_url url|string The camera component URL to use for the transformation.
12-
-- @return number screen_x The X coordinate in screen space.
13-
-- @return number screen_y The Y coordinate in screen space.
14-
-- @return number screen_z Always returns 0 (depth information is not preserved).
15-
local function world_to_screen(world_position, camera_url)
16-
local proj = camera.get_projection(camera_url)
17-
local view = camera.get_view(camera_url)
18-
19-
local view_proj = proj * view
20-
local scr_coord = view_proj * vmath.vector4(world_position.x, world_position.y, world_position.z, 1)
21-
local w, h = window.get_size()
22-
scr_coord.x = (scr_coord.x / scr_coord.w + 1) * 0.5 * w
23-
scr_coord.y = (scr_coord.y / scr_coord.w + 1) * 0.5 * h
24-
25-
return vmath.vector3(scr_coord.x, scr_coord.y, 0)
26-
end
27-
285
function init(self)
296
-- Get the IDs of the player view and UI objects
307
self.player_view_id = go.get_id("player_view")
@@ -54,7 +31,7 @@ function update(self, dt)
5431
-- Update the world transform of the player UI object and convert the world position to screen coordinates
5532
go.update_world_transform(self.player_ui_id)
5633
local world_pos = go.get_world_position(self.player_ui_id)
57-
local screen_pos = world_to_screen(world_pos, self.camera_url)
34+
local screen_pos = camera.world_to_screen(world_pos, self.camera_url)
5835
-- Send the screen position to the HUD script
5936
msg.post(self.hud_url, "update_data", { screen_position = screen_pos })
6037
end

0 commit comments

Comments
 (0)