I have this `Modifier` that creates sanded paper t...
# compose
m
I have this
Modifier
that creates sanded paper texture. but the performance is TERRIBLE as expected with the number of drawn circles. how to make performance better?
Copy code
fun Modifier.sandedPaperOverlay(
    lightGrainColor: Color = Color.White.copy(alpha = 0.04f),
    darkGrainColor: Color = Color.Black.copy(alpha = 0.03f),
    grainCount: Int = 40_000,
    maxGrainRadius: Float = 2f,
): Modifier = this.drawWithContent {
    drawContent()

    val random = Random(0)
    repeat(grainCount) {
        val x = random.nextFloat() * size.width
        val y = random.nextFloat() * size.height
        val r = random.nextFloat() * maxGrainRadius + 1f
        drawCircle(lightGrainColor, r, Offset(x, y))
    }
    repeat(grainCount / 2) {
        val x = random.nextFloat() * size.width
        val y = random.nextFloat() * size.height
        val r = random.nextFloat() * maxGrainRadius + 1f
        drawCircle(darkGrainColor, r, Offset(x, y))
    }
}
s
To make it faster, you can use the shader approach, but it requires additional knowledge and a higher Android API level. Alternatively, you can draw the grain texture once into a bitmap using GraphicsLayer, and then blend it with your UI.
Also, I’m pretty sure there are more performant noise texture algorithms.
m
I’m currently working on shader approach. I was wondering there might be some draw API that I don’t know about that can make this better. or that somebody has already implemented this 😄
s
You can draw points in batches, which is much more efficient than drawing each circle separately.
Instead of 60k draw calls, you end up with just 2, 40k points and 20k points per batch, which I believe can be reduced even further.
m
performance is terrible even with 10k circles, so 40k and 20k at once is too much
I tried to see how much I can draw at once in order to split as you mentioned but to no avail
s
Yeah, that’s not the right way to do it. 😅
But this way, you’ll lose control over the point radius, unlike when using circles. Which might not be a problem at all, given the total number of points to be drawn. 🤔
m
thank you. I’ll try it tomorrow
👍 1
r
Something that makes more sense for this kind of effect is to have a tileable bitmap
1
(which would contain noise, like blue noise)
You can easily tile a bitmap using
ShaderBrush(ImageShader(…))
and passing the repeated tile modes on each axis
❤️ 2
K 1
You could either generate the tileable bitmap, or just include it with your app. The bitmap doesn't have to be big and it's extremely cheap to render
You can also find plenty of pre-tiled paper textures online for you to use
m
@romainguy thank you very much. I managed to get it work the way you suggested and it works perfectly 💯
s
An old technique, but a gold one
🔥 1