Комментарии 11
Шейдеры только в 13 Андроиде завезли, ниже их нет, так что конечно красиво, но ветвления логики что-то не заметно, кто соберёт на устройство ниже, поймает краш.
А у вас все хорошо работает, glsl вместо agls подхватился без проблем?
Я написал это приложение не просто на Jetpack Compose, а на Compose Multiplatform
Совсем запутали... Как понять что есть что?
Jetpack Compose - фреймворк для разработки под Андроид от Google. Вскоре после его релиза Jetbrains выпустили на его основе Compose Multiplatform - фреймворк, позволяющий запускать интерфейсы Jetpack Compose дополнительно в десктопных приложениях, iOS и в браузере. Управление состоянием, StateFlow, рендерер Skia те же. Подпробнее можно почитать тут: https://github.com/JetBrains/compose-multiplatform и в моей статье: https://habr.com/ru/companies/timeweb/articles/734818/
Они даже пару слов в язык добавили, все ради него.
Если вы про expect и actual - они доступны только при наличии KCP kotlin("multiplatform"). Любой желающий может добавить в свой проект на котлине новые ключевые слова, если напишет собственный плагин компиляции.
Я так понимаю, что от Modifier.drawWithCache
нету смысла, так как происходит постоянное изменение времени, а значит, что шейдеры пересоздаются на каждую перерисовку
(Промахнулся веткой, ответ на этот комментарий)
Согласно документации, drawWithCache
вызывает лямбду когда изменился размер рисуемой области и/или состояние, которое читается из лямбды
В вашем случае, это сработает только между кадрами, если кадры будут рисоваться быстрее, чем вы изменяете переменную time
Можете print
в консоль сделать и убедится, что у вас постоянно создаются новые шейдеры
Ну да, получается, что самое лучшее, что можно здесь сделать - это закешировать shaderBuilder:
actual fun Modifier.shaderEffect(shaderOption: ShaderOptions): Modifier = composed {
val time by produceState(0f) {
while (true) {
withInfiniteAnimationFrameMillis {
value = it / 1000f
}
}
}
val effect = remember(shaderOption) { RuntimeEffect.makeForShader(shaderOption.toShaderCode()) }
val compositeShaderBuilder = remember(effect) { RuntimeShaderBuilder(effect) }
Modifier.drawWithCache {
compositeShaderBuilder.uniform(
name = "iResolution",
value1 = size.width,
value2 = size.height
)
compositeShaderBuilder.uniform(
"iTime",
time
)
val shaderBrush = ShaderBrush(compositeShaderBuilder.makeShader())
onDrawBehind {
withTransform({ scale(scaleX = 1f, scaleY = -1f) }) {
drawRect(shaderBrush)
}
}
}
}
Тогда хотя бы выделения памяти под него не будет.
Это на примере десктопа, на андроиде будет чуть отличаться
Как создать анимированные шейдеры в Jetpack Compose