Android uygulamanızda AGSL'yi kullanma

Bu sayfada AGSL ile ilgili temel bilgiler ve Android uygulamanızda AGSL'yi kullanmanın farklı yolları ele alınmaktadır.

Basit bir AGSL gölgelendirici

Gölgelendirici kodunuz, çizilen her piksel için çağrılır ve pikselin boyanması gereken rengi döndürür. Son derece basit bir gölgelendirici, her zaman tek bir renk döndürür. Bu örnekte kırmızı kullanılmaktadır. Gölgelendirici, bir String içinde tanımlanır.

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

Sonraki adım, gölgelendirici dizenizle başlatılan bir RuntimeShader nesnesi oluşturmaktır. Bu işlem ayrıca gölgelendiriciyi de derler.

Kotlin

val fixedColorShader = RuntimeShader(COLOR_SHADER_SRC)

Java

RuntimeShader fixedColorShader = new RuntimeShader(COLOR_SHADER_SRC);

RuntimeShader cihazınız standart bir Android gölgelendiricinin kullanılabileceği her yerde kullanılabilir. Örnek olarak, Canvas kullanarak özel bir View içine çizim yapmak üzere bunu kullanabilirsiniz.

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

Bu, kırmızı bir View çizer. Çizilecek gölgelendiriciye bir renk parametresi geçirmek için uniform kullanabilirsiniz. İlk olarak, gölgelendiriciye uniform rengini ekleyin:

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

Ardından, istediğiniz rengi AGSL gölgelendiricisine geçirmek üzere özel View cihazınızdan setColorUniform çağrısı yapın.

Kotlin

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

Java

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

Şimdi yeşil bir View elde edersiniz; View rengi, gölgelendiriciye yerleştirmek yerine özel View kodunuzdaki bir parametre kullanılarak kontrol edilir.

Bunun yerine bir renk gradyanı efekti oluşturabilirsiniz. Öncelikle giriş olarak View çözünürlüğünü kabul etmek için gölgelendiriciyi değiştirmeniz gerekir:

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

Gradyanı çizme

Bu gölgelendirici biraz gösterişli bir şey yapıyor. Her piksel için x ve y koordinatlarının çözünürlüğe bölünmesiyle elde edilen bir float2 vektörü oluşturur. Böylece, sıfır ile bir arasında bir değer oluşturulur. Daha sonra, dönüş renginin kırmızı ve yeşil bileşenlerini oluşturmak için bu ölçeklendirilmiş vektörü kullanır.

View çözünürlüğünü setFloatUniform yöntemini çağırarak bir AGSL gölgelendiricisine uniform iletirsiniz.

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);
   }
}
Kırmızı ve Yeşil gradyanı
Kırmızı ve yeşil gradyan

Gölgelendiriciye animasyon ekleme

Gölgelendiriciyi iTime ve iDuration forma alacak şekilde değiştirerek benzer bir teknik kullanabilirsiniz. Gölgelendirici, renkler için üçgen bir dalga oluşturmak amacıyla bu değerleri kullanır. Böylece, renklerin gradyan değerleri arasında gidip gelirler.

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

ValueAnimator, özel görünüm kaynak kodundaki iTime tek tipliğini günceller.

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());
   }
});
Kırmızı ve Yeşil animasyonlu gradyan
Kırmızı ve Yeşil animasyonlu gradyan

Karmaşık nesneleri boyama

Arka planı doldurmak için gölgelendiriciyi çizmenize gerek yoktur; drawText gibi Paint nesnesini kabul eden her yerde kullanılabilir.

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);
Kırmızı ve Yeşil animasyonlu gradyan metin
Kırmızı ve Yeşil animasyonlu gradyan metni

Gölgeleme ve Tuval dönüşümleri

Gölgeli metninize döndürme gibi ek Canvas dönüşümleri uygulayabilirsiniz. ValueAnimator ürününde, yerleşik android.graphics.Camera sınıfını kullanarak 3D rotasyonlar için bir matrisi güncelleyebilirsiniz.

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

Metni köşe yerine merkez eksenden döndürmek istediğiniz için metin sınırlarını alın ve ardından metni çevirmek üzere matrisi değiştirmek için preTranslate ve postTranslate ile değiştirin. Böylece, metnin ekranda çizildiği konumu değiştirmeden, döndürmenin merkezi 0,0 olacaktır.

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();
Animasyonlu gradyan metni döndüren Kırmızı ve Yeşil
Animasyonlu gradyan metni döndüren Kırmızı ve Yeşil

RuntimeShader'ı Jetpack Compose ile kullanma

Kullanıcı arayüzünüzü Jetpack Compose kullanarak oluşturuyorsanız RuntimeShader kullanmak daha da kolaydır. Önceki gradyan gölgelendiriciyle başlayarak:

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

Bu gölgelendiriciyi bir ShaderBrush öğesine uygulayabilirsiniz. Daha sonra ShaderBrush, Canvas çizim kapsamınızdaki çizim komutlarına parametre olarak eklenir.

// 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)
}
AGSL Compose gradyan dairesi
Kırmızı ve yeşil gradyan dairesi

RuntimeShader'ı RenderEffect ile kullanma

RuntimeShader öğesini üst View ve tüm alt görünümlere uygulamak için RenderEffect kullanabilirsiniz. Bu, özel bir View çizmekten daha pahalıdır. ancak createRuntimeShaderEffect kullanılarak başlangıçta çizilmiş olanları içeren bir efekti kolayca oluşturmanıza olanak tanır.

Kotlin

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

Java

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

İkinci parametre, RenderNode öğesinin (Görünüm ve alt görünümleri) orijinal rengini elde etmek için bir koordinat parametresiyle (fragCoord'da iletilen gibi) eval ile eval oluşturarak her türlü efekti gerçekleştirebilmenizi sağlar.

uniform shader background;       // Root node of View tree to be altered
return mix(returnColor, background.eval(fragCoord), 0.5);
Üzerinde karıştırılmış ızgara düğmesi
Düğme üzerinde harmanlanmış AGSL ızgarası

Bir düğmenin üzerine karıştırılmış ancak kayan işlem düğmesinin altında (farklı bir View hiyerarşisinde olduğu için) ızgara efekti.