このページでは、AGSL の基本と、Android で AGSL を使用するさまざまな方法について説明します。 。
シンプルな AGSL シェーダー
シェーダーのコードは描画されたピクセルごとに呼び出され、ピクセルの
ペイントする必要があります非常にシンプルなシェーダーは、常に
単色この例では赤を使用しています。シェーダーは String
内で定義されます。
private const val COLOR_SHADER_SRC =
"""half4 main(float2 fragCoord) {
return half4(1,0,0,1);
}"""
private static final String COLOR_SHADER_SRC =
"half4 main(float2 fragCoord) {\n" +
"return half4(1,0,0,1);\n" +
"}";
次に、RuntimeShader
を作成します。
シェーダーの文字列で初期化されたオブジェクト。これにより、シェーダーもコンパイルされます。
val fixedColorShader = RuntimeShader(COLOR_SHADER_SRC)
RuntimeShader fixedColorShader = new RuntimeShader(COLOR_SHADER_SRC);
RuntimeShader
は、標準の Android シェーダーが使用できる場所で使用できます。として
たとえば、カスタム View
Canvas
。
val paint = Paint()
paint.shader = fixedColorShader
override fun onDrawForeground(canvas: Canvas?) {
canvas?.let {
canvas.drawPaint(paint) // fill the Canvas with the shader
}
}
Paint paint = new Paint();
paint.setShader(fixedColorShader);
public void onDrawForeground(@Nullable Canvas canvas) {
if (canvas != null) {
canvas.drawPaint(paint); // fill the Canvas with the shader
}
}
これにより、赤色の View
が描画されます。uniform
を使用して、色パラメータを
描画するシェーダーを指定します。まず、色 uniform
をシェーダーに追加します。
private const val COLOR_SHADER_SRC =
"""layout(color) uniform half4 iColor;
half4 main(float2 fragCoord) {
return iColor;
}"""
private static final String COLOR_SHADER_SRC =
"layout(color) uniform half4 iColor;\n"+
"half4 main(float2 fragCoord) {\n" +
"return iColor;\n" +
"}";
次に、カスタムの View
から setColorUniform
を呼び出して、目的の色を渡します。
AGSL シェーダーに統合します
fixedColorShader.setColorUniform("iColor", Color.GREEN )
fixedColorShader.setColorUniform("iColor", Color.GREEN );
これで、緑色の View
が表示されます。View
の色は、
パラメータをカスタム View
のコードから
作成します。
代わりに、カラー グラデーション効果を作成できます。まず、
シェーダーで View
解像度を入力として受け入れます。
private const val COLOR_SHADER_SRC =
"""uniform float2 iResolution;
half4 main(float2 fragCoord) {
float2 scaled = fragCoord/iResolution.xy;
return half4(scaled, 0, 1);
}"""
private static final String COLOR_SHADER_SRC =
"uniform float2 iResolution;\n" +
"half4 main(float2 fragCoord) {\n" +
"float2 scaled = fragCoord/iResolution.xy;\n" +
"return half4(scaled, 0, 1);\n" +
"}";
グラデーションの描画
このシェーダーは、ちょっとした工夫をしています。ピクセルごとに float2
が作成されます。
x 座標と y 座標を解像度で割った値を含むベクトル。
0 ~ 1 の値が作成されます。そのスケーリングされたベクトルを使用して、
戻り値の色の赤と緑のコンポーネントを作成します。
次のコマンドを呼び出して、View
の解像度を AGSL シェーダーの uniform
に渡します。
setFloatUniform
。
val paint = Paint()
paint.shader = fixedColorShader
override fun onDrawForeground(canvas: Canvas?) {
canvas?.let {
fixedColorShader.setFloatUniform("iResolution", width.toFloat(), height.toFloat())
canvas.drawPaint(paint)
}
}
Paint paint = new Paint();
paint.setShader(fixedColorShader);
public void onDrawForeground(@Nullable Canvas canvas) {
if (canvas != null) {
fixedColorShader.setFloatUniform("iResolution", (float)getWidth(), (float()getHeight()));
canvas.drawPaint(paint);
}
}

シェーダーをアニメーション化する
同様の手法を使用して、iTime
ユニフォームと iDuration
ユニフォームを受け取るようにシェーダーを変更することで、シェーダーをアニメーション化できます。シェーダーはこれらの値を使用して、
三角波を使って色をグラデーションします。
private const val DURATION = 4000f
private const val COLOR_SHADER_SRC = """
uniform float2 iResolution;
uniform float iTime;
uniform float iDuration;
half4 main(in float2 fragCoord) {
float2 scaled = abs(1.0-mod(fragCoord/iResolution.xy+iTime/(iDuration/2.0),2.0));
return half4(scaled, 0, 1.0);
}
"""
private static final float DURATION = 4000f;
private static final String COLOR_SHADER_SRC =
"uniform float2 iResolution;\n"+
"uniform float iTime;\n"+
"uniform float iDuration;\n"+
"half4 main(in float2 fragCoord) {\n"+
"float2 scaled = abs(1.0-mod(fragCoord/iResolution.xy+iTime/(iDuration/2.0),2.0));\n"+
"return half4(scaled, 0, 1.0);\n"+
"}";
カスタムビューのソースコードから、
ValueAnimator
が
iTime
ユニフォーム。
// declare the ValueAnimator
private val shaderAnimator = ValueAnimator.ofFloat(0f, DURATION)
// use it to animate the time uniform
shaderAnimator.duration = DURATION.toLong()
shaderAnimator.repeatCount = ValueAnimator.INFINITE
shaderAnimator.repeatMode = ValueAnimator.RESTART
shaderAnimator.interpolator = LinearInterpolator()
animatedShader.setFloatUniform("iDuration", DURATION )
shaderAnimator.addUpdateListener { animation ->
animatedShader.setFloatUniform("iTime", animation.animatedValue as Float )
}
shaderAnimator.start()
// declare the ValueAnimator
private final ValueAnimator shaderAnimator = ValueAnimator.ofFloat(0f, DURATION);
// use it to animate the time uniform
shaderAnimator.setDuration((long)DURATION);
shaderAnimator.setRepeatCount(ValueAnimator.INFINITE);
shaderAnimator.setRepeatMode(ValueAnimator.RESTART);
shaderAnimator.setInterpolator(new LinearInterpolator());
animatedShader.setFloatUniform("iDuration", DURATION );
shaderAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public final void onAnimationUpdate(ValueAnimator animation) {
animatedShader.setFloatUniform("iTime", (float)animation.getAnimatedValue());
}
});

複雑なオブジェクトの描画
背景全体にシェーダーを描画する必要はありません。できる
使用できるように、
Paint
オブジェクト(
drawText
。
canvas.drawText(ANIMATED_TEXT, TEXT_MARGIN_DP, TEXT_MARGIN_DP + bounds.height(),
paint)
canvas.drawText(ANIMATED_TEXT, TEXT_MARGIN_DP, TEXT_MARGIN_DP + bounds.height(),
paint);

シェーディングとキャンバスの変換
シェーディングされたテキストには、次のような追加の Canvas
変換を適用できます。
作成できます。ValueAnimator
で、3D 回転のマトリックスを更新できます。
組み込みの
android.graphics.Camera
クラス。
// in the ValueAnimator
camera.rotate(0.0f, animation.animatedValue as Float / DURATION * 360f, 0.0f)
// in the ValueAnimator
camera.rotate(0.0f, (Float)animation.getAnimatedValue() / DURATION * 360f, 0.0f);
テキストを隅からではなく中心軸から回転させるため、
テキスト境界を取得してから、preTranslate
と postTranslate
を使用して
行列を使用してテキストを翻訳し、0,0 を
画面上のテキストが描画される位置を変更する。
linearColorPaint.getTextBounds(ANIMATED_TEXT, 0, ANIMATED_TEXT.length, bounds)
camera.getMatrix(rotationMatrix)
val centerX = (bounds.width().toFloat())/2
val centerY = (bounds.height().toFloat())/2
rotationMatrix.preTranslate(-centerX, -centerY)
rotationMatrix.postTranslate(centerX, centerY)
canvas.save()
canvas.concat(rotationMatrix)
canvas.drawText(ANIMATED_TEXT, 0f, 0f + bounds.height(), paint)
canvas.restore()
linearColorPaint.getTextBounds(ANIMATED_TEXT, 0, ANIMATED_TEXT.length(), bounds);
camera.getMatrix(rotationMatrix);
float centerX = (float)bounds.width()/2.0f;
float centerY = (float)bounds.height()/2.0f;
rotationMatrix.preTranslate(-centerX, -centerY);
rotationMatrix.postTranslate(centerX, centerY);
canvas.save();
canvas.concat(rotationMatrix);
canvas.drawText(ANIMATED_TEXT, 0f, 0f + bounds.height(), paint);
canvas.restore();

Jetpack Compose で RuntimeShader を使用する
を使用して UI をレンダリングする場合は、RuntimeShader
を使用する方がさらに簡単です。
Jetpack Compose。まずは、先ほどと同じグラデーション シェーダーを
before:
private const val COLOR_SHADER_SRC =
"""uniform float2 iResolution;
half4 main(float2 fragCoord) {
float2 scaled = fragCoord/iResolution.xy;
return half4(scaled, 0, 1);
}"""
そのシェーダーを
ShaderBrush
。マイページ
次に、ShaderBrush
を
Canvas
の描画スコープ。
// created as top level constants
val colorShader = RuntimeShader(COLOR_SHADER_SRC)
val shaderBrush = ShaderBrush(colorShader)
Canvas(
modifier = Modifier.fillMaxSize()
) {
colorShader.setFloatUniform("iResolution",
size.width, size.height)
drawCircle(brush = shaderBrush)
}

RenderEffect で RuntimeShader を使用する
次を使用:
RenderEffect
:
RuntimeShader
を親 View
へ
およびすべての子ビュー。この方法は、カスタムの View
を描画するよりもコストがかかります。
そうすると、作成したばかりのコンポーネントに
元々は
createRuntimeShaderEffect
。
view.setRenderEffect(RenderEffect.createRuntimeShaderEffect(myShader, "background"))
view.setRenderEffect(RenderEffect.createRuntimeShaderEffect(myShader, "background"));
2 つ目のパラメータは、シェーダーのユニフォームの名前です。eval
(fragCoord で渡された値など)の座標パラメータを使って、
RenderNode
(ビューとその子ビュー)
ビューなど)を使用して、あらゆる種類のエフェクトを実行できます。
uniform shader background; // Root node of View tree to be altered
return mix(returnColor, background.eval(fragCoord), 0.5);

ボタンの上に、フローティング アクション ボタンの下にあるグリッド エフェクトが混在している
(View
階層が異なるため)。