تتناول هذه الصفحة أساسيات AGSL وطرقًا مختلفة لاستخدام AGSL في جهاز Android. التطبيق.
أداة تظليل 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" +
"}";
بعد ذلك، يمكنك طلب setColorUniform
من View
المخصّص لتمرير اللون المطلوب.
باستخدام أداة تظليل 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 مقسومًا على الدقة،
سوف يُنشئ قيمة بين صفر وواحد. ثم تستخدم هذا الخط المتجه المُعدَّل
لإنشاء المكونات الحمراء والخضراء للون الإرجاع.
يمكنك تمرير درجة دقة 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
، يمكنك تعديل مصفوفة لعمليات التدوير الثلاثية الأبعاد.
باستخدام الميزات
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();

استخدام RuntimeShader مع Jetpack Compose
يمكنك الآن استخدام 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)
}

استخدام RuntimeShader مع RenderEffect
يمكنك استخدام
RenderEffect
لتطبيق
RuntimeShader
إلى أحد الوالدين View
و جميع المشاهدات من قِبل الأطفال. هذا الإجراء أكثر تكلفة من رسم View
مخصّص. لكن
يسمح لك بإنشاء تأثير يتضمن بسهولة ما قد يكون
مرسومة في الأصل باستخدام
createRuntimeShaderEffect
view.setRenderEffect(RenderEffect.createRuntimeShaderEffect(myShader, "background"))
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
هرمي مختلف).