多くのビジュアルノベルのように Rend'Py では 2 次元の矩形画像が主に使用されていますが、内部には近代的な GPU に見られる機能を利用できるようにしたモデルベースのレンダラーがあります。これにより他では出来ない多くのビジュアルエフェクトを可能にします。
警告すると、これは Ren'Py の最も高度な機能の1つです。多くの場合でモデルベースのレンダリングが背後でどのように動いているかを理解する必要はなく、 matrixcolor
や Live2D のような機能のサポートはモデルベースのレンダリングの動作を理解しなくても使用できます。しかし理解すればそのような機能を追加できるでしょう。このドキュメントはかなり高度な制作者または Ren'Py 本体に機能を追加したい開発者を対象とします。
Ren'Py 7.4 (2020) では、モデルベースのレンダリングの使用には有効化する必要があります。これは config.gl2 を True にして実行されます。
define config.gl2 = True
config.gl2
= False linkTrue なら、 Ren'Py はデフォルトでモデルベースのレンダラーを使用します。
近い将来、モデルベースのレンダラーが唯一のレンダラーになると期待されているので、このドキュメントの残りの部分はモデルベースのレンダリングが常に有効である前提で書かれています。
モデルベースのレンダリングは Ren'Py の最も高度な機能の1つであり、このドキュメントは先に OpenGL, OpenGL ES, GLSL ES のマニュアルを読んでおかなければ理解が難しいでしょう。さらに直接 GPU ドライバーに渡される部分があり、それらは間違った入力も受け付けてしまうので、複数種類のハードウェアでのチェックが重要となります。
Ren'Pyが画面に描画する基本的なものはモデルです。モデルは次の要素で構成されます :
1つ以上の三角形のメッシュ。三角は3つの角となる頂点で構成され、それぞれ2次元、または三次元の位置を格納し、追加情報を持つ場合もあります。追加情報の多くはテクスチャの座標です。
0枚以上のテクスチャー。ゲームで動作可能な正確な枚数は GPU によって制限されます。すべての GPU は 1 つのモデルにつき最低 3 つのテクスチャをサポートするはずです。テクスチャとは GPU に直接または render-to-texture 操作でロードされた 画像データを含む矩形のことです。
シェーダーパーツ名の一覧。Ren'Py はこれらのシェーダーパーツを使って、モデルをレンダリングするために GPU 上で実行されるプログラムであるシェーダーを作成します。シェーダーパーツの名前の前に "-" をつけると、そのシェーダーパーツを使用しないようにできます。
uniform 値。 uniform は、そのモデル全体で同じである追加データのです。例えば、モデルが solid カラーを表現するなら、その色は uniform です。
GL プロパティー。GL プロパティーは minification/magnification モードやカラーマスクのようなレンダリング方法をさらに制御するためのフラグです。
Ren'Py は通常複数のものを画面に描画するので、 Render
オブジェクトのツリーを作成します。これらのレンダーオブジェクトは、モデルや他のレンダーを子として持てます ( 後述するように、レンダーオブジェクトをモデルにもできます)。レンダーは以下のものを含みます。 :
各子に対して適用される2次元のオフセットを含む子のリスト
3次元空間において、子がどのように transform されるかを記述した Matrix
描画時にModelに適用されるシェーダーパーツ名のリスト、uniform、GLプロパティー
ポリゴンを切り取る描画可能空間が更新されるべきかどうかを決定するフラグ。
Ren'Py は、レンダーのツリーを深度優先で探索し、モデルに出会うまで画面を描画します。この探索の間、Ren'Pyはモデルの位置を transform する matrix, ポリゴンの切り取り、シェーダーパーツのリスト、uniform、gl プロパティーを更新します。この探索の過程で Model に遭遇すると、適切なシェーダプログラムが GPU 上で起動され、すべての情報が渡され、描画処理が実行されます。
Ren'Py は通常の操作の一環として、自動的にモデルを作成します。モデルがどこで作られるかを理解する主な理由は、モデルが描画操作に対応し、それゆえシェーダーが適用される単位となるからです。
これらはメッシュを持つモデルを作成し、そのメッシュには画像の矩形をカバーする2つの三角形を含みます。そのメッシュにはテクスチャ座標も含みます。このモデルは "renpy.texture" シェーダを使用します。
Solid()
Solid Displayable は 2 つの三角形を含むメッシュを作成し、テクスチャ座標はありません。このモデルは "renpy.solid "シェーダーを使用し、その色は u_renpy_solid_color
の uniform に配置されています。
Dissolve()
, ImageDissolve()
, AlphaDissolve()
, Pixellate()
, AlphaMask()
, Flatten()
これらの transform と Displayable はそれぞれその目的に必要なメッシュ、シェーダー、 uniform を持つモデルを作成します。
Live2D Displayable はレンダリング時に複数のモデルを作成し一般的にレイヤーごとに1つのモデルがあります。
Transform()
and ATLmesh
が True または blur
が使用されているなら、 Transform はモデルを作成します。この場合、Transform の子はテクスチャにレンダリングされ、そのモデルに関連するメッシュとして最初のテクスチャのメッシュが使用されます。
すべての transform がモデルを作成するわけではありません。いくつかの transform は単に Render にシェーダーや uniform を追加するだけです ( blur
や alpha
を使用する transform など ) 。その他の transform は単純にジオメトリに影響を与えるものです。
Render
transform は mesh
attribute が True ならモデルを作成します。この場合、その Render の子はテクスチャにレンダリングされ、そのモデルに関連するメッシュとして最初のテクスチャのメッシュが使用されます。
将来的にモデルを作成するさらに他の方法が Ren'Py に追加されると期待されます。
Ren'Py はまずシェーダーパーツ名のリストを組み立てて、シェーダープログラムを生成します。このリストは、 "renpy.geometry", レンダーから取得したシェーダーパーツのリスト、描画中のModelにあるシェーダーパーツのリストで構成されています。
その後、シェーダーパーツは重複排除されます。 "-" で始まるシェーダーパーツはリストから削除され、先頭の "-" を除いたものと同じシェーダーパーツも削除されます ( つまり "-renpy.geometry" はそれ自身と "renpy.geometry" を削除します ) 。
続いて Ren'Py は、シェーダーパーツのリストを受け取り、変数、関数、 vertex シェーダーパーツ、フラグメントシェーダーパーツのリストを取得します。これらは順番にシェーダーのソースコード生成に使われます。 vertex シェーダーとフラグメントシェーダーのパーツは、番号の小さいものから大きいものへと優先順位をつけて含まれます。
つまり、あるシェーダで作成された変数は、そのシェーダパーツのリストにある他のシェーダからのあらゆるフラグメントからアクセスできるようになります。 Python の関数のように、シェーダ間の干渉を防ぐためのスコープは存在しません。
Ren'Py はこれまでに使用されたすべてのシェーダーパーツの組み合わせを game/cache/shaders.txt にキャッシュしておき、起動時にそれらを読み込みます。シェーダーの使用に大きな変更があった場合は、このファイルを編集または削除して、有効なデータで再作成できるようするべきです。
renpy.register_shader 関数を呼び出して GLSL シェーダーの部品を提供すると新しいシェーダーパーツが作成できます。
一般的に、シェーダーパーツは "mygame.recolor" や "mylibrary.warp" のような "namespace.part" の形式であるべきです。 "renpy." や "live2d." で始まる名前は _ で始まる始まるもの同様に Ren'Py で予約されています。
renpy.
register_shader
(name, **kwargs) linkこれはシェーダーパーツの登録をします。 name とその後に続くキーワード引数を受け取ります。
登録するシェーダーパーツの名前の文字列です。アンダースコアや "renpy." で始まる名前は Ren'Py で予約されています。
登録するシェーダーパーツで使用される変数です。これらは行ごとに (uniform や attribute, varying のような)ストレージに続いて、型、セミコロンとなるべきです。例
variables='''
uniform sampler2D tex0;
attribute vec2 a_tex_coord;
varying vec2 v_tex_coord;
'''
指定するなら vertex シェーダーに含まれる関数を含める文字列です。
指定するなら fragment シェーダーに含まれる関数を含める文字列です。
他のキーワード引数は "fragment_200" や "vertex_300" のように vertex_
や fragment_
から始まり、優先度を表す数値で終わるべきです。これらは優先度の数値順に適切なシェーダーに配置されるテキストを指定します。
Ren'Py では次の型の変数のみをサポートします。 :
float (Python float)
vec2 (2つの浮動小数のタプル)
vec3 (3 つの浮動小数のタプル)
vec4 ( 4 つの浮動小数のタプル)
mat4 (Matrix
)
sampler2D (Ren'Py 提供 )
Uniform 変数は u_ で、 attribute は a_, varying 変数 は v_ で始めるべきです。 u_renpy_ や a_renpy、v_renpy で始まる変数は後述する標準的な変数同様に予約されています。
優先順位に対する基本的な考え方としては、優先度 100 でジオメトリを設定し、優先度 200 で初期のフラグメントカラー(gl_FragColor)を決定し、より高い番号の優先度ではその色を変更するエフェクトを適用できます。
こちらはレンダリングに使用される各モデルにグラデーションを適用するカスタムシェーダーパーツの例です。
init python:
renpy.register_shader("example.gradient", variables="""
uniform vec4 u_gradient_left;
uniform vec4 u_gradient_right;
uniform vec2 u_model_size;
varying float v_gradient_done;
attribute vec4 a_position;
""", vertex_300="""
v_gradient_done = a_position.x / u_model_size.x;
""", fragment_300="""
float gradient_done = v_gradient_done;
gl_FragColor *= mix(u_gradient_left, u_gradient_right, gradient_done);
""")
これによりカスタムシェーダーが transform を使用して適用できます。
transform gradient:
shader "example.gradient"
u_gradient_left (1.0, 0.0, 0.0, 1.0)
u_gradient_right (0.0, 0.0, 1.0, 1.0)
show eileen happy at gradient
前述したように、example.gradient シェーダの gradient_done
変数は、同じリストから適用される他のすべてのシェーダからアクセス可能になります。これは、あるシェーダシステムにオプションのパーツがある場合に便利ですが、独立した2つのシェーダを使用する場合に名前の衝突を引き起こす可能性もあります。
カスタムシェーダーのデバッグに役立つ変数があります。 :
config.log_gl_shaders
= False linkTrue なら GLSL シェーダープログラム用のソースコードが起動時に log.txt に書き加えられます。
モデルベースのレンダリングは次のプロパティーを ATLと Transform()
に追加します :
mesh
linkType: | None or True or tuple |
---|---|
Default: | None |
None でなければ、この Transform はモデルとしてレンダリングされます。 つまり :
メッシュが作成されます。これが 2 要素のタプルなら、 x 方向と y 方向のメッシュ内のポイント数として取得されます(各次元で少なくとも 2 でなければいけません)。 True の場合、そのメッシュは子から取得されます。
この transform の子はテクスチャにレンダリングされます。
renpy.texture シェーダーが追加されます。
mesh_pad
linkType: | None or tuple |
---|---|
Default: | None |
None でない場合、これは 2 成分または 4 成分のタプルにです。 mesh が True でこれが与えられた場合、これはメッシュで使用されるテクスチャに適用されるテクスチャのサイズにパディングを適用します。 2 成分ののタプルは右と下にパディングを適用し、4成分のタプルは左、上、右、下にパディングを適用します。
gl_pixel_perfect
プロパティーと組み合わせるとメッシュにテキストをレンダリングできます。 Ren'Py においてテキストは画面の解像度で描画されるため、メッシュに適用されるテクスチャの境界を越える可能性があります。数ピクセルのパディングを追加すると、テクスチャはより大きくなり、すべてのピクセルが表示されるようになります。例
transform adjust_text:
mesh True
mesh_pad (10, 0)
gl_pixel_perfect True
shader "shaders.adjust_text"
上記はそのシェーダーに渡されるテクスチャに、そのテキストのすべてのピクセルを含むことを保証します。
shader
linkType: | None or str or list of str |
---|---|
Default: | None |
None またはこのレンダーを通して到達するモデル、 ( モデルが作成されるなら ) このレンダーに適用されるシェーダーパーツ名、シェーダーパーツ名のリストです。
blend
linkType: | None or str |
---|---|
Default: | None |
None または文字列です。この文字列が config.gl_blend_func
で検索され、gl_blend_func プロパティーの値を取得します。ブレンドモードの変更に使用されます。
サポートしているデフォルトのブレンドモードは "normal", "add", "multiply", "min", and "max" です(それぞれ通常、加算、乗算、比較(暗), 比較(明) の合成モードに相当します)。
加えて、 u_renpy でない u_ で始まる uniform は Transform プロパティーとして利用できます。 GL プロパティー は gl_ で始めると Transformプロパティとして利用できるようになります。例えば color_mask プロパティは gl_color_mask として利用可能です。
config.gl_blend_func
= { ... } linkブレンドモード名をブレンド関数に対応付ける辞書です。ブレンドモードは、後述する blend_func プロパティに提供されます。
デフォルトのブレンドモードです
gl_blend_func["normal"] = (GL_FUNC_ADD, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_FUNC_ADD, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
gl_blend_func["add"] = (GL_FUNC_ADD, GL_ONE, GL_ONE, GL_FUNC_ADD, GL_ZERO, GL_ONE)
gl_blend_func["multiply"] = (GL_FUNC_ADD, GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA, GL_FUNC_ADD, GL_ZERO, GL_ONE)
gl_blend_func["min"] = (GL_MIN, GL_ONE, GL_ONE, GL_MIN, GL_ONE, GL_ONE)
gl_blend_func["max"] = (GL_MAX, GL_ONE, GL_ONE, GL_MAX, GL_ONE, GL_ONE)
次の uniform はすべてのモデルで利用可能です。
vec2 u_model_size
モデルの幅と高さ
float u_lod_bias
テクスチャ参照に適用される詳細バイアスのレベルです。これは Transform で設定されるかもしれません。デフォルト値は config.gl_lod_bias
から取得され、デフォルトでは -0.5 です。この値は Ren'Py が常に次の大きなレベルを選択して、それをスケールダウンするようにバイアスをかけます。
mat4 u_transform
仮想ピクセルを OpenGL ビューポートに投影するのに使用される transform です。
float u_time
そのフレームの時間です。エポックは未定義なので秒ごとに増える数値として扱うとよいです。この時間は 86400 の剰余なので、一日ごとに 0.0 にリセットされます。
vec4 u_random
フレームごとに (非常に高い確率で) 異なる 0.0 から 1.0 の間の 4 つの乱数です。
vec4 u_viewport
これは現在内部に描画が行われている viewport を指定します。 u_viewport.xy は ウィンドウの左下隅を基準にした viewport の左下隅の座標です。 u_viewport.pq はその viewport の幅と高さを表します。
sampler2D tex0
, sampler2D tex1
, sampler2D tex2
テクスチャが利用可能なら、対応するサンプラーがこの変数に格納されます。
vec2 res0
, vec2 res1
, vec2 res2
テクスチャが利用可能なら、そのテクスチャのサイズがこれらの変数に格納されます。テクスチャがディスクから読み込まれたときはこれは画像ファイルのサイズで、テクスチャにレンダリングされた後はレンダリングされたテクスチャ上で描画されるピクセルの数です。
次の attribute はすべてのモデルで利用可能です :
vec4 a_position
レンダリングされた頂点の位置
テクスチャが利用可能なら、次の attribute も使用可能です :
vec2 a_tex_coord
この頂点を投影するテクスチャ内部の座標です。
GLプロパティーは、OpenGLやモデルベースのレンダラのグローバルな状態を変更します。これらのプロパティは Transform や Render.add_property()
関数で使用できます。
gl_blend_func
あればこれは6要素のタプルが期待され、すでに描画されているピクセルと描画するピクセルを合成する方程式と、その方程式のパラメータを設定するために使用されます。
具体的にはこれは (rgb_equation, src_rgb, dst_rgb, alpha_equation, src_alpha, dst_alpha) です。これらは次の呼び出しで使用されます。
glBlendEquationSeparate(rgb_equation, alpha_equation)
glBlendFuncSeparate(src_rgb, dst_rgb, src_alpha, dst_alpha)
これらの関数が何をしているかは OpenGLのドキュメントを参照してください。OpenGL 定数は renpy.uguu からインポートできます。
init python:
from renpy.uguu import GL_ONE, GL_ONE_MINUS_SRC_ALPHA
一般的に blend
transform プロパティーがこれを使用する簡単な方法です。
gl_color_mask
これには、ピクセルの4つのチャンネル(赤、緑、青、アルファ)に対応する真偽値の4タプルが期待されます。あるチャンネルが True であれば、描画処理でそのピクセルに書き込みます。そうでなければ、描画は行われません。
gl_depth
True の場合、 深度バッファをクリアし、この Displayable とこの Displayable の子に対して z バッファ法でのレンダリングを有効にします。
透明なピクセルであっても、任意のピクセルを描画すると、深度バッファが更新されることに注意してください。そのため透明度のある画像に使用すると、予期せぬ問題が発生する可能性があります( 別の方法として show
ステートメントの zorder
や behind
節を検討してください)。
gl_pixel_perfect
True のとき、Ren'Py はメッシュの最初の頂点が画面上のピクセルと一致するように移動します。これは主にテキストと組み合わせて、テキストがシャープに保たれるようにするために使用されます。
次のプロパティーは、 mesh
が設定された Transform または Model()
によってテクスチャが作成されるときのみ、プロパティメソッドに渡され効果を持ちます。
gl_drawable_resolution
True または設定されていない場合、テクスチャーはウィンドウがゲームを表示しているのと同じ解像度でレンダリングされます。 False ならその Displayable の仮想解像度でレンダリングされます。
gl_anisotropic
与えられた場合、これはメッシュに渡されるテクスチャが異方性で作成されてるかどうかを判断します。異方性とは、テクスチャーが X と Y で異なる量だけズームされたときに、複数のテクセル(テクスチャピクセル)がサンプリングされる機能です。
これはデフォルトでは True です。 Ren'Py は Pixellate のような特定のエフェクトのためにこれを False に設定します。
gl_mipmap
与えられた場合、これはメッシュに渡されるテクスチャがミップマップで作成されるかどうかを決定します。デフォルトは True です。
gl_texture_wrap
与えられた場合、これはメッシュに適用されるテクスチャがどのようにラップされるかを決定します。これには2要素のタプルが期待され、最初の要素は GL_TEXTURE_WRAP_S を、 2番目の要素は GL_TEXTURE_WRAP_T を設定するために用いられます。これらは通常、作成されたテクスチャの X 軸と Y 軸を表します。
値は OpenGL に含まれ、 renpy.uguu からインポートされます。
init python:
from renpy.uguu import GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT, GL_REPEAT
モデル Displayable はモデルベースのレンダラーで使用するためのモデルを作成するのに役立ちます。
Model
(size=None, **properties) linkこれは Ren'Py にモデルベースのレンダラーで使用する 2D や 3D のモデルを作成させる Displayable であり、ここで指定したシェーダーを使用して単一の処理により、または囲んでいるTransform や Displayable によって選択されて描画されます。
None でなければ幅と高さのタプルで、そのモデルのサイズを指定するのに使用されます。指定されないと、そのモデルは与えられた領域のサイズになります。テクスチャへの fit パラメータがより優先されます。
mesh メソッドが呼び出されない場合、少なくとも1つのテクスチャを与えられれば Ren'Py がテクスチャをロードする方法に合わせて a_position と a_tex_coord を設定するメッシュが作成され、そうでなければ a_position のみを設定するメッシュが使用されます。
このクラスのすべてのメソッドはそのメソッドが呼び出された Displayable を返すのでチェーン呼び出しが出来ます。
child
(displayable, fit=False) linkこれは focus と main パラメーターが True に設定される他は texture メソッドと同じです。
grid_mesh
(width, height) linkwidth x height の等間隔のポイントを持つグリッドで構成されるメッシュを作成し、各ポイントを垂直および水平方向の最も近いポイントに接続し、作成されたグリッド内の各長方形を三角形に分割します。
水平、垂直方法のポイント数で、少なくとも2以上の整数です。
property
(name, value) linkgl プロパティーの値を設定します。
GL プロパティーの名前を指定する文字列で、 "gl_" 接頭辞を含みます。
gl プロパティーの値
shader
(shader) linkこのモデルにシェーダーを追加します。
このモデルで使用するシェーダーの名前の文字列です。
texture
(displayable, focus=False, main=False, fit=False) link指定の Displayable をレンダリングしてこのモデルにテクスチャを追加します。追加される最初のテクスチャは tex0
で、 2つ目は tex1
と続きます。
True なら、フォーカスイベントがその Displayable に渡されます。ここではそのモデルに対する相対座標がその Displayable に帯する相対座標と 1:1 で対応すると想定しています。
True なら、これは Displayable インスペクターに検知されるこの Displayable のメインの子としてマークされます。
True なら、モデルにはその Displayable のサイズが指定されます。これは1つのテクスチャに対してのみ True でしょう。
uniform
(name, value) linkシェーダーに渡される uniform の値を設定します。
uniform の名前の文字列で、 "u_" を接頭辞に持ちます。
uniform の値です。浮動小数、浮動小数の2, 3, 4要素のタプルまたはマトリックスです。
このモデル Displayable は、ATL transform と組み込みのシェーダを組み合わせてディゾルブ transform 作成に使用できます。
transform dt(delay=1.0, new_widget=None, old_widget=None):
delay delay
Model().texture(old_widget).child(new_widget)
shader [ 'renpy.dissolve' ]
u_renpy_dissolve 0.0
linear delay u_renpy_dissolve 1.0
モデル Displayable を Displayable の子に使用すると 2つ共が Ren'Py 内にモデルを作成するので、 mesh
と互換性がなくなります。
Variables:
uniform mat4 u_transform;
attribute vec4 a_position;
Vertex shader:
gl_Position = u_transform * a_position;
Variables:
uniform sampler2D tex0;
attribute vec2 a_tex_coord;
varying vec2 v_tex_coord;
uniform float u_renpy_blur_log2;
Vertex shader:
v_tex_coord = a_tex_coord;
Fragment shader:
gl_FragColor = vec4(0.);
float renpy_blur_norm = 0.;
for (float i = -5.; i < 1.; i += 1.) {
float renpy_blur_weight = exp(-0.5 * pow(u_renpy_blur_log2 - i, 2.));
renpy_blur_norm += renpy_blur_weight;
}
gl_FragColor += renpy_blur_norm * texture2D(tex0, v_tex_coord.xy, 0.);
for (float i = 1.; i < 14.; i += 1.) {
if (i >= u_renpy_blur_log2 + 5.) {
break;
}
float renpy_blur_weight = exp(-0.5 * pow(u_renpy_blur_log2 - i, 2.));
gl_FragColor += renpy_blur_weight * texture2D(tex0, v_tex_coord.xy, i);
renpy_blur_norm += renpy_blur_weight;
}
if (renpy_blur_norm > 0.0) {
gl_FragColor /= renpy_blur_norm;
} else {
gl_FragColor = texture2D(tex0, v_tex_coord.xy, 0.0);
}
Variables:
uniform float u_lod_bias;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform float u_renpy_dissolve;
attribute vec2 a_tex_coord;
varying vec2 v_tex_coord;
Vertex shader:
v_tex_coord = a_tex_coord;
Fragment shader:
vec4 color0 = texture2D(tex0, v_tex_coord.st, u_lod_bias);
vec4 color1 = texture2D(tex1, v_tex_coord.st, u_lod_bias);
gl_FragColor = mix(color0, color1, u_renpy_dissolve);
Variables:
uniform float u_lod_bias;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform float u_renpy_dissolve_offset;
uniform float u_renpy_dissolve_multiplier;
attribute vec2 a_tex_coord;
varying vec2 v_tex_coord;
Vertex shader:
v_tex_coord = a_tex_coord;
Fragment shader:
vec4 color0 = texture2D(tex0, v_tex_coord.st, u_lod_bias);
vec4 color1 = texture2D(tex1, v_tex_coord.st, u_lod_bias);
vec4 color2 = texture2D(tex2, v_tex_coord.st, u_lod_bias);
float a = clamp((color0.a + u_renpy_dissolve_offset) * u_renpy_dissolve_multiplier, 0.0, 1.0);
gl_FragColor = mix(color1, color2, a);
Variables:
uniform vec4 u_renpy_solid_color;
Fragment shader:
gl_FragColor = u_renpy_solid_color;
Variables:
uniform float u_lod_bias;
uniform sampler2D tex0;
attribute vec2 a_tex_coord;
varying vec2 v_tex_coord;
Vertex shader:
v_tex_coord = a_tex_coord;
Fragment shader:
gl_FragColor = texture2D(tex0, v_tex_coord.xy, u_lod_bias);
Variables:
uniform mat4 u_renpy_matrixcolor;
Fragment shader:
gl_FragColor = u_renpy_matrixcolor * gl_FragColor;
Variables:
uniform float u_renpy_alpha;
uniform float u_renpy_over;
Fragment shader:
gl_FragColor = gl_FragColor * vec4(u_renpy_alpha, u_renpy_alpha, u_renpy_alpha, u_renpy_alpha * u_renpy_over);