【Defold】パーティクルの手前にスプライトを表示する

Defold, DEVELOP

レンダラーをカスタマイズすると、パーティクルの手前にスプライトを表示することが出来ます。

初期設定の確認

Defoldが表示するゲームオブジェクトの描画順のスクリプトは[builtins]-[render]->[default.render_script]から確認できます。

function init(self)
    self.tile_pred = render.predicate({"tile"})
    self.gui_pred = render.predicate({"gui"})
    self.text_pred = render.predicate({"text"})
    self.particle_pred = render.predicate({"particle"})
end
function update(self)
    -- 事前処理
    --
    -- 描画
    --
    render.draw(self.tile_pred)
    render.draw(self.particle_pred)
    render.draw_debug3d()
    -- 後処理
    --
end

ソースコードを読むとパーティクルはtile_predの後にまとめて描画する様になっています。Defoldは、この初期スクリプトを簡単に変更できます。

確認バージョン

1.2.158

カスタムレンダラーに変更する

初期状態のdefault.renderとcustom.render_scriptをカスタムレンダラーへ差し替えることから始めます。

※こちらの記事が参考になりました。

デフォルトではパーティクルはスプライトの上に表示されるが、スプライトの下にパーティクルを表示したい。
Renderをカスタマイズして、スプライトの下に表示されるパーティクルを追加しようとしたが失敗。
パーティクルの上に表示されるスプライト(マテリアル)を作成したら上手く行ったのでメモ。

Defold:スプライトの下にパーティクルを表示する | devlog [naru design]

custom.render_script の作成

Assetsビューにrenderフォルダを作成します。renderフォルダを右クリック->[New…]->[Render Script]からcustom.render_scriptを作成します。スクリプト処理が空なので、 default.render_scriptの中身を丸ごとコピーし貼り付けます。

--
-- projection that centers content with maintained aspect ratio and optional zoom
--
local function fixed_projection(near, far, zoom)
	local projected_width = render.get_window_width() / (zoom or 1)
	local projected_height = render.get_window_height() / (zoom or 1)
	local xoffset = -(projected_width - render.get_width()) / 2
	local yoffset = -(projected_height - render.get_height()) / 2
	return vmath.matrix4_orthographic(xoffset, xoffset + projected_width, yoffset, yoffset + projected_height, near, far)
end
--
-- projection that centers and fits content with maintained aspect ratio
--
local function fixed_fit_projection(near, far)
	local width = render.get_width()
	local height = render.get_height()
	local window_width = render.get_window_width()
	local window_height = render.get_window_height()
	local zoom = math.min(window_width / width, window_height / height)
	return fixed_projection(near, far, zoom)
end
--
-- projection that stretches content
--
local function stretch_projection(near, far)
	return vmath.matrix4_orthographic(0, render.get_width(), 0, render.get_height(), near, far)
end
local function get_projection(self)
	return self.projection_fn(self.near, self.far, self.zoom)
end
function init(self)
	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.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)
	self.view = vmath.matrix4()
	-- default is stretch projection. copy from builtins and change for different projection
	-- or send a message to the render script to change projection:
	-- msg.post("@render:", "use_stretch_projection", { near = -1, far = 1 })
	-- msg.post("@render:", "use_fixed_projection", { near = -1, far = 1, zoom = 2 })
	-- msg.post("@render:", "use_fixed_fit_projection", { near = -1, far = 1 })
	self.near = -1
	self.far = 1
	self.projection_fn = stretch_projection
end
function update(self)
	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.set_viewport(0, 0, render.get_window_width(), render.get_window_height())
	render.set_view(self.view)
	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.set_projection(get_projection(self))
	render.draw(self.tile_pred)
	render.draw(self.particle_pred)
	render.draw_debug3d()
	-- render GUI
	--
	render.set_view(vmath.matrix4())
	render.set_projection(vmath.matrix4_orthographic(0, render.get_window_width(), 0, render.get_window_height(), -1, 1))
	render.enable_state(render.STATE_STENCIL_TEST)
	render.draw(self.gui_pred)
	render.draw(self.text_pred)
	render.disable_state(render.STATE_STENCIL_TEST)
end
function on_message(self, message_id, message)
	if message_id == hash("clear_color") then
		self.clear_color = message.color
	elseif message_id == hash("set_view_projection") then
		self.view = message.view
		self.projection = message.projection
	elseif message_id == hash("use_camera_projection") then
		self.projection_fn = function() return self.projection or vmath.matrix4() end
	elseif message_id == hash("use_stretch_projection") then
		self.near = message.near or -1
		self.far = message.far or 1
		self.projection_fn = stretch_projection
	elseif message_id == hash("use_fixed_projection") then
		self.near = message.near or -1
		self.far = message.far or 1
		self.zoom = message.zoom or 1
		self.projection_fn = fixed_projection
	elseif message_id == hash("use_fixed_fit_projection") then
		self.near = message.near or -1
		self.far = message.far or 1
		self.projection_fn = fixed_fit_projection
	end
end

コピー出来たら、initとupdateにコードを追加します。

function init(self)
	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.above_particle_pred = render.predicate({"above_particle"})
end
function update(self)
	render.draw(self.tile_pred)
	render.draw(self.particle_pred)
    -- 追加
	render.draw(self.above_particle_pred)
	render.draw_debug3d()
end

custom.renderの作成

custom.render_scriptと同様に、renderフォルダを右クリック->[New…]->[Render]からcustom.renderを作成します。 custom.render を開きScriptをプロパティにcustom.render_scriptを設定します。

レンダラーの変更

game.projectのレンダラーをcustom.renderへ変更します。

マテリアルの作成

  • Assetsビューにmaterialsフォルダを作成します。[builtins]-[materials]フォルダのsprite.materialをAssetsビューのmaterialsフォルダへコピーします。ファイル名は sprite_above_particle. materialに変更します。
  • sprite_above_particle.materialを開き、Tagsプロパティをabove_particleに変更します。

GameObjectへマテリアルを割り当てる

パーティクルより手前に表示したいスプライトのMaterialをsprite_above_particle.materialへ変更します。

実行結果

Posted by kazupon