Questa pagina illustra le nozioni di base di AGSL e i vari modi per utilizzarlo in Android dell'app.
Un semplice Shar AGSL
Il codice dello shaker viene chiamato per ogni pixel disegnato e restituisce il colore del pixel
deve essere dipinto. Uno Shar estremamente semplice è un tipo che ritorna sempre
un solo colore; in questo esempio viene usato il rosso. Lo streamr è definito all'interno di un String
.
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" + "}";
Il passaggio successivo consiste nel creare una RuntimeShader
inizializzato con la stringa shaker. In questo modo viene compilato anche lo shaker.
Kotlin
val fixedColorShader = RuntimeShader(COLOR_SHADER_SRC)
Java
RuntimeShader fixedColorShader = new RuntimeShader(COLOR_SHADER_SRC);
Il tuo RuntimeShader
può essere utilizzato ovunque possa fare uno shaker Android standard. Come
ad esempio, puoi usarlo per disegnare in un elemento View
personalizzato utilizzando
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 } }
In questo modo viene tracciata una View
rossa. Puoi utilizzare un uniform
per passare un parametro di colore a
lo shaker da disegnare. Innanzitutto, aggiungi il colore uniform
allo shaker:
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" + "}";
Poi, chiama setColorUniform
dal tuo View
personalizzato per trasmettere il colore desiderato
nello streamr AGSL.
Kotlin
fixedColorShader.setColorUniform("iColor", Color.GREEN )
Java
fixedColorShader.setColorUniform("iColor", Color.GREEN );
Ora, ottieni un View
verde; il colore View
viene controllato utilizzando un
del codice nel tuo asset View
personalizzato anziché essere incorporato nel
Shar.
In alternativa, puoi creare un effetto a gradiente di colore. Devi prima modificare
lo shaker accetti la risoluzione View
come input:
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" + "}";
Disegno del gradiente
Questo Shar fa qualcosa di leggermente particolare. Per ogni pixel, viene creato un float2
vettore contenente le coordinate x e y divise per la risoluzione,
creerà un valore compreso tra zero e uno. Quindi utilizza il vettore scalato
i componenti rosso e verde del colore restituito.
Puoi passare la risoluzione di View
in uno shaker AGSL uniform
chiamando
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); } }
![Gradiente rosso e verde](https://developer.android.com/static/images/guide/topics/graphics/agsl/agsl-gradient.png?hl=it)
Animazione dello shaker
Puoi utilizzare una tecnica simile per animare lo shaker modificandolo in modo da ricevere le uniformi di iTime
e iDuration
. Lo shaker userà questi valori per creare
un'onda triangolare per i colori, che li fa scorrere avanti e indietro attraverso i valori del gradiente.
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"+ "}";
Nel codice sorgente della visualizzazione personalizzata,
ValueAnimator
aggiorna la
uniforme da 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()); } });
![Gradiente animato rosso e verde](https://developer.android.com/static/images/guide/topics/graphics/agsl/agsl-animated-gradient.gif?hl=it)
Pittura di oggetti complessi
Non è necessario disegnare lo shaker per riempire lo sfondo; può essere
utilizzate in qualsiasi luogo che accetti
Oggetto Paint
, ad esempio
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);
![Testo gradiente animato rosso e verde](https://developer.android.com/static/images/guide/topics/graphics/agsl/agsl-animated-gradient-text.gif?hl=it)
Trasformazioni di ombreggiatura e canvas
Puoi applicare ulteriori trasformazioni Canvas
al testo ombreggiato, ad esempio
la rotazione. In ValueAnimator
, puoi aggiornare una matrice per le rotazioni 3D
usando i modelli
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);
Poiché vuoi ruotare il testo dall'asse centrale anziché dall'angolo,
ottenere i limiti di testo e quindi usare preTranslate
e postTranslate
per modificare
per tradurre il testo in modo che 0,0 sia il centro della rotazione senza
cambiare la posizione in cui il testo viene disegnato sullo schermo.
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();
![Testo gradiente animato rotante rosso e verde](https://developer.android.com/static/images/guide/topics/graphics/agsl/agsl-rotating-animated-gradient-text.gif?hl=it)
Utilizzo di RuntimeShader con Jetpack Compose
È ancora più facile usare RuntimeShader
se esegui il rendering dell'UI con
Jetpack Compose. A partire dallo stesso Shader gradiente
prima del:
private const val COLOR_SHADER_SRC =
"""uniform float2 iResolution;
half4 main(float2 fragCoord) {
float2 scaled = fragCoord/iResolution.xy;
return half4(scaled, 0, 1);
}"""
Puoi applicare lo shaker a una
ShaderBrush
Tu
poi usa ShaderBrush
come parametro per i comandi di disegno all'interno delle
Ambito di disegno di 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)
}
![Cerchio gradiente AGSL Compose](https://developer.android.com/static/images/guide/topics/graphics/agsl/agsl-compose-gradient-circle.png?hl=it)
Utilizzo di RuntimeShader con RenderEffect
Puoi utilizzare
RenderEffect
per applicare uno
RuntimeShader
a un genitore View
e tutte le viste secondarie. È più costoso che disegnare un View
personalizzato. ma
consente di creare facilmente un effetto che incorpora ciò che
sono state originariamente disegnate
createRuntimeShaderEffect
Kotlin
view.setRenderEffect(RenderEffect.createRuntimeShaderEffect(myShader, "background"))
Java
view.setRenderEffect(RenderEffect.createRuntimeShaderEffect(myShader, "background"));
Il secondo parametro è il nome di un'uniforme shaker che puoi eval
con un
(come quello passato in fragCoord) per ottenere il colore originale
del
RenderNode
(la Vista e le relative schede secondarie
di visualizzazione), consentendoti di eseguire qualsiasi tipo di effetto.
uniform shader background; // Root node of View tree to be altered
return mix(returnColor, background.eval(fragCoord), 0.5);
![Pulsante Griglia combinata sopra](https://developer.android.com/static/images/guide/topics/graphics/agsl/agsl-grid-blend.png?hl=it)
Effetto griglia combinato su un pulsante, ma sotto un pulsante di azione mobile
(poiché si trova in una gerarchia View
diversa).