【Defold】カラーグレーディングに対応する

2020/07/12Defold, DEVELOP

Defold で画面全体の色調補正を実装してみます。公式サイトの Grading shader tutorial の通りに実装すると簡単に実装できます。

目次

手順

それではチュートリアルを参考にしながら進めてみます。カラーグレーディングに対応する以前はこの様な見た目のシーンを用意しました。

カスタムレンダラーの設定

まず画面を描画するスクリプトを差し替える所から始めます。 /builtins/render/default.render_script をコピーしてmain フォルダ以下に配置します。ファイル名は custom.render_script とします。同様に /builtins/render/default.render をコピーして main フォルダ以下に配置します。ファイル名は custom.render とします。

custom.render を開き Script を custom.render_script へ変更します。

game.project を開き Boostrap の Render をcustom.render へ変更します。 これで、カスタムレンダラーの設定が完了します。

スクリプトの修正

custom.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"})
    -- 追加
    self.grade_pred = render.predicate({"grade"})
 
    ...
 
    -- 追加
    local color_params = { format = render.FORMAT_RGBA,
    width = render.get_width(),
    height = render.get_height() } -- <1>
    local target_params = {[render.BUFFER_COLOR_BIT] = color_params }
 
    self.target = render.render_target("original", target_params)
    -- ここまで追加
end

init でオフスクリーンレンダーターゲットを作成します。画面外・裏で描き込む用のバッファです。次にupdate でそれを使う形に書き換えます。

function update(self)
 
    -- 追加
    render.enable_render_target(self.target)
    
    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_width(), render.get_height())
--  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.disable_render_target(self.target)
 
    -- 追加
    render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color})
 
    render.set_viewport(0, 0, render.get_window_width(), render.get_window_height())
    render.set_view(vmath.matrix4())
    render.set_projection(vmath.matrix4())
 
    render.enable_texture(0, self.target, render.BUFFER_COLOR_BIT)
    render.draw(self.grade_pred)
    render.disable_texture(0, self.target)
    -- ここまで 追加
 
    -- 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

update の変更内容としては オフスクリーンレンダーターゲットに描き込んだ後、結果を grade_pred のターゲットとなるGameObject(画面全体描画用) に反映します。最終的に色調補正後の grade_pred ターゲットとなるGameObject を画面に表示する形となります。スクリプトの修正はこれで完了です。

画面を埋めるもの

レンダー ターゲットのカラー バッファのピクセルを画面に描画するには、ピクセル データでテクスチャを処理できる設定が必要です。そのために、平坦な2次3Dモデルを使用します。Blender などで作成するのも良いでしょう。作成する方法が分からない様であれば こちら からダウンロードして使うこともできます。ダウンロードできたら解凍し main フォルダ以下に配置します。

カラーグレーディング用のマテリアルを作成する

色調補正用のマテリアルを作成します。main フォルダに grade.material、grade.vp(頂点シェーダー)、grade.fp(フラグメントシェーダー)を作成します。

また、色調補正用のテクスチャも公式のチュートリアルからダウンロードしておくと良いでしょう。

こんなやつです。ファイル名はlut16.ong

grade.material を開き各種項目を設定します。イメージと同じ設定にしておくと問題ないでしょう。

シェーダーファイルの編集

頂点シェーダーとフラグメントシェーダーを編集します。

// grade.vp
uniform mediump mat4 view_proj;
 
// positions are in world space
attribute mediump vec4 position;
attribute mediump vec2 texcoord0;
 
varying mediump vec2 var_texcoord0;
 
void main()
{
    gl_Position = view_proj * vec4(position.xyz, 1.0);
    var_texcoord0 = texcoord0;
}
varying mediump vec4 position;
varying mediump vec2 var_texcoord0;
 
uniform lowp sampler2D original;
uniform lowp sampler2D lut;
 
#define MAXCOLOR 15.0
#define COLORS 16.0
#define WIDTH 256.0
#define HEIGHT 16.0
 
void main()
{
    vec4 px = texture2D(original, var_texcoord0.xy);
 
    float cell = px.b * MAXCOLOR;
 
    float cell_l = floor(cell);
    float cell_h = ceil(cell);
 
    float half_px_x = 0.5 / WIDTH;
    float half_px_y = 0.5 / HEIGHT;
    float r_offset = half_px_x + px.r / COLORS * (MAXCOLOR / COLORS);
    float g_offset = half_px_y + px.g * (MAXCOLOR / COLORS);
 
    vec2 lut_pos_l = vec2(cell_l / COLORS + r_offset, g_offset);
    vec2 lut_pos_h = vec2(cell_h / COLORS + r_offset, g_offset);
 
    vec4 graded_color_l = texture2D(lut, lut_pos_l);
    vec4 graded_color_h = texture2D(lut, lut_pos_h);
 
    vec4 graded_color = mix(graded_color_l, graded_color_h, fract(cell));
 
    gl_FragColor = graded_color;
}

main.collection にモデルを配置する

main.collection にカラーグレーディング用のモデルをモデルを配置します。空のGameObject を作成し名前を grade とします。grade オブジェクトには model コンポーネントを追加します。model コンポーネントの中身は以下の様になっています。

ここまで出来ると、色調補正が反映される状態になっています。

実行してみる

一度実行してみます。色調補正用のテクスチャは補正がかからない状態のものになっていますので、実行すると最初のイメージのまま表示されたかと思います。

見た目を変えるためには lut16.ong テクスチャをPhotoShop などで修正してあげます。例えばセピア調にしたければ

この様に編集します。テクスチャを保存し実行すると

セピア調になります。

お知らせ

Posted by kazupon