تغطي هذه الصفحة أساسيات لغة AGSL وطرقًا مختلفة لاستخدام لغة AGSL في تطبيق Android الخاص بك.
أداة تظليل AGSL بسيطة
يتم استدعاء رمز التظليل لكل بكسل مرسوم، ويعرض اللون الذي يجب طلاء
البكسل به. أداة التظليل البسيطة للغاية هي أداة تعرض دائمًا
لونًا واحدًا؛ يستخدم هذا المثال اللون الأحمر. يتم تحديد أداة التظليل داخل 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" + "}";
تتمثّل الخطوة التالية في إنشاء كائن RuntimeShader
تم إعداده بسلسلة Shadr. يؤدي ذلك أيضًا إلى تجميع أداة التظليل.
Kotlin
val fixedColorShader = RuntimeShader(COLOR_SHADER_SRC)
Java
RuntimeShader fixedColorShader = new RuntimeShader(COLOR_SHADER_SRC);
يمكن استخدام RuntimeShader
في أي مكان يمكن فيه استخدام أداة تظليل Android العادية. فمثلاً، يمكنك استخدامها للرسم في 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 } }
يؤدي ذلك إلى رسم View
باللون الأحمر. يمكنك استخدام uniform
لتمرير معلمة لون إلى
أداة التظليل المراد رسمها. أولاً، أضِف اللون uniform
إلى أداة التظليل:
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" + "}";
بعد ذلك، يمكنك استدعاء setColorUniform
من View
المخصّص لتمرير اللون المطلوب إلى أداة تظليل AGSL.
Kotlin
fixedColorShader.setColorUniform("iColor", Color.GREEN )
Java
fixedColorShader.setColorUniform("iColor", Color.GREEN );
ستحصل الآن على View
باللون الأخضر، ويتم التحكّم في لون View
باستخدام معلَمة من الرمز البرمجي في View
المخصص بدلاً من تضمينه في التظليل.
يمكنك إنشاء تأثير تدرج اللون بدلاً من ذلك. ستحتاج أولاً إلى تغيير أداة التظليل لقبول درجة دقة View
كإدخال:
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" + "}";
رسم التدرج
يعمل جهاز التظليل هذا بشيء فاخر بعض الشيء. لكل بكسل، يتم إنشاء متجه float2
يحتوي على إحداثيات x وy مقسومًا على درجة الدقة، ما سيؤدي إلى إنشاء قيمة بين صفر وواحد. ثم تستخدم هذا المتجه المتدرج لإنشاء
المكونات الأحمر والأخضر للون العائد.
تمرير درجة دقة View
إلى uniform
أداة تظليل لغة AGSL من خلال طلب 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); } }
تحريك أداة التظليل
يمكنك استخدام أسلوب مشابه لتحريك أداة التظليل عن طريق تعديلها لتلقّي زيّ iTime
وiDuration
موحّد. سيستخدم الظل هذه القيم لإنشاء موجة مثلثة للألوان، مما يجعلها تدور ذهابًا وإيابًا عبر قيم تدرجها.
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
لنموذج 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()); } });
طلاء العناصر المعقدة
ليس عليك رسم أداة التظليل لملء الخلفية، إذ يمكن استخدامها في أي مكان يقبل عناصر
Paint
، مثل
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);
تغييرات التظليل و"لوحة الرسم"
يمكنك تطبيق عمليات تحويل Canvas
إضافية على النص المظلّل، مثل
تدوير. في ValueAnimator
، يمكنك تعديل مصفوفة لعمليات الدوران الثلاثي الأبعاد
باستخدام الفئة
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);
بما أنّك تريد تدوير النص من المحور الأوسط بدلاً من الزاوية،
احصل على حدود النص ثم استخدِم preTranslate
وpostTranslate
لتغيير
المصفوفة لترجمة النص بحيث يكون 0,0 هو مركز التدوير بدون تغيير موضع رسم النص على الشاشة.
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();
استخدام RuntimeShader مع حزمة Jetpack Compose
سيصبح استخدام RuntimeShader
أسهل إذا كنت تعرض واجهة المستخدم باستخدام
Jetpack Compose. بدءًا من نفس أداة تظليل التدرج من قبل:
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)
}
استخدام RuntimeShader مع عرض RenderEffect
يمكنك استخدام
RenderEffect
لتطبيق
RuntimeShader
على أحد الوالدَين View
وكل المشاهدات الفرعية. وهذه تكلفة أعلى من رسم View
مخصّص. ولكنّه يتيح لك بسهولة إنشاء تأثير يتضمّن ما كان
يمكن رسمه في الأصل باستخدام createRuntimeShaderEffect
.
Kotlin
view.setRenderEffect(RenderEffect.createRuntimeShaderEffect(myShader, "background"))
Java
view.setRenderEffect(RenderEffect.createRuntimeShaderEffect(myShader, "background"));
والمَعلمة الثانية هي اسم عنصر تظليل يمكنك eval
باستخدام مَعلمة إحداثية (مثل التي تم تمريرها في fragCoord) للحصول على اللون الأصلي للسمة RenderNode
(طريقة العرض وطرق العرض الفرعية الخاصة بها)، ما يتيح لك تنفيذ جميع أنواع التأثيرات.
uniform shader background; // Root node of View tree to be altered
return mix(returnColor, background.eval(fragCoord), 0.5);
تأثير شبكة مختلط على زر، ولكن أسفل زر إجراء عائم
(لأنه في تسلسل View
هرمي مختلف).