Loading weathereffects/graphics/assets/shaders/rain_glass_layer.agsldeleted 100644 → 0 +0 −105 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ uniform shader texture; uniform float time; uniform float screenAspectRatio; uniform float gridScale; uniform float2 screenSize; uniform half intensity; #include "shaders/constants.agsl" #include "shaders/utils.agsl" #include "shaders/glass_rain.agsl" #include "shaders/rain_constants.agsl" vec4 main(float2 fragCoord) { // 0. Calculate UV and add a bit of noise so that the droplets are not perfect circles. float2 uv = vec2(valueNoise(fragCoord) * 0.015 - 0.0025) + fragCoord / screenSize; // 1. Generate small glass rain. GlassRain smallDrippingRain = generateGlassRain( uv, screenAspectRatio, time * 0.7, /* Grid size = */ vec2(5.0, 1.6) * gridScale, intensity * 0.6); float dropMask = smallDrippingRain.dropMask; float droppletsMask = smallDrippingRain.droppletsMask; float trailMask = smallDrippingRain.trailMask; vec2 dropUvMasked = smallDrippingRain.drop * dropMask; vec2 droppletsUvMasked = smallDrippingRain.dropplets * droppletsMask; // 2. Generate medium size glass rain. GlassRain medDrippingRain = generateGlassRain( uv, screenAspectRatio, time * 0.80, /* Grid size = */ vec2(6., 0.945) * gridScale, intensity * 0.6); // 3. Combine those two glass rains. dropMask = max(medDrippingRain.dropMask, dropMask); droppletsMask = max(medDrippingRain.droppletsMask, droppletsMask); trailMask = max(medDrippingRain.trailMask, trailMask); dropUvMasked = mix(dropUvMasked, medDrippingRain.drop * medDrippingRain.dropMask, medDrippingRain.dropMask); droppletsUvMasked = mix(droppletsUvMasked, medDrippingRain.dropplets * medDrippingRain.droppletsMask, medDrippingRain.droppletsMask); // 4. Add static rain droplets on the glass surface. (They stay in place and dissapate.) vec2 gridSize = vec2(12., 12.) * gridScale; // Aspect ratio impacts visible cells. gridSize.y /= screenAspectRatio; vec3 staticRain = generateStaticGlassRain(uv, time, intensity, gridSize); dropMask = max(dropMask, staticRain.z); dropUvMasked = mix(dropUvMasked, staticRain.xy * staticRain.z, staticRain.z); // 5. Distort uv for the rain drops and dropplets. float distortionDrop = -0.1; vec2 uvDiffractionOffsets = distortionDrop * dropUvMasked; vec2 s = screenSize; // Ensure the diffracted image in drops is not inverted. s.y *= -1; vec4 color = texture.eval(fragCoord); vec3 sampledColor = texture.eval(fragCoord + uvDiffractionOffsets * s).rgb; color.rgb = mix(color.rgb, sampledColor, max(dropMask, droppletsMask)); // 6. Add color tint to the rain drops. color.rgb = mix( color.rgb, dropTint, dropTintIntensity * smoothstep(0.7, 1., max(dropMask, droppletsMask))); // 7. Add highlight to the drops. color.rgb = mix( color.rgb, highlightColor, highlightIntensity * smoothstep(0.05, 0.08, max(dropUvMasked * 1.7, droppletsUvMasked * 2.6)).x); // 8. Add shadows to the drops. color.rgb = mix( color.rgb, contactShadowColor, dropShadowIntensity * smoothstep(0.055, 0.1, max(length(dropUvMasked * 1.7), length(droppletsUvMasked * 1.9)))); return color; } No newline at end of file weathereffects/graphics/assets/shaders/rain_shower.agsl +0 −2 Original line number Diff line number Diff line Loading @@ -41,8 +41,6 @@ Rain generateRain( in float rainIntensity ) { /* Grid. */ // Number of rows and columns (each one is a cell, a drop). float cellAspectRatio = rainGridSize.x / rainGridSize.y; // Aspect ratio impacts visible cells. uv.y /= screenAspectRatio; // scale the UV to allocate number of rows and columns. Loading weathereffects/graphics/assets/shaders/rain_shower_layer.agsl +83 −6 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ uniform mat3 transformMatrixWeather; #include "shaders/rain_shower.agsl" #include "shaders/rain_constants.agsl" #include "shaders/rain_splash.agsl" #include "shaders/glass_rain.agsl" // Controls how visible the rain drops are. const float rainVisibility = 0.4; Loading Loading @@ -79,6 +80,7 @@ vec3 drawSplashes(vec2 uv, vec2 fragCoord, vec3 color) { } vec4 main(float2 fragCoord) { // 1. Generate rain shower. // Apply transform matrix to fragCoord float2 uvTexture = transformPoint(transformMatrixBitmap, fragCoord); // Calculate uv for snow based on transformed coordinates Loading @@ -96,7 +98,7 @@ vec4 main(float2 fragCoord) { float variation = wiggle(time - uv.y * 1.1, 0.10); vec2 uvRot = rotateAroundPoint(uv, vec2(0.5, -1.42), variation * PI / 9.); // 1. Generate a layer of rain behind the subject. // 1.1. Generate a layer of rain behind the subject. Rain rain = generateRain( uvRot, screenAspectRatio, Loading @@ -106,7 +108,7 @@ vec4 main(float2 fragCoord) { color.rgb = mix(color.rgb, highlightColor, rainVisibility * rain.dropMask); // 2. Generate mid layer of rain behind the subject. // 1.2. Generate mid layer of rain behind the subject. rain = generateRain( uvRot, screenAspectRatio, Loading @@ -114,16 +116,16 @@ vec4 main(float2 fragCoord) { /* Grid size = */ vec2(30.0, 4.0) * gridScale, intensity); // 3. Blend those layers. // 1.3. Blend those layers. color.rgb = mix(color.rgb, highlightColor, rainVisibility * rain.dropMask); // 4. Blend with the foreground. Any effect from here will be in front of the subject. // 1.4. Blend with the foreground. Any effect from here will be in front of the subject. color.rgb = normalBlend(color.rgb, colorForeground.rgb, colorForeground.a); // 5. Draw splashes // (1.5. Draw splashes) color.rgb = drawSplashes(uv, fragCoord, color.rgb); // 6. Generate a layer of rain in front of the subject (bigger and faster). // 1.6. Generate a layer of rain in front of the subject (bigger and faster). rain = generateRain( uvRot, screenAspectRatio, Loading @@ -134,5 +136,80 @@ vec4 main(float2 fragCoord) { // Closer rain drops are less visible. color.rgb = mix(color.rgb, highlightColor, 0.7 * rainVisibility * rain.dropMask); // 2. Generate glass rain layer. // 2.0. Calculate UV and add a bit of noise so that the droplets are not perfect circles. float2 glassUv = vec2(valueNoise(fragCoord) * 0.015 - 0.0025) + fragCoord / screenSize; // 2.1. Generate small glass rain. GlassRain smallDrippingRain = generateGlassRain( glassUv, screenAspectRatio, time * 0.7, /* Grid size = */ vec2(5.0, 1.6) * gridScale, intensity * 0.6); float dropMask = smallDrippingRain.dropMask; float droppletsMask = smallDrippingRain.droppletsMask; float trailMask = smallDrippingRain.trailMask; vec2 dropUvMasked = smallDrippingRain.drop * dropMask; vec2 droppletsUvMasked = smallDrippingRain.dropplets * droppletsMask; // 2.2. Generate medium size glass rain. GlassRain medDrippingRain = generateGlassRain( glassUv, screenAspectRatio, time * 0.80, /* Grid size = */ vec2(6., 0.945) * gridScale, intensity * 0.6); // 2.3. Combine those two glass rains. dropMask = max(medDrippingRain.dropMask, dropMask); droppletsMask = max(medDrippingRain.droppletsMask, droppletsMask); trailMask = max(medDrippingRain.trailMask, trailMask); dropUvMasked = mix(dropUvMasked, medDrippingRain.drop * medDrippingRain.dropMask, medDrippingRain.dropMask); droppletsUvMasked = mix(droppletsUvMasked, medDrippingRain.dropplets * medDrippingRain.droppletsMask, medDrippingRain.droppletsMask); // 2.4. Add static rain droplets on the glass surface. (They stay in place and dissapate.) vec2 gridSize = vec2(12., 12.) * gridScale; // Aspect ratio impacts visible cells. gridSize.y /= screenAspectRatio; vec3 staticRain = generateStaticGlassRain(glassUv, time, intensity, gridSize); dropMask = max(dropMask, staticRain.z); dropUvMasked = mix(dropUvMasked, staticRain.xy * staticRain.z, staticRain.z); // 2.5. Distort uv for the rain drops and dropplets. float distortionDrop = -0.1; vec2 uvDiffractionOffsets = distortionDrop * dropUvMasked; vec2 s = screenSize; // Ensure the diffracted image in drops is not inverted. s.y *= -1; vec3 sampledColor = background.eval(uvTexture + uvDiffractionOffsets * s).rgb; sampledColor = imageRangeConversion(sampledColor, 0.84, 0.02, noise, intensity); color.rgb = mix(color.rgb, sampledColor, max(dropMask, droppletsMask)); // 2.6. Add color tint to the rain drops. color.rgb = mix( color.rgb, dropTint, dropTintIntensity * smoothstep(0.7, 1., max(dropMask, droppletsMask))); // 2.7. Add highlight to the drops. color.rgb = mix( color.rgb, highlightColor, highlightIntensity * smoothstep(0.05, 0.08, max(dropUvMasked * 1.7, droppletsUvMasked * 2.6)).x); // 2.8. Add shadows to the drops. color.rgb = mix( color.rgb, contactShadowColor, dropShadowIntensity * smoothstep(0.055, 0.1, max(length(dropUvMasked * 1.7), length(droppletsUvMasked * 1.9)))); return color; } weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/WeatherEffectBase.kt +4 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.util.SizeF import com.google.android.wallpaper.weathereffects.graphics.utils.GraphicsUtils import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.calculateTransformDifference import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.centerCropMatrix import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.getScale import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.invertAndTransposeMatrix import kotlin.random.Random Loading @@ -47,6 +48,7 @@ abstract class WeatherEffectBase( // Apply to weather components not rely on image textures // Should be identity matrix in editor, and only change when parallax applied in homescreen private val transformMatrixWeather: FloatArray = FloatArray(9) protected var bitmapScale = getScale(centerCropMatrix) protected var elapsedTime: Float = 0f abstract val shader: RuntimeShader Loading @@ -56,6 +58,7 @@ abstract class WeatherEffectBase( override fun setMatrix(matrix: Matrix) { this.parallaxMatrix.set(matrix) bitmapScale = getScale(parallaxMatrix) adjustCropping(surfaceSize) } Loading Loading @@ -111,6 +114,7 @@ abstract class WeatherEffectBase( SizeF(background.width.toFloat(), background.height.toFloat()), ) parallaxMatrix.set(centerCropMatrix) bitmapScale = getScale(centerCropMatrix) shader.setInputBuffer( "background", BitmapShader(this.background, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR), Loading weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/rain/RainEffect.kt +24 −47 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package com.google.android.wallpaper.weathereffects.graphics.rain import android.graphics.Bitmap import android.graphics.BitmapShader import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.RenderEffect import android.graphics.RuntimeShader Loading @@ -29,7 +28,6 @@ import com.google.android.wallpaper.weathereffects.graphics.FrameBuffer import com.google.android.wallpaper.weathereffects.graphics.WeatherEffect.Companion.DEFAULT_INTENSITY import com.google.android.wallpaper.weathereffects.graphics.WeatherEffectBase import com.google.android.wallpaper.weathereffects.graphics.utils.GraphicsUtils import com.google.android.wallpaper.weathereffects.graphics.utils.SolidColorShader import com.google.android.wallpaper.weathereffects.graphics.utils.TimeUtils import java.util.concurrent.Executor Loading @@ -46,12 +44,17 @@ class RainEffect( ) : WeatherEffectBase(foreground, background, surfaceSize) { private val rainPaint = Paint().also { it.shader = rainConfig.colorGradingShader } // Set blur effect to reduce the outline noise. No need to set blur effect every time we // re-generate the outline buffer. // Outline buffer is set with bitmap size, so we need to multiply blur radius by scale to get // consistent blur across different surface private var outlineBuffer = FrameBuffer(background.width, background.height).apply { setRenderEffect(RenderEffect.createBlurEffect(2f, 2f, Shader.TileMode.CLAMP)) setRenderEffect( RenderEffect.createBlurEffect( 2f / bitmapScale, 2f / bitmapScale, Shader.TileMode.CLAMP, ) ) } private val outlineBufferPaint = Paint().also { it.shader = rainConfig.outlineShader } Loading @@ -67,43 +70,19 @@ class RainEffect( elapsedTime += TimeUtils.millisToSeconds(deltaMillis) rainConfig.rainShowerShader.setFloatUniform("time", elapsedTime) rainConfig.glassRainShader.setFloatUniform("time", elapsedTime) rainConfig.glassRainShader.setInputShader("texture", rainConfig.rainShowerShader) rainConfig.colorGradingShader.setInputShader("texture", rainConfig.glassRainShader) rainConfig.colorGradingShader.setInputShader("texture", rainConfig.rainShowerShader) } override fun draw(canvas: Canvas) { canvas.drawPaint(rainPaint) } override fun release() { super.release() outlineBuffer.close() } override fun setIntensity(intensity: Float) { super.setIntensity(intensity) rainConfig.glassRainShader.setFloatUniform("intensity", intensity) val thickness = 1f + intensity * 10f rainConfig.outlineShader.setFloatUniform("thickness", thickness) // Need to recreate the outline buffer as the uniform has changed. createOutlineBuffer() } override fun setBitmaps(foreground: Bitmap?, background: Bitmap): Boolean { if (!super.setBitmaps(foreground, background)) { return false } outlineBuffer.close() outlineBuffer = FrameBuffer(background.width, background.height).apply { setRenderEffect(RenderEffect.createBlurEffect(2f, 2f, Shader.TileMode.CLAMP)) } updateTextureUniforms() // Need to recreate the outline buffer as the outlineBuffer has changed due to background updateTextureUniforms() createOutlineBuffer() return true } Loading @@ -120,18 +99,6 @@ class RainEffect( override val colorGradingIntensity: Float get() = rainConfig.colorGradingIntensity override fun adjustCropping(newSurfaceSize: SizeF) { super.adjustCropping(newSurfaceSize) rainConfig.glassRainShader.setFloatUniform( "screenSize", newSurfaceSize.width, newSurfaceSize.height, ) val screenAspectRatio = GraphicsUtils.getAspectRatio(newSurfaceSize) rainConfig.glassRainShader.setFloatUniform("screenAspectRatio", screenAspectRatio) } override fun updateTextureUniforms() { val foregroundBuffer = BitmapShader(super.foreground, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR) Loading @@ -144,7 +111,15 @@ class RainEffect( ) } /** * It's necessary to create outline buffer only when bitmaps change, only intensity change won't * create a new one cause we refer to intensity in each cell when drawing splashes. */ private fun createOutlineBuffer() { rainConfig.outlineShader.setFloatUniform( "thickness", MAX_RAIN_OUTLINE_THICKNESS / bitmapScale, ) val canvas = outlineBuffer.beginDrawing() canvas.drawPaint(outlineBufferPaint) outlineBuffer.endDrawing() Loading @@ -162,8 +137,7 @@ class RainEffect( private fun prepareColorGrading() { // Initialize the buffer with black, so that we don't ever draw garbage buffer. rainConfig.glassRainShader.setInputShader("texture", SolidColorShader(Color.BLACK)) rainConfig.colorGradingShader.setInputShader("texture", rainConfig.glassRainShader) rainConfig.colorGradingShader.setInputShader("texture", rainConfig.rainShowerShader) rainConfig.lut?.let { rainConfig.colorGradingShader.setInputShader( "lut", Loading @@ -176,6 +150,9 @@ class RainEffect( val widthScreenScale = GraphicsUtils.computeDefaultGridSize(newSurfaceSize, rainConfig.pixelDensity) rainConfig.rainShowerShader.setFloatUniform("gridScale", widthScreenScale) rainConfig.glassRainShader.setFloatUniform("gridScale", widthScreenScale) } companion object { const val MAX_RAIN_OUTLINE_THICKNESS = 11f } } Loading
weathereffects/graphics/assets/shaders/rain_glass_layer.agsldeleted 100644 → 0 +0 −105 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ uniform shader texture; uniform float time; uniform float screenAspectRatio; uniform float gridScale; uniform float2 screenSize; uniform half intensity; #include "shaders/constants.agsl" #include "shaders/utils.agsl" #include "shaders/glass_rain.agsl" #include "shaders/rain_constants.agsl" vec4 main(float2 fragCoord) { // 0. Calculate UV and add a bit of noise so that the droplets are not perfect circles. float2 uv = vec2(valueNoise(fragCoord) * 0.015 - 0.0025) + fragCoord / screenSize; // 1. Generate small glass rain. GlassRain smallDrippingRain = generateGlassRain( uv, screenAspectRatio, time * 0.7, /* Grid size = */ vec2(5.0, 1.6) * gridScale, intensity * 0.6); float dropMask = smallDrippingRain.dropMask; float droppletsMask = smallDrippingRain.droppletsMask; float trailMask = smallDrippingRain.trailMask; vec2 dropUvMasked = smallDrippingRain.drop * dropMask; vec2 droppletsUvMasked = smallDrippingRain.dropplets * droppletsMask; // 2. Generate medium size glass rain. GlassRain medDrippingRain = generateGlassRain( uv, screenAspectRatio, time * 0.80, /* Grid size = */ vec2(6., 0.945) * gridScale, intensity * 0.6); // 3. Combine those two glass rains. dropMask = max(medDrippingRain.dropMask, dropMask); droppletsMask = max(medDrippingRain.droppletsMask, droppletsMask); trailMask = max(medDrippingRain.trailMask, trailMask); dropUvMasked = mix(dropUvMasked, medDrippingRain.drop * medDrippingRain.dropMask, medDrippingRain.dropMask); droppletsUvMasked = mix(droppletsUvMasked, medDrippingRain.dropplets * medDrippingRain.droppletsMask, medDrippingRain.droppletsMask); // 4. Add static rain droplets on the glass surface. (They stay in place and dissapate.) vec2 gridSize = vec2(12., 12.) * gridScale; // Aspect ratio impacts visible cells. gridSize.y /= screenAspectRatio; vec3 staticRain = generateStaticGlassRain(uv, time, intensity, gridSize); dropMask = max(dropMask, staticRain.z); dropUvMasked = mix(dropUvMasked, staticRain.xy * staticRain.z, staticRain.z); // 5. Distort uv for the rain drops and dropplets. float distortionDrop = -0.1; vec2 uvDiffractionOffsets = distortionDrop * dropUvMasked; vec2 s = screenSize; // Ensure the diffracted image in drops is not inverted. s.y *= -1; vec4 color = texture.eval(fragCoord); vec3 sampledColor = texture.eval(fragCoord + uvDiffractionOffsets * s).rgb; color.rgb = mix(color.rgb, sampledColor, max(dropMask, droppletsMask)); // 6. Add color tint to the rain drops. color.rgb = mix( color.rgb, dropTint, dropTintIntensity * smoothstep(0.7, 1., max(dropMask, droppletsMask))); // 7. Add highlight to the drops. color.rgb = mix( color.rgb, highlightColor, highlightIntensity * smoothstep(0.05, 0.08, max(dropUvMasked * 1.7, droppletsUvMasked * 2.6)).x); // 8. Add shadows to the drops. color.rgb = mix( color.rgb, contactShadowColor, dropShadowIntensity * smoothstep(0.055, 0.1, max(length(dropUvMasked * 1.7), length(droppletsUvMasked * 1.9)))); return color; } No newline at end of file
weathereffects/graphics/assets/shaders/rain_shower.agsl +0 −2 Original line number Diff line number Diff line Loading @@ -41,8 +41,6 @@ Rain generateRain( in float rainIntensity ) { /* Grid. */ // Number of rows and columns (each one is a cell, a drop). float cellAspectRatio = rainGridSize.x / rainGridSize.y; // Aspect ratio impacts visible cells. uv.y /= screenAspectRatio; // scale the UV to allocate number of rows and columns. Loading
weathereffects/graphics/assets/shaders/rain_shower_layer.agsl +83 −6 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ uniform mat3 transformMatrixWeather; #include "shaders/rain_shower.agsl" #include "shaders/rain_constants.agsl" #include "shaders/rain_splash.agsl" #include "shaders/glass_rain.agsl" // Controls how visible the rain drops are. const float rainVisibility = 0.4; Loading Loading @@ -79,6 +80,7 @@ vec3 drawSplashes(vec2 uv, vec2 fragCoord, vec3 color) { } vec4 main(float2 fragCoord) { // 1. Generate rain shower. // Apply transform matrix to fragCoord float2 uvTexture = transformPoint(transformMatrixBitmap, fragCoord); // Calculate uv for snow based on transformed coordinates Loading @@ -96,7 +98,7 @@ vec4 main(float2 fragCoord) { float variation = wiggle(time - uv.y * 1.1, 0.10); vec2 uvRot = rotateAroundPoint(uv, vec2(0.5, -1.42), variation * PI / 9.); // 1. Generate a layer of rain behind the subject. // 1.1. Generate a layer of rain behind the subject. Rain rain = generateRain( uvRot, screenAspectRatio, Loading @@ -106,7 +108,7 @@ vec4 main(float2 fragCoord) { color.rgb = mix(color.rgb, highlightColor, rainVisibility * rain.dropMask); // 2. Generate mid layer of rain behind the subject. // 1.2. Generate mid layer of rain behind the subject. rain = generateRain( uvRot, screenAspectRatio, Loading @@ -114,16 +116,16 @@ vec4 main(float2 fragCoord) { /* Grid size = */ vec2(30.0, 4.0) * gridScale, intensity); // 3. Blend those layers. // 1.3. Blend those layers. color.rgb = mix(color.rgb, highlightColor, rainVisibility * rain.dropMask); // 4. Blend with the foreground. Any effect from here will be in front of the subject. // 1.4. Blend with the foreground. Any effect from here will be in front of the subject. color.rgb = normalBlend(color.rgb, colorForeground.rgb, colorForeground.a); // 5. Draw splashes // (1.5. Draw splashes) color.rgb = drawSplashes(uv, fragCoord, color.rgb); // 6. Generate a layer of rain in front of the subject (bigger and faster). // 1.6. Generate a layer of rain in front of the subject (bigger and faster). rain = generateRain( uvRot, screenAspectRatio, Loading @@ -134,5 +136,80 @@ vec4 main(float2 fragCoord) { // Closer rain drops are less visible. color.rgb = mix(color.rgb, highlightColor, 0.7 * rainVisibility * rain.dropMask); // 2. Generate glass rain layer. // 2.0. Calculate UV and add a bit of noise so that the droplets are not perfect circles. float2 glassUv = vec2(valueNoise(fragCoord) * 0.015 - 0.0025) + fragCoord / screenSize; // 2.1. Generate small glass rain. GlassRain smallDrippingRain = generateGlassRain( glassUv, screenAspectRatio, time * 0.7, /* Grid size = */ vec2(5.0, 1.6) * gridScale, intensity * 0.6); float dropMask = smallDrippingRain.dropMask; float droppletsMask = smallDrippingRain.droppletsMask; float trailMask = smallDrippingRain.trailMask; vec2 dropUvMasked = smallDrippingRain.drop * dropMask; vec2 droppletsUvMasked = smallDrippingRain.dropplets * droppletsMask; // 2.2. Generate medium size glass rain. GlassRain medDrippingRain = generateGlassRain( glassUv, screenAspectRatio, time * 0.80, /* Grid size = */ vec2(6., 0.945) * gridScale, intensity * 0.6); // 2.3. Combine those two glass rains. dropMask = max(medDrippingRain.dropMask, dropMask); droppletsMask = max(medDrippingRain.droppletsMask, droppletsMask); trailMask = max(medDrippingRain.trailMask, trailMask); dropUvMasked = mix(dropUvMasked, medDrippingRain.drop * medDrippingRain.dropMask, medDrippingRain.dropMask); droppletsUvMasked = mix(droppletsUvMasked, medDrippingRain.dropplets * medDrippingRain.droppletsMask, medDrippingRain.droppletsMask); // 2.4. Add static rain droplets on the glass surface. (They stay in place and dissapate.) vec2 gridSize = vec2(12., 12.) * gridScale; // Aspect ratio impacts visible cells. gridSize.y /= screenAspectRatio; vec3 staticRain = generateStaticGlassRain(glassUv, time, intensity, gridSize); dropMask = max(dropMask, staticRain.z); dropUvMasked = mix(dropUvMasked, staticRain.xy * staticRain.z, staticRain.z); // 2.5. Distort uv for the rain drops and dropplets. float distortionDrop = -0.1; vec2 uvDiffractionOffsets = distortionDrop * dropUvMasked; vec2 s = screenSize; // Ensure the diffracted image in drops is not inverted. s.y *= -1; vec3 sampledColor = background.eval(uvTexture + uvDiffractionOffsets * s).rgb; sampledColor = imageRangeConversion(sampledColor, 0.84, 0.02, noise, intensity); color.rgb = mix(color.rgb, sampledColor, max(dropMask, droppletsMask)); // 2.6. Add color tint to the rain drops. color.rgb = mix( color.rgb, dropTint, dropTintIntensity * smoothstep(0.7, 1., max(dropMask, droppletsMask))); // 2.7. Add highlight to the drops. color.rgb = mix( color.rgb, highlightColor, highlightIntensity * smoothstep(0.05, 0.08, max(dropUvMasked * 1.7, droppletsUvMasked * 2.6)).x); // 2.8. Add shadows to the drops. color.rgb = mix( color.rgb, contactShadowColor, dropShadowIntensity * smoothstep(0.055, 0.1, max(length(dropUvMasked * 1.7), length(droppletsUvMasked * 1.9)))); return color; }
weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/WeatherEffectBase.kt +4 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.util.SizeF import com.google.android.wallpaper.weathereffects.graphics.utils.GraphicsUtils import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.calculateTransformDifference import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.centerCropMatrix import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.getScale import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.invertAndTransposeMatrix import kotlin.random.Random Loading @@ -47,6 +48,7 @@ abstract class WeatherEffectBase( // Apply to weather components not rely on image textures // Should be identity matrix in editor, and only change when parallax applied in homescreen private val transformMatrixWeather: FloatArray = FloatArray(9) protected var bitmapScale = getScale(centerCropMatrix) protected var elapsedTime: Float = 0f abstract val shader: RuntimeShader Loading @@ -56,6 +58,7 @@ abstract class WeatherEffectBase( override fun setMatrix(matrix: Matrix) { this.parallaxMatrix.set(matrix) bitmapScale = getScale(parallaxMatrix) adjustCropping(surfaceSize) } Loading Loading @@ -111,6 +114,7 @@ abstract class WeatherEffectBase( SizeF(background.width.toFloat(), background.height.toFloat()), ) parallaxMatrix.set(centerCropMatrix) bitmapScale = getScale(centerCropMatrix) shader.setInputBuffer( "background", BitmapShader(this.background, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR), Loading
weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/rain/RainEffect.kt +24 −47 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package com.google.android.wallpaper.weathereffects.graphics.rain import android.graphics.Bitmap import android.graphics.BitmapShader import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.RenderEffect import android.graphics.RuntimeShader Loading @@ -29,7 +28,6 @@ import com.google.android.wallpaper.weathereffects.graphics.FrameBuffer import com.google.android.wallpaper.weathereffects.graphics.WeatherEffect.Companion.DEFAULT_INTENSITY import com.google.android.wallpaper.weathereffects.graphics.WeatherEffectBase import com.google.android.wallpaper.weathereffects.graphics.utils.GraphicsUtils import com.google.android.wallpaper.weathereffects.graphics.utils.SolidColorShader import com.google.android.wallpaper.weathereffects.graphics.utils.TimeUtils import java.util.concurrent.Executor Loading @@ -46,12 +44,17 @@ class RainEffect( ) : WeatherEffectBase(foreground, background, surfaceSize) { private val rainPaint = Paint().also { it.shader = rainConfig.colorGradingShader } // Set blur effect to reduce the outline noise. No need to set blur effect every time we // re-generate the outline buffer. // Outline buffer is set with bitmap size, so we need to multiply blur radius by scale to get // consistent blur across different surface private var outlineBuffer = FrameBuffer(background.width, background.height).apply { setRenderEffect(RenderEffect.createBlurEffect(2f, 2f, Shader.TileMode.CLAMP)) setRenderEffect( RenderEffect.createBlurEffect( 2f / bitmapScale, 2f / bitmapScale, Shader.TileMode.CLAMP, ) ) } private val outlineBufferPaint = Paint().also { it.shader = rainConfig.outlineShader } Loading @@ -67,43 +70,19 @@ class RainEffect( elapsedTime += TimeUtils.millisToSeconds(deltaMillis) rainConfig.rainShowerShader.setFloatUniform("time", elapsedTime) rainConfig.glassRainShader.setFloatUniform("time", elapsedTime) rainConfig.glassRainShader.setInputShader("texture", rainConfig.rainShowerShader) rainConfig.colorGradingShader.setInputShader("texture", rainConfig.glassRainShader) rainConfig.colorGradingShader.setInputShader("texture", rainConfig.rainShowerShader) } override fun draw(canvas: Canvas) { canvas.drawPaint(rainPaint) } override fun release() { super.release() outlineBuffer.close() } override fun setIntensity(intensity: Float) { super.setIntensity(intensity) rainConfig.glassRainShader.setFloatUniform("intensity", intensity) val thickness = 1f + intensity * 10f rainConfig.outlineShader.setFloatUniform("thickness", thickness) // Need to recreate the outline buffer as the uniform has changed. createOutlineBuffer() } override fun setBitmaps(foreground: Bitmap?, background: Bitmap): Boolean { if (!super.setBitmaps(foreground, background)) { return false } outlineBuffer.close() outlineBuffer = FrameBuffer(background.width, background.height).apply { setRenderEffect(RenderEffect.createBlurEffect(2f, 2f, Shader.TileMode.CLAMP)) } updateTextureUniforms() // Need to recreate the outline buffer as the outlineBuffer has changed due to background updateTextureUniforms() createOutlineBuffer() return true } Loading @@ -120,18 +99,6 @@ class RainEffect( override val colorGradingIntensity: Float get() = rainConfig.colorGradingIntensity override fun adjustCropping(newSurfaceSize: SizeF) { super.adjustCropping(newSurfaceSize) rainConfig.glassRainShader.setFloatUniform( "screenSize", newSurfaceSize.width, newSurfaceSize.height, ) val screenAspectRatio = GraphicsUtils.getAspectRatio(newSurfaceSize) rainConfig.glassRainShader.setFloatUniform("screenAspectRatio", screenAspectRatio) } override fun updateTextureUniforms() { val foregroundBuffer = BitmapShader(super.foreground, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR) Loading @@ -144,7 +111,15 @@ class RainEffect( ) } /** * It's necessary to create outline buffer only when bitmaps change, only intensity change won't * create a new one cause we refer to intensity in each cell when drawing splashes. */ private fun createOutlineBuffer() { rainConfig.outlineShader.setFloatUniform( "thickness", MAX_RAIN_OUTLINE_THICKNESS / bitmapScale, ) val canvas = outlineBuffer.beginDrawing() canvas.drawPaint(outlineBufferPaint) outlineBuffer.endDrawing() Loading @@ -162,8 +137,7 @@ class RainEffect( private fun prepareColorGrading() { // Initialize the buffer with black, so that we don't ever draw garbage buffer. rainConfig.glassRainShader.setInputShader("texture", SolidColorShader(Color.BLACK)) rainConfig.colorGradingShader.setInputShader("texture", rainConfig.glassRainShader) rainConfig.colorGradingShader.setInputShader("texture", rainConfig.rainShowerShader) rainConfig.lut?.let { rainConfig.colorGradingShader.setInputShader( "lut", Loading @@ -176,6 +150,9 @@ class RainEffect( val widthScreenScale = GraphicsUtils.computeDefaultGridSize(newSurfaceSize, rainConfig.pixelDensity) rainConfig.rainShowerShader.setFloatUniform("gridScale", widthScreenScale) rainConfig.glassRainShader.setFloatUniform("gridScale", widthScreenScale) } companion object { const val MAX_RAIN_OUTLINE_THICKNESS = 11f } }