Skip to content

Commit

Permalink
fixes for render script mamual
Browse files Browse the repository at this point in the history
  • Loading branch information
AGulev committed Oct 17, 2023
1 parent 3db927a commit 24b0ec4
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 221 deletions.
109 changes: 59 additions & 50 deletions docs/en/manuals/render.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,76 +159,79 @@ init()
function init(self)
-- Define the render predicates. Each predicate is drawn by itself and
-- that allows us to change the state of OpenGL between the draws.
self.tile_pred = render.predicate({"tile"})
self.gui_pred = render.predicate({"gui"})
self.text_pred = render.predicate({"text"})
self.particle_pred = render.predicate({"particle"})
self.model_pred = render.predicate({"model"})

self.clear_color = vmath.vector4(0, 0, 0, 0)
self.clear_color.x = sys.get_config("render.clear_color_red", 0)
self.clear_color.y = sys.get_config("render.clear_color_green", 0)
self.clear_color.z = sys.get_config("render.clear_color_blue", 0)
self.clear_color.w = sys.get_config("render.clear_color_alpha", 0)

-- Define a view matrix to use. If we have a camera object, it will
-- send "set_view_projection" messages to the render script and we
-- can update the view matrix with the value the camera provides.
self.view = vmath.matrix4()
self.predicates = create_predicates("tile", "gui", "text", "particle", "model")

-- Create and fill data tables will be used in update()
local state = create_state()
self.state = state
local camera_world = create_camera(state, "camera_world", true)
init_camera(camera_world, get_stretch_projection)
local camera_gui = create_camera(state, "camera_gui")
init_camera(camera_gui, get_gui_projection)
update_state(state)
end
```

update()
: The `update()` function is called once each frame. Its function is to perform the actual drawing by calling the underlying OpenGL ES APIs (OpenGL Embedded Systems API). To properly understand what's going on in the `update()` function, you need to understand how OpenGL works. There are many great resources on OpenGL ES available. The official site is a good starting place. You find it at https://www.khronos.org/opengles/

This example contains the setup necessary to draw 3D models. The `init()` function defined a `self.model_pred` predicate. Elsewhere a material with the tag "model" has been created. There are also some model components that use the material:
This example contains the setup necessary to draw 3D models. The `init()` function defined a `self.predicates.model` predicate. Elsewhere a material with the tag "model" has been created. There are also some model components that use the material:

```lua
function update(self)
local window_width = render.get_window_width()
local window_height = render.get_window_height()
if window_width == 0 or window_height == 0 then
return
local state = self.state
if not state.valid then
if not update_state(state) then
return
end
end

local predicates = self.predicates
-- clear screen buffers
--
render.set_depth_mask(true)
render.set_stencil_mask(0xff)
render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0})
render.clear(state.clear_buffers)

-- render world (sprites, tilemaps, particles etc)
--
local proj = get_projection(self)
local frustum = proj * self.view
local camera_world = state.cameras.camera_world
render.set_viewport(0, 0, state.window_width, state.window_height)
render.set_view(camera_world.view)
render.set_projection(camera_world.proj)

render.set_viewport(0, 0, window_width, window_height)
render.set_view(self.view)
render.set_projection(proj)

-- render models
--
render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
render.enable_state(render.STATE_CULL_FACE)
render.enable_state(render.STATE_DEPTH_TEST)
render.set_depth_mask(true)
render.draw(predicates.model_pred)
render.set_depth_mask(false)
render.disable_state(render.STATE_DEPTH_TEST)
render.disable_state(render.STATE_STENCIL_TEST)
render.enable_state(render.STATE_BLEND)
render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
render.disable_state(render.STATE_CULL_FACE)

render.draw(self.tile_pred, {frustum = frustum})
render.draw(self.particle_pred, {frustum = frustum})
-- render world (sprites, tilemaps, particles etc)
--
render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
render.enable_state(render.STATE_DEPTH_TEST)
render.enable_state(render.STATE_STENCIL_TEST)
render.enable_state(render.STATE_BLEND)
render.draw(predicates.tile)
render.draw(predicates.particle)
render.disable_state(render.STATE_STENCIL_TEST)
render.disable_state(render.STATE_DEPTH_TEST)

-- debug
render.draw_debug3d()

-- render GUI
--
local view_gui = vmath.matrix4()
local proj_gui = vmath.matrix4_orthographic(0, window_width, 0, window_height, -1, 1)
local frustum_gui = proj_gui * view_gui

render.set_view(view_gui)
render.set_projection(proj_gui)

local camera_gui = state.cameras.camera_gui
render.set_view(camera_gui.view)
render.set_projection(camera_gui.proj)
render.enable_state(render.STATE_STENCIL_TEST)
render.draw(self.gui_pred, {frustum = frustum_gui})
render.draw(self.text_pred, {frustum = frustum_gui})
render.draw(predicates.gui, camera_gui.frustum)
render.draw(predicates.text, camera_gui.frustum)
render.disable_state(render.STATE_STENCIL_TEST)
end
```
Expand All @@ -239,17 +242,21 @@ on_message()
: A render script can define an `on_message()` function and receive messages from other parts of your game or app. A common case where an external component sends information to the render script is the _camera_. A camera component that has acquired camera focus will automatically send its view and projection to the render script each frame. This message is named `"set_view_projection"`:

```lua
local MSG_CLEAR_COLOR = hash("clear_color")
local MSG_WINDOW_RESIZED = hash("window_resized")
local MSG_SET_VIEW_PROJ = hash("set_view_projection")

function on_message(self, message_id, message)
if message_id == hash("clear_color") then
if message_id == MSG_CLEAR_COLOR then
-- Someone sent us a new clear color to be used.
self.clear_color = message.color
elseif message_id == hash("set_view_projection") then
update_clear_color(state, message.color)
elseif message_id == MSG_SET_VIEW_PROJ then
-- The camera component that has camera focus will sent set_view_projection
-- messages to the @render socket. We can use the camera information to
-- set view (and possibly projection) of the rendering.
-- Currently, we're rendering orthogonally so there's no need for camera
-- projection.
self.view = message.view
camera.view = message.view
self.camera_projection = message.projection or vmath.matrix4()
update_camera(camera, state)
end
end
```
Expand All @@ -276,8 +283,10 @@ The Defold render script API translates render operations into the following gra
: The engine will send this message on changes of the window size. You can listen to this message to alter rendering when the target window size changes. On desktop this means that the actual game window has been resized and on mobile devices this message is sent whenever an orientation change happens.

```lua
local MSG_WINDOW_RESIZED = hash("window_resized")

function on_message(self, message_id, message)
if message_id == hash("window_resized") then
if message_id == MSG_WINDOW_RESIZED then
-- The window was resized. message.width and message.height contain the new dimensions.
...
end
Expand Down
117 changes: 64 additions & 53 deletions docs/ko/manuals/render.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,16 @@ render predicates(렌더 술어 or 조건자)는 오브젝트의 그리기 순
```lua
function init(self)
-- render predicate를 정의합니다. 각 predicate는 자기 스스로 드로우되고 이 드로우들 사이에서 OpenGL의 상태를 변경 할 수 있습니다.
self.tile_pred = render.predicate({"tile"})
self.gui_pred = render.predicate({"gui"})
self.text_pred = render.predicate({"text"})
self.particle_pred = render.predicate({"particle"})
self.model_pred = render.predicate({"model"})

self.clear_color = vmath.vector4(0, 0, 0, 0)
self.clear_color.x = sys.get_config("render.clear_color_red", 0)
self.clear_color.y = sys.get_config("render.clear_color_green", 0)
self.clear_color.z = sys.get_config("render.clear_color_blue", 0)
self.clear_color.w = sys.get_config("render.clear_color_alpha", 0)

-- 사용할 view matrix를 정의합니다. 카메라 오브젝트를 사용한다면 "set_view_projection" 메세지를 렌더 스크립트로 전송하고 카메라가 제공하는 값으로 view matrix를 업데이트 할 수 있습니다.
self.view = vmath.matrix4()
self.predicates = create_predicates("tile", "gui", "text", "particle", "model")

-- Create and fill data tables will be used in update()
local state = create_state()
self.state = state
local camera_world = create_camera(state, "camera_world", true)
init_camera(camera_world, get_stretch_projection)
local camera_gui = create_camera(state, "camera_gui")
init_camera(camera_gui, get_gui_projection)
update_state(state)
end
```

Expand All @@ -61,56 +57,64 @@ end
#### update()
update() 함수는 매 프레임 마다 호출됩니다. 이 함수는 OpenGL ES API(OpenGL Embedded Systems API)를 사용하여 실제 드로잉을 처리합니다. update() 함수에서 무슨일이 벌어지는지 이해하기 위해서는 OpenGL이 동작하는 방법을 이해해야만 합니다. OpenGL ES에는 훌륭한 리소스가 많이 있으며 https://www.khronos.org/opengles/ 공식 사이트가 이해를 위한 좋은 출발점이 될 수 있습니다.

다음 예제에는 3D 모델을 올바르게 그리는데 필요한 설정을 하는 내장 스크립트에 대한 주요사항이 포함되어 있습니다. 위에서 보았듯이, self.model_pred predicate가 구성되고 다른 곳에서 이 predicate에 해당하는 메터리얼이 정의되어 3D 모델 컴포넌트에 반영되었습니다. update() 코드는 이 predicate에 대한 특정한 처리를 필요로 합니다.
다음 예제에는 3D 모델을 올바르게 그리는데 필요한 설정을 하는 내장 스크립트에 대한 주요사항이 포함되어 있습니다. 위에서 보았듯이, self.predicates.model predicate가 구성되고 다른 곳에서 이 predicate에 해당하는 메터리얼이 정의되어 3D 모델 컴포넌트에 반영되었습니다. update() 코드는 이 predicate에 대한 특정한 처리를 필요로 합니다.

```lua
function update(self)
-- depth buffer를 수정할 수 있도록 depth mask를 설정함
render.set_depth_mask(true)
local state = self.state
if not state.valid then
if not update_state(state) then
return
end
end

-- 클리어 컬러값(clear color)으로 color buffer를 지우고 depth buffer를 1.0으로 설정함
-- 정상적인 depth 값은 0.0(near)에서 1.0(far) 사이이므로 버퍼에서 값들을 최대화(maximizing)하면 그려진 모든 픽셀이 1.0보다 가까워지기 때문에 올바르게 그려지게 되며 깊이 테스트(depth testing)가 수행됨
render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0})
local predicates = self.predicates
-- clear screen buffers
--
render.set_depth_mask(true)
render.set_stencil_mask(0xff)
render.clear(state.clear_buffers)

-- 뷰포트를 윈도우의 창 크기로 설정함
render.set_viewport(0, 0, render.get_window_width(), render.get_window_height())
local camera_world = state.cameras.camera_world
render.set_viewport(0, 0, state.window_width, state.window_height)
render.set_view(camera_world.view)
render.set_projection(camera_world.proj)

-- 뷰를 저장한 뷰 값으로 설정함(카메라 오브젝트를 이용해 설정 가능)
render.set_view(self.view)

-- 2D 공간 렌더링하기
-- render models
--
render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
render.enable_state(render.STATE_CULL_FACE)
render.enable_state(render.STATE_DEPTH_TEST)
render.set_depth_mask(true)
render.draw(predicates.model_pred)
render.set_depth_mask(false)
render.disable_state(render.STATE_DEPTH_TEST)
render.disable_state(render.STATE_STENCIL_TEST)
render.enable_state(render.STATE_BLEND)
render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
render.disable_state(render.STATE_CULL_FACE)

-- 직교(orthographic) 상태로 투영(projection)방식을 설정하여 -200에서 200 Z-depth 사이까지만 렌더링함
render.set_projection(vmath.matrix4_orthographic(0, render.get_width(), 0, render.get_height(), -200, 200))

render.draw(self.tile_pred)
render.draw(self.particle_pred)

-- 3D 공간 렌더링하기, 하지만 여전히 직교(orthographic) 상태임
-- 페이스 컬링(Face culling)과 깊이 테스트(depth test)를 활성화 함
render.enable_state(render.STATE_CULL_FACE)
-- render world (sprites, tilemaps, particles etc)
--
render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
render.enable_state(render.STATE_DEPTH_TEST)
render.set_depth_mask(true)
render.draw(self.model_pred)
render.draw_debug3d()
render.enable_state(render.STATE_STENCIL_TEST)
render.enable_state(render.STATE_BLEND)
render.draw(predicates.tile)
render.draw(predicates.particle)
render.disable_state(render.STATE_STENCIL_TEST)
render.disable_state(render.STATE_DEPTH_TEST)

-- 마지막으로 GUI 렌더링하기
render.set_view(vmath.matrix4())
render.set_projection(vmath.matrix4_orthographic(0, render.get_window_width(), 0, render.get_window_height(), -1, 1))
-- debug
render.draw_debug3d()

-- render GUI
--
local camera_gui = state.cameras.camera_gui
render.set_view(camera_gui.view)
render.set_projection(camera_gui.proj)
render.enable_state(render.STATE_STENCIL_TEST)
render.draw(self.gui_pred)
render.draw(self.text_pred)
render.draw(predicates.gui, camera_gui.frustum)
render.draw(predicates.text, camera_gui.frustum)
render.disable_state(render.STATE_STENCIL_TEST)

render.set_depth_mask(false)
render.draw_debug2d()
end
```

Expand All @@ -120,14 +124,19 @@ end
이 렌더 스크립트 또한 Defold의 메세지 전달 세상에서는 보통의 시민들과 다를 바 없습니다. 그냥 렌더 스크립트에 on_message() 함수를 정의하는 것으로 게임의 다른 파트에서 렌더 스크립트의 동작에 영향을 주도록 하면 됩니다. 렌더 스크립트에 정보를 보내는 외부 오브젝트에 대한 예제로는 카메라 컴포넌트가 있습니다(자세한 내용은 [Camera](/manuals/camera) 문서 참고). 카메라 포커스가 있는 카메라 컴포넌트는 자동적으로 렌더 스크립트에 view와 projection을 보내고 있습니다. 반면 일반 스크립트에서 렌더 스크립트와 통신하려면 특수한 소켓인 @render를 사용하면 됩니다.

```lua
local MSG_CLEAR_COLOR = hash("clear_color")
local MSG_WINDOW_RESIZED = hash("window_resized")
local MSG_SET_VIEW_PROJ = hash("set_view_projection")

function on_message(self, message_id, message)
if message_id == hash("clear_color") then
if message_id == MSG_CLEAR_COLOR then
-- 어디선가 클리어 컬러(clear color) 메세지를 보냄
self.clear_color = message.color
elseif message_id == hash("set_view_projection") then
elseif message_id == MSG_SET_VIEW_PROJ then
-- 카메라 포커스를 가진 카메라 컴포넌트가 @render 소켓으로 set_view_projection 메세지를 보냄. 렌더링의 view(그리고 사용가능한 projection)를 설정하기 위한 카메라 정보를 사용할 수 있음
-- 현재, 직교 상태로(orthogonally) 렌더링 중이므로 카메라 투영(projection)이 필요 없음
self.view = message.view
camera.view = message.view
self.camera_projection = message.projection or vmath.matrix4()
update_camera(camera, state)
end
end
```
Expand All @@ -142,8 +151,10 @@ msg.post("@render:", "clear_color", { color = vmath.vector4(0.3, 0.4, 0.5, 0) })
@render 소켓은 몇 가지 내장 메세지를 가지고 있습니다. 우선, 윈도우 사이즈가 변경되었을 경우 엔진이 보내주는 window_resized 메세지가 있습니다. 데스크탑에서는 게임 창 크기가 조절될 경우, 모바일에서는 orientation이 바뀔 경우 이 메세지가 전달됩니다.

```lua
local MSG_WINDOW_RESIZED = hash("window_resized")

function on_message(self, message_id, message)
if message_id == hash("window_resized") then
if message_id == MSG_WINDOW_RESIZED then
-- 윈도우가 리사이징 됨. 새 크기가 message.width와 message.height에 포함됨
...
end
Expand Down
Loading

0 comments on commit 24b0ec4

Please sign in to comment.