AGSL in Ihrer Android-App verwenden

Auf dieser Seite werden die Grundlagen von AGSL und verschiedene Möglichkeiten erläutert, wie Sie AGSL auf Ihrem Android-Gerät verwenden können.

Ein einfacher AGSL-Shader

Ihr Shader-Code wird für jedes gezeichnete Pixel aufgerufen und gibt die Farbe zurück, die das Pixel gezeichnet werden sollte. Ein äußerst einfacher Shader in einer einzigen Farbe; In diesem Beispiel wird Rot verwendet. Der Shader wird in einem String definiert.

Kotlin

private const val COLOR_SHADER_SRC =
   """half4 main(float2 fragCoord) {
      return half4(1,0,0,1);
   }"""

Java

private static final String COLOR_SHADER_SRC =
   "half4 main(float2 fragCoord) {\n" +
      "return half4(1,0,0,1);\n" +
   "}";

Im nächsten Schritt erstellen Sie eine RuntimeShader Objekt, das mit Ihrem Shader-String initialisiert wurde. Dadurch wird auch der Shader kompiliert.

Kotlin

val fixedColorShader = RuntimeShader(COLOR_SHADER_SRC)

Java

RuntimeShader fixedColorShader = new RuntimeShader(COLOR_SHADER_SRC);

RuntimeShader kann überall dort verwendet werden, wo es ein standardmäßiger Android-Shader kann. Als Sie können damit beispielsweise in ein benutzerdefiniertes View Canvas

Kotlin

val paint = Paint()
paint.shader = fixedColorShader
override fun onDrawForeground(canvas: Canvas?) {
   canvas?.let {
      canvas.drawPaint(paint) // fill the Canvas with the shader
   }
}

Java

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
   }
}

Dadurch wird ein rotes View gezeichnet. Mit uniform können Sie einen Farbparameter an der zu zeichnende Shader. Fügen Sie dem Shader zuerst die Farbe uniform hinzu:

Kotlin

private const val COLOR_SHADER_SRC =
"""layout(color) uniform half4 iColor;
   half4 main(float2 fragCoord) {
      return iColor;
   }"""

Java

private static final String COLOR_SHADER_SRC =
   "layout(color) uniform half4 iColor;\n"+
      "half4 main(float2 fragCoord) {\n" +
      "return iColor;\n" +
   "}";

Rufen Sie dann setColorUniform aus Ihrer benutzerdefinierten View auf, um die gewünschte Farbe zu übergeben. in den AGSL-Shader.

Kotlin

fixedColorShader.setColorUniform("iColor", Color.GREEN )

Java

fixedColorShader.setColorUniform("iColor", Color.GREEN );

Jetzt wird ein grünes View angezeigt. wird die Farbe View mit einem aus dem Code Ihrer benutzerdefinierten View, anstatt in den Shader.

Sie können stattdessen einen Farbverlaufseffekt erstellen. Sie müssen zunächst den Shader, um die View-Auflösung als Eingabe zu akzeptieren:

Kotlin

private const val COLOR_SHADER_SRC =
"""uniform float2 iResolution;
   half4 main(float2 fragCoord) {
      float2 scaled = fragCoord/iResolution.xy;
      return half4(scaled, 0, 1);
   }"""

Java

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" +
   "}";

Farbverlauf zeichnen

Dieser Shader hat etwas Raffiniertes. Für jedes Pixel wird ein float2 erstellt. Vektor mit den x- und y-Koordinaten geteilt durch die Auflösung, wobei einen Wert zwischen null und eins. Anhand dieses skalierten Vektors die roten und grünen Komponenten der Rückgabefarbe.

Sie übergeben die Auflösung von View an einen AGSL-Shader uniform, indem Sie folgenden Befehl aufrufen: setFloatUniform

Kotlin

val paint = Paint()
paint.shader = fixedColorShader
override fun onDrawForeground(canvas: Canvas?) {
   canvas?.let {
      fixedColorShader.setFloatUniform("iResolution", width.toFloat(), height.toFloat())
      canvas.drawPaint(paint)
   }
}

Java

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);
   }
}
<ph type="x-smartling-placeholder">
</ph> Rot- und Grün-Farbverlauf
Roter und grüner Farbverlauf

Shader animieren

Mit einer ähnlichen Technik kannst du den Shader animieren, indem du ihn so änderst, dass er iTime- und iDuration-Uniformen erhält. Der Shader verwendet diese Werte, um einen dreieckige Welle für die Farben, sodass sie zwischen den Werten des Farbverlaufs hin- und herwechseln.

Kotlin

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);
   }
"""

Java

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"+
   "}";

Aus dem Quellcode der benutzerdefinierten Ansicht wird ein ValueAnimator aktualisiert die Trikot von iTime.

Kotlin

// 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()

Java

// 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());
   }
});
<ph type="x-smartling-placeholder">
</ph> Animierter Farbverlauf in Rot und Grün
Animierter Farbverlauf in Rot und Grün

Komplexe Objekte bemalen

Sie müssen den Shader nicht zeichnen, um den Hintergrund zu füllen. kann es sein überall verwendet werden, Paint-Objekt, z. B. drawText

Kotlin

canvas.drawText(ANIMATED_TEXT, TEXT_MARGIN_DP, TEXT_MARGIN_DP + bounds.height(),
   paint)

Java

canvas.drawText(ANIMATED_TEXT, TEXT_MARGIN_DP, TEXT_MARGIN_DP + bounds.height(),
   paint);
<ph type="x-smartling-placeholder">
</ph> Animierter Farbverlauf in Rot und Grün
Animierter Farbverlauf in Rot und Grün

Shading- und Canvas-Transformationen

Sie können zusätzliche Canvas-Transformationen auf den schattierten Text anwenden, z. B. Rotation. Im ValueAnimator können Sie eine Matrix für 3D-Drehungen aktualisieren. mit der integrierten Klasse android.graphics.Camera.

Kotlin

// in the ValueAnimator
camera.rotate(0.0f, animation.animatedValue as Float / DURATION * 360f, 0.0f)

Java

// in the ValueAnimator
camera.rotate(0.0f, (Float)animation.getAnimatedValue() / DURATION * 360f, 0.0f);

Da Sie den Text von der Mittelachse und nicht von der Ecke aus drehen möchten, Rufen Sie die Textgrenzen ab und ändern Sie mit preTranslate und postTranslate Matrix, um den Text so zu übersetzen, dass 0,0 der Mittelpunkt der Drehung ist, Position ändern, an der der Text auf dem Bildschirm gezeichnet wird.

Kotlin

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()

Java

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();
<ph type="x-smartling-placeholder">
</ph> Rot und Grün rotierender animierter Farbverlaufstext
Rot und Grün rotierender animierter Farbverlauf

RuntimeShader mit Jetpack Compose verwenden

Es ist noch einfacher, RuntimeShader zu verwenden, wenn du deine UI mit Jetpack Compose. Beginnend mit demselben Farbverlauf-Shader von vorher:

private const val COLOR_SHADER_SRC =
    """uniform float2 iResolution;
   half4 main(float2 fragCoord) {
   float2 scaled = fragCoord/iResolution.xy;
   return half4(scaled, 0, 1);
}"""

Sie können diesen Shader auf einen ShaderBrush Ich Verwenden Sie dann ShaderBrush als Parameter für die Zeichenbefehle in Ihrem Zeichenumfang von 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)
}
<ph type="x-smartling-placeholder">
</ph> Kreis mit Farbverlauf für AGSL Compose
Kreis mit rotem und grünem Farbverlauf

RuntimeShader mit RenderEffect verwenden

Sie können RenderEffect zum Anwenden RuntimeShader an das übergeordnete Element View und alle untergeordneten Ansichten enthält. Das ist teurer als das Zeichnen einer benutzerdefinierten View. aber können Sie ganz einfach einen Effekt erzeugen, der das Prinzip der die ursprünglich mit createRuntimeShaderEffect

Kotlin

view.setRenderEffect(RenderEffect.createRuntimeShaderEffect(myShader, "background"))

Java

view.setRenderEffect(RenderEffect.createRuntimeShaderEffect(myShader, "background"));

Der zweite Parameter ist der Name einer Shader-Uniform, die Sie eval mit einem -Koordinatenparameter wie den in fragCoord übergebenen Parameter, um die Originalfarbe abzurufen der RenderNode (die Datenansicht und ihr untergeordnetes Element) Ansichten), sodass du alle möglichen Effekte anwenden kannst.

uniform shader background;       // Root node of View tree to be altered
return mix(returnColor, background.eval(fragCoord), 0.5);
<ph type="x-smartling-placeholder">
</ph> Raster über Schaltfläche
AGSL-Raster über Schaltfläche

Ein Rastereffekt, gemischt über einer Schaltfläche, aber unter einer unverankerten Aktionsschaltfläche da es sich in einer anderen View-Hierarchie befindet.