2.2K Views
November 28, 24
スライド概要
AGSLで画像にエフェクトを加える 米山 俊平(@Komeyama)
今回の内容 • AGSLを使ったエフェクトの例をいくつか紹介 • Jetpack Composeで実装する場合の要点を紹介
AGSL(Android Graphics Shading Language) • 高度なグラフィックが要求されるAndroidアプリでシェーダー を使いたいときに使用できる。 • GLSL(OpenGL Shading Language)の構文と似ている。 • Android13以降で使用可能である。 など
エフェクトの例を紹介
エフェクトを加える画像
雨粒のようなエフェクト Shaderは以下のGLSLのコードを参考にした。 • 『Heartfelt』Created by BigWIngs • https://www.shadertoy.com/view/ltffzl • 『Sitting By The Window』Created by Kris_Katur • https://www.shadertoy.com/view/slfSzS
タップ操作によって変化する波紋風エフェクト Shaderは以下のGLSLのコードを参考にした。 『RippleEffectFragmentShader』Created by abhi_bansal • https://www.shadertoy.com/view/ldBXDD
デバイスの傾きによって変化するレアカード風エフェクト Shaderは以下のGLSLのコードを参考にした。 『Voronoi Boronoi』Created by jcraw • https://www.shadertoy.com/view/Mc2BD1
実装方法の要点を紹介
GLSLとの主な違いを簡単なコードで紹介 GLSL AGSL uniform vec2 u_resolution; uniform vec2 u_resolution; uniform shader u_contents; uniform sampler2D u_text; vec4 main(in vec2 fragCoord) { void main() { } vec2 fragCoord.xy / u_resolution.xy; vec2 uv = fragCoord.xy / u_resolution.xy vec3 col = vec3(0,0); vec3 col = vec3(0,0); vec3 imgCol = u_contents.evel(uv * u_resolution.xy).rgb; vec4 texColor = texture(u_tex, uv); col.r = imgCol.b; col.r = texColor.b; col.g = imgCol.r; col.g = texColor.r; col.b = imgCol.g; col.b = texColor.g; return vec4(col, 1.0); gl_FragColor = vec4(col, 1.0); }
GLSLとの主な違いを簡単なコードで紹介
GLSL
AGSL
uniform vec2 u_resolution;
uniform vec2 u_resolution;
uniform shader u_contents;
uniform sampler2D u_text;
vec4 main(in vec2 fragCoord) {
void main() {
vec2 fragCoord.xy / u_resolution.xy;
vec2 uv = fragCoord.xy / u_resolution.xy
vec3 col = vec3(0,0);
vec3 col = vec3(0,0);
その他
vec3 imgCol = u_contents.evel(uv
* u_resolution.xy).rgb;
col.r = imgCol.b;
col.g = imgCol.r;
col.b = imgCol.g;
return vec4(col, 1.0);
}
vec4 texColor = texture(u_tex, uv);
• 座標について
col.r = texColor.b;
• AGSLは左上を基準、GLSLは左下が基準となる。
col.g = texColor.r;
• Developersに変換方法の参考例が記載されている。
col.b = texColor.g;
▪ https://developer.android.com/develop/ui/views/graphics/agsl/agslvs-glsl#coordinate_space gl_FragColor = vec4(col, 1.0);
• AGSLには存在しないGLSLの関数はある。
}
など
Jetpack ComposeでAGSLを使う
val shader = RuntimeShader(AGSL_CODE)
Image(
painter = painterResource(id = R.drawable.landscape),
modifier = Modifier.
onSizeChanged { size ->
shader.setFloatUniform(
shader.setFloatUniform("resolution", size.width.toFloat(),size.height.toFloat())
)
}.graphicsLayer {
renderEffect = RenderEffect
.createRuntimeShaderEffect(shader, "contents")
.asComposeRenderEffect()
}
)
Jetpack ComposeでAGSLを使う
val shader = RuntimeShader(AGSL_CODE)
Image(
painter = painterResource(id
= R.drawable.landscape),
@Language("AGSL")
modifier = Modifier. const val AGSL_CODE = """
uniform float 2 resolution;
onSizeChanged { size ->
uniform shader contens;
shader.setFloatUniform(
vec4 main(in vec2 fragCoord)
{
shader.setFloatUniform("resolution",
size.width.toFloat(),size.height.toFloat())
)
・・・
}.graphicsLayer {
renderEffect""".trimIndent()
= RenderEffect
.createRuntimeShaderEffect(shader, "contents")
.asComposeRenderEffect()
}
)
Jetpack ComposeでAGSLを使う
val shader = RuntimeShader(AGSL_CODE)
Image(
painter = painterResource(id = R.drawable.landscape),
modifier = Modifier.
onSizeChanged { size ->
shader.setFloatUniform(
shader.setFloatUniform("resolution", size.width.toFloat(),size.height.toFloat())
)
}.graphicsLayer {
@Language("AGSL")
renderEffect = RenderEffect
const val AGSL_CODE = """
uniform
float 2 resolution;
.createRuntimeShaderEffect(shader,
"contents")
uniform shader contens;
.asComposeRenderEffect()
}
)
・・・
Jetpack ComposeでAGSLを使う
val shader = RuntimeShader(AGSL_CODE)
Image(
painter = painterResource(id = R.drawable.landscape),
modifier = Modifier.
onSizeChanged { size ->
@Language("AGSL")
shader.setFloatUniform(
const val AGSL_CODE = """
uniform
float 2 resolution;
shader.setFloatUniform("resolution",
size.width.toFloat(),size.height.toFloat())
uniform shader contens;
)
}.graphicsLayer {
・・・
renderEffect = RenderEffect
.createRuntimeShaderEffect(shader, "contents")
.asComposeRenderEffect()
}
)
Jetpack ComposeでAGSLを使う
val shader = RuntimeShader(AGSL_CODE)
Image(
painter = painterResource(id = R.drawable.landscape),
modifier = Modifier.
onSizeChanged { size ->
shader.setFloatUniform(
)
時間やセンサー情報などのパラメーターをAGSLで使
shader.setFloatUniform("resolution",
size.width.toFloat(),size.height.toFloat())
いたい場合、setFloatUnifom等をgraphicLayer内に
記述する。
}.graphicsLayer {
shader.setFloatUniform("time", time)
renderEffect = RenderEffect
.createRuntimeShaderEffect(shader, "contents")
.asComposeRenderEffect()
}
)
まとめ • AGSLを使うことで面白いエフェクトをアプリに加えることができ る。 • センサー情報等を使うことでモバイルデバイスならではの表現をア プリに加えられる。 • シェーダー自体の作成は難しいが、Shadertoyなどにある先人達の 作ったGLSLのコードを参考にすれば、比較的楽にAndroidアプリに 組み込むことができる。
ご清聴ありがとうございました