https://kotlinlang.org logo
Title
y

yogaboy

05/17/2023, 7:11 AM
Hi, any idea how can I achieve this stunning effect on player? 🙏
j

Jakub Syty

05/17/2023, 8:01 AM
I think this is your system that is doing that. It's a normal media style notification
y

yogaboy

05/17/2023, 8:08 AM
On player I suppose yes. But I would like to achieve this in some my card in App
The Wave 🌊 effect.
j

Jakub Syty

05/17/2023, 9:38 AM
I think this is a shader
y

yogaboy

05/17/2023, 10:17 AM
I tried to do with shader something similar. But it’s not even close …
I have no idea how they made it on player
s

Stylianos Gakis

05/17/2023, 12:43 PM
If it’s the squiggly thing you’re after, I know I’ve seen it before in this https://github.com/saket/ExtendedSpans repo, maybe you can look into it and get some inspiration about how to implement it? If it’s about the thing going on around the entire player, maybe that code is open source and you can search for it? I haven’t done any serious code searching inside the system aside from
<https://cs.android.com/>
, so not sure if you’d find that in there too.
y

yogaboy

05/17/2023, 1:16 PM
🤔 I guess we don’t understand what effect I mean
I mean the effect that appears after the ripple effect on the entire surface of the player.
Such dark chaotic ripples across the entire surface
s

Stylianos Gakis

05/17/2023, 1:18 PM
I re-read what you said and I think you mean the effect that goes on top of the entire player, that looks like there’s some “water” on top of it or something like that. So scratch the link about the squiggly lines, my bad. Still, for that ripple, as I said above, maybe there’s a way for you to try and find the code for that effect in AOSP? Shouldn’t it be in there somewhere?
y

yogaboy

05/17/2023, 1:21 PM
Yes. The water effect!!
s

Stylianos Gakis

05/17/2023, 1:23 PM
I guess the question is not so much if there is a way to do this, but more like how to get exactly the same effect, which to me sounds impossible unless you find the specific source code that is used by the system too?
y

yogaboy

05/17/2023, 1:24 PM
I just tried to move the colors chaotically through the shaders. But it doesn’t even remotely remind me of the water effect. I can’t even think of how to put it above the photo
a

andrew

05/17/2023, 4:25 PM
class TurbulenceNoiseShader : RuntimeShader(TURBULENCE_NOISE_SHADER) {
    // language=AGSL
    companion object {
        private const val UNIFORMS =
            """
            uniform float in_gridNum;
            uniform vec3 in_noiseMove;
            uniform vec2 in_size;
            uniform float in_aspectRatio;
            uniform float in_opacity;
            uniform float in_pixelDensity;
            layout(color) uniform vec4 in_color;
            layout(color) uniform vec4 in_backgroundColor;
        """

        private const val SHADER_LIB =
            """
            float getLuminosity(vec3 c) {
                return 0.3*c.r + 0.59*c.g + 0.11*c.b;
            }

            vec3 maskLuminosity(vec3 dest, float lum) {
                dest.rgb *= vec3(lum);
                // Clip back into the legal range
                dest = clamp(dest, vec3(0.), vec3(1.0));
                return dest;
            }
        """

        private const val MAIN_SHADER =
            """
            vec4 main(vec2 p) {
                vec2 uv = p / in_size.xy;
                uv.x *= in_aspectRatio;

                vec3 noiseP = vec3(uv + in_noiseMove.xy, in_noiseMove.z) * in_gridNum;
                float luma = simplex3d(noiseP) * in_opacity;
                vec3 mask = maskLuminosity(in_color.rgb, luma);
                vec3 color = in_backgroundColor.rgb + mask * 0.6;

                // Add dither with triangle distribution to avoid color banding. Ok to dither in the
                // shader here as we are in gamma space.
                float dither = triangleNoise(p * in_pixelDensity) / 255.;

                // The result color should be pre-multiplied, i.e. [R*A, G*A, B*A, A], thus need to
                // multiply rgb with a to get the correct result.
                color = (color + dither.rrr) * in_color.a;
                return vec4(color, in_color.a);
            }
        """

        private const val TURBULENCE_NOISE_SHADER =
            ShaderUtilLibrary.SHADER_LIB + UNIFORMS + SHADER_LIB + MAIN_SHADER
    }

    /** Sets the number of grid for generating noise. */
    fun setGridCount(gridNumber: Float = 1.0f) {
        setFloatUniform("in_gridNum", gridNumber)
    }

    /**
     * Sets the pixel density of the screen.
     *
     * Used it for noise dithering.
     */
    fun setPixelDensity(pixelDensity: Float) {
        setFloatUniform("in_pixelDensity", pixelDensity)
    }

    /** Sets the noise color of the effect. */
    fun setColor(color: Int) {
        setColorUniform("in_color", color)
    }

    /** Sets the background color of the effect. */
    fun setBackgroundColor(color: Int) {
        setColorUniform("in_backgroundColor", color)
    }

    /**
     * Sets the opacity to achieve fade in/ out of the animation.
     *
     * Expected value range is [1, 0].
     */
    fun setOpacity(opacity: Float) {
        setFloatUniform("in_opacity", opacity)
    }

    /** Sets the size of the shader. */
    fun setSize(width: Float, height: Float) {
        setFloatUniform("in_size", width, height)
        setFloatUniform("in_aspectRatio", width / max(height, 0.001f))
    }

    /** Current noise movements in x, y, and z axes. */
    var noiseOffsetX: Float = 0f
        private set
    var noiseOffsetY: Float = 0f
        private set
    var noiseOffsetZ: Float = 0f
        private set

    /** Sets noise move offset in x, y, and z direction. */
    fun setNoiseMove(x: Float, y: Float, z: Float) {
        noiseOffsetX = x
        noiseOffsetY = y
        noiseOffsetZ = z
        setFloatUniform("in_noiseMove", noiseOffsetX, noiseOffsetY, noiseOffsetZ)
    }
}
This is from AOSP
r

Rebecca Franks

05/17/2023, 4:37 PM
You might want to use AGSL, but have your image as input so it looks like water is on top of the surface of your content. I did something similar with this Jelly fish post https://medium.com/androiddevelopers/making-jellyfish-move-in-compose-animating-imagevectors-and-applying-agsl-rendereffects-3666596a8888
In particular, the part where you set a renderEffect of graphicsLayer on the Image composable like so
Image(
   vectorPainter, contentDescription = "",
   modifier = Modifier
       .fillMaxSize()
       .background(largeRadialGradient)
       .onSizeChanged { size ->
           shader.setFloatUniform(
               "resolution",
               size.width.toFloat(),
               size.height.toFloat()
           )
       }
       .graphicsLayer {
           shader.setFloatUniform("time", time)
           renderEffect = android.graphics.RenderEffect
               .createRuntimeShaderEffect(
                   shader,
                   "contents"
               )
               .asComposeRenderEffect()
       }
)
You can set the render effect on a whole tree of composables
k

Kirill Grouchnikov

05/17/2023, 4:56 PM
ShaderToy is a decent source of implementation “inspirations” for various effects. https://www.shadertoy.com/results?query=water+ripples&amp;sort=popular&amp;from=12&amp;num=12 is for some water ripples. I don’t think you can expect to get the exact effect you’re always looking for, but rather a starting point for your own take on it.
a

andrew

05/17/2023, 6:46 PM
I mean, the AOSP sample is AGSL code, it can probably be ported over pretty easily to compose with some minor tweaking
y

yogaboy

05/18/2023, 8:43 AM
@andrew @Rebecca Franks @Kirill Grouchnikov thank you all. It’s completely new to me. Thanks a lot for the resources. It will probably take me a while to try it out and at least understand a little. Thank you very much!