diff options
author | 2021-11-05 19:25:05 +0000 | |
---|---|---|
committer | 2021-12-17 02:44:46 +0000 | |
commit | 56c079839121da5d368d4aadeaceeff558ee106b (patch) | |
tree | 1f2134ea697ca6d689cc9942759724b76108c00b | |
parent | 1cac926292f5e6e7144add5ab1ba646112f27749 (diff) |
Add RuntimeShader API to RenderEffect
Bug: 201546136
Test: atest CtsUiRenderingTestCases:RuntimeShaderTests
Change-Id: I96ad4fcfc0486f340653878519efcc4a793191a2
-rw-r--r-- | core/api/current.txt | 1 | ||||
-rw-r--r-- | graphics/java/android/graphics/RenderEffect.java | 18 | ||||
-rw-r--r-- | libs/hwui/jni/RenderEffect.cpp | 45 | ||||
-rw-r--r-- | tests/HwAccelerationTest/Android.bp | 4 | ||||
-rw-r--r-- | tests/HwAccelerationTest/AndroidManifest.xml | 9 | ||||
-rw-r--r-- | tests/HwAccelerationTest/res/drawable-nodpi/scratches.png | bin | 0 -> 248848 bytes | |||
-rw-r--r-- | tests/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg | bin | 0 -> 706520 bytes | |||
-rw-r--r-- | tests/HwAccelerationTest/res/layout/view_runtime_shader.xml | 205 | ||||
-rw-r--r-- | tests/HwAccelerationTest/res/values/styles.xml | 1 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt | 138 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt | 109 |
11 files changed, 521 insertions, 9 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index f84322eb7a04..4b9f57e1f185 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -16518,6 +16518,7 @@ package android.graphics { method @NonNull public static android.graphics.RenderEffect createColorFilterEffect(@NonNull android.graphics.ColorFilter); method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float); method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float, @NonNull android.graphics.RenderEffect); + method @NonNull public static android.graphics.RenderEffect createRuntimeShaderEffect(@NonNull android.graphics.RuntimeShader, @NonNull String); method @NonNull public static android.graphics.RenderEffect createShaderEffect(@NonNull android.graphics.Shader); } diff --git a/graphics/java/android/graphics/RenderEffect.java b/graphics/java/android/graphics/RenderEffect.java index ad4c3fe86175..b8a46856601e 100644 --- a/graphics/java/android/graphics/RenderEffect.java +++ b/graphics/java/android/graphics/RenderEffect.java @@ -290,6 +290,22 @@ public final class RenderEffect { return new RenderEffect(nativeCreateShaderEffect(shader.getNativeInstance())); } + /** + * Create a {@link RenderEffect} that executes the provided {@link RuntimeShader} and passes + * the contents of the {@link android.graphics.RenderNode} that this RenderEffect is installed + * on as an input to the shader. + * @param shader the runtime shader that will bind the inputShaderName to the RenderEffect input + * @param uniformShaderName the uniform name defined in the RuntimeShader's program to which + * the contents of the RenderNode will be bound + */ + @NonNull + public static RenderEffect createRuntimeShaderEffect( + @NonNull RuntimeShader shader, @NonNull String uniformShaderName) { + return new RenderEffect( + nativeCreateRuntimeShaderEffect(shader.getNativeShaderBuilder(), + uniformShaderName)); + } + private final long mNativeRenderEffect; /* only constructed from static factory methods */ @@ -318,5 +334,7 @@ public final class RenderEffect { private static native long nativeCreateBlendModeEffect(long dst, long src, int blendmode); private static native long nativeCreateChainEffect(long outer, long inner); private static native long nativeCreateShaderEffect(long shader); + private static native long nativeCreateRuntimeShaderEffect( + long shaderBuilder, String inputShaderName); private static native long nativeGetFinalizer(); } diff --git a/libs/hwui/jni/RenderEffect.cpp b/libs/hwui/jni/RenderEffect.cpp index a48d7f734e29..213f35a81b88 100644 --- a/libs/hwui/jni/RenderEffect.cpp +++ b/libs/hwui/jni/RenderEffect.cpp @@ -127,6 +127,32 @@ static jlong createShaderEffect( return reinterpret_cast<jlong>(shaderFilter.release()); } +static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args); + va_end(args); + return ret; +} + +static jlong createRuntimeShaderEffect(JNIEnv* env, jobject, jlong shaderBuilderHandle, + jstring inputShaderName) { + SkRuntimeShaderBuilder* builder = + reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilderHandle); + ScopedUtfChars name(env, inputShaderName); + + if (builder->child(name.c_str()).fChild == nullptr) { + ThrowIAEFmt(env, + "unable to find a uniform with the name '%s' of the correct " + "type defined by the provided RuntimeShader", + name.c_str()); + return 0; + } + + sk_sp<SkImageFilter> filter = SkImageFilters::RuntimeShader(*builder, name.c_str(), nullptr); + return reinterpret_cast<jlong>(filter.release()); +} + static void RenderEffect_safeUnref(SkImageFilter* filter) { SkSafeUnref(filter); } @@ -136,15 +162,16 @@ static jlong getRenderEffectFinalizer(JNIEnv*, jobject) { } static const JNINativeMethod gRenderEffectMethods[] = { - {"nativeGetFinalizer", "()J", (void*)getRenderEffectFinalizer}, - {"nativeCreateOffsetEffect", "(FFJ)J", (void*)createOffsetEffect}, - {"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect}, - {"nativeCreateBitmapEffect", "(JFFFFFFFF)J", (void*)createBitmapEffect}, - {"nativeCreateColorFilterEffect", "(JJ)J", (void*)createColorFilterEffect}, - {"nativeCreateBlendModeEffect", "(JJI)J", (void*)createBlendModeEffect}, - {"nativeCreateChainEffect", "(JJ)J", (void*)createChainEffect}, - {"nativeCreateShaderEffect", "(J)J", (void*)createShaderEffect} -}; + {"nativeGetFinalizer", "()J", (void*)getRenderEffectFinalizer}, + {"nativeCreateOffsetEffect", "(FFJ)J", (void*)createOffsetEffect}, + {"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect}, + {"nativeCreateBitmapEffect", "(JFFFFFFFF)J", (void*)createBitmapEffect}, + {"nativeCreateColorFilterEffect", "(JJ)J", (void*)createColorFilterEffect}, + {"nativeCreateBlendModeEffect", "(JJI)J", (void*)createBlendModeEffect}, + {"nativeCreateChainEffect", "(JJ)J", (void*)createChainEffect}, + {"nativeCreateShaderEffect", "(J)J", (void*)createShaderEffect}, + {"nativeCreateRuntimeShaderEffect", "(JLjava/lang/String;)J", + (void*)createRuntimeShaderEffect}}; int register_android_graphics_RenderEffect(JNIEnv* env) { android::RegisterMethodsOrDie(env, "android/graphics/RenderEffect", diff --git a/tests/HwAccelerationTest/Android.bp b/tests/HwAccelerationTest/Android.bp index e618ed1e3ab9..51848f2857c9 100644 --- a/tests/HwAccelerationTest/Android.bp +++ b/tests/HwAccelerationTest/Android.bp @@ -32,6 +32,10 @@ android_test { "**/*.java", "**/*.kt", ], + static_libs: [ + "androidx.cardview_cardview", + ], + platform_apis: true, certificate: "platform", } diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 22fe4242fbbb..b0ccbd1cf22f 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -789,6 +789,15 @@ </intent-filter> </activity> + <activity android:name="RenderEffectViewActivity" + android:label="RenderEffect/View" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="com.android.test.hwui.TEST"/> + </intent-filter> + </activity> + <activity android:name="StretchShaderActivity" android:label="RenderEffect/Stretch" android:exported="true"> diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/scratches.png b/tests/HwAccelerationTest/res/drawable-nodpi/scratches.png Binary files differnew file mode 100644 index 000000000000..cc8adf15f4f0 --- /dev/null +++ b/tests/HwAccelerationTest/res/drawable-nodpi/scratches.png diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg b/tests/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg Binary files differnew file mode 100644 index 000000000000..b5aff104207a --- /dev/null +++ b/tests/HwAccelerationTest/res/drawable-nodpi/weather_2.jpg diff --git a/tests/HwAccelerationTest/res/layout/view_runtime_shader.xml b/tests/HwAccelerationTest/res/layout/view_runtime_shader.xml new file mode 100644 index 000000000000..b91377d1ab49 --- /dev/null +++ b/tests/HwAccelerationTest/res/layout/view_runtime_shader.xml @@ -0,0 +1,205 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2021 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. + --> + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <LinearLayout + android:id="@+id/TopLayout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingBottom="8dp" + android:orientation="vertical"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:text="Sample Card #1"/> + + <androidx.cardview.widget.CardView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:layout_marginBottom="16dp" + android:clickable="true" + android:focusable="true" + android:minHeight="148dp"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="16dp" + android:paddingBottom="8dp"> + + <ImageView + android:layout_width="50dp" + android:layout_height="50dp" + android:layout_marginEnd="8dp" + android:layout_marginRight="8dp" + android:contentDescription="Logo" + android:src="@drawable/icon"/> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1.0" + android:layout_marginStart="8dp" + android:layout_marginLeft="8dp" + android:orientation="vertical"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textStyle="bold" + android:text="Image Transition"/> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:ellipsize="end" + android:maxLines="1" + android:text="Touch the image to trigger the animation"/> + </LinearLayout> + </LinearLayout> + + <com.android.test.hwui.BitmapTransitionView + android:layout_width="match_parent" + android:layout_height="194dp" + android:padding="8dp"/> + + </LinearLayout> + + </androidx.cardview.widget.CardView> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="16dp" + android:text="Sample Card #2"/> + + <androidx.cardview.widget.CardView + android:id="@+id/CardView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:layout_marginBottom="16dp" + android:clickable="true" + android:focusable="true" + android:minHeight="148dp"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="16dp" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="16dp" + android:paddingBottom="8dp"> + + <ImageView + android:layout_width="50dp" + android:layout_height="50dp" + android:layout_marginEnd="8dp" + android:layout_marginRight="8dp" + android:contentDescription="Logo" + android:src="@drawable/icon"/> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1.0" + android:layout_marginStart="8dp" + android:layout_marginLeft="8dp" + android:orientation="vertical"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textStyle="bold" + android:text="View Group Manipulation"/> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:ellipsize="end" + android:maxLines="1" + android:text="Tap the card to trigger the animation"/> + </LinearLayout> + </LinearLayout> + + <ImageView + android:layout_width="match_parent" + android:layout_height="194dp" + android:background="@android:color/transparent" + android:src="@drawable/weather_2"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="16dp" + android:paddingBottom="8dp" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <RatingBar + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="Card Rating" + android:isIndicator="true" + android:numStars="5" + android:rating="4.5" + + android:stepSize="0.5"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center_vertical" + android:text="Category 4.5 Storm"/> + </LinearLayout> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:maxLines="3" + android:textIsSelectable="true" + android:text="Lorem ipsum dolor sit amet, nec no nominavi scaevola. Per et + sint sapientem, nobis perpetua salutandi mei te. Quo tamquam probatus + reprehendunt in. Eos esse purto eruditi ea. Enim tation persius ut sea, + eos ad consul populo. Ne eum solet altera. Cibo eligendi et est, electram + theophrastus te vel eu."/> + + </LinearLayout> + + </LinearLayout> + + </androidx.cardview.widget.CardView> + </LinearLayout> +</ScrollView> diff --git a/tests/HwAccelerationTest/res/values/styles.xml b/tests/HwAccelerationTest/res/values/styles.xml index fa5437f38ace..55f4dd697907 100644 --- a/tests/HwAccelerationTest/res/values/styles.xml +++ b/tests/HwAccelerationTest/res/values/styles.xml @@ -41,4 +41,5 @@ <item name="android:spotShadowAlpha">1</item> --> </style> + </resources> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt new file mode 100644 index 000000000000..d3ad9e8193c0 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2021 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. + */ + +package com.android.test.hwui + +import android.animation.ValueAnimator +import android.content.Context +import android.graphics.BitmapShader +import android.graphics.Canvas +import android.graphics.ImageDecoder +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.RuntimeShader +import android.graphics.Shader +import android.util.AttributeSet +import android.view.View + +class BitmapTransitionView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : View(context, attrs, defStyleAttr) { + + private val mPaint = Paint() + private val mImageA = ImageDecoder.decodeBitmap( + ImageDecoder.createSource(context.resources, R.drawable.large_photo)) + private val mImageB = ImageDecoder.decodeBitmap( + ImageDecoder.createSource(context.resources, R.drawable.very_large_photo)) + private val mShaderA = BitmapShader(mImageA, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) + private val mShaderB = BitmapShader(mImageB, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) + private val mShader = RuntimeShader(AGSL, false) + private var mCurrentProgress = -1f + private var mForwardProgress = true + private var mCurrentAnimator = ValueAnimator.ofFloat(-1f, 1f) + + init { + isClickable = true + + mCurrentAnimator.duration = 1500 + mCurrentAnimator.addUpdateListener { animation -> + mCurrentProgress = animation.animatedValue as Float + postInvalidate() + } + } + + override fun performClick(): Boolean { + if (super.performClick()) return true + + if (mCurrentAnimator.isRunning) { + mCurrentAnimator.reverse() + return true + } + + if (mForwardProgress) { + mCurrentAnimator.setFloatValues(-1f, 1f) + mForwardProgress = false + } else { + mCurrentAnimator.setFloatValues(1f, -1f) + mForwardProgress = true + } + + mCurrentAnimator.start() + postInvalidate() + return true + } + + override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) { + val matrixA = Matrix() + val matrixB = Matrix() + + matrixA.postScale(width.toFloat() / mImageA.width, height.toFloat() / mImageA.height) + matrixB.postScale(width.toFloat() / mImageB.width, height.toFloat() / mImageB.height) + + mShaderA.setLocalMatrix(matrixA) + mShaderB.setLocalMatrix(matrixB) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + mShader.setInputShader("imageA", mShaderA) + mShader.setInputShader("imageB", mShaderB) + mShader.setIntUniform("imageDimensions", width, height) + mShader.setFloatUniform("progress", mCurrentProgress) + + mPaint.shader = mShader + canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), mPaint) + } + + private companion object { + const val AGSL = """ + uniform shader imageA; + uniform shader imageB; + uniform ivec2 imageDimensions; + uniform float progress; + + const vec2 iSize = vec2(48.0, 48.0); + const float iDir = 0.5; + const float iRand = 0.81; + + float hash12(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * .1031); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.x + p3.y) * p3.z); + } + + float ramp(float2 p) { + return mix(hash12(p), + dot(p/vec2(imageDimensions), float2(iDir, 1 - iDir)), + iRand); + } + + half4 main(float2 p) { + float2 lowRes = p / iSize; + float2 cellCenter = (floor(lowRes) + 0.5) * iSize; + float2 posInCell = fract(lowRes) * 2 - 1; + + float v = ramp(cellCenter) + progress; + float distToCenter = max(abs(posInCell.x), abs(posInCell.y)); + + return distToCenter > v ? imageA.eval(p).rgb1 : imageB.eval(p).rgb1; + } + """ + } +}
\ No newline at end of file diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt new file mode 100644 index 000000000000..06280d295425 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2021 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. + */ + +package com.android.test.hwui + +import android.animation.ValueAnimator +import android.app.Activity +import android.graphics.Bitmap +import android.graphics.BitmapShader +import android.graphics.ImageDecoder +import android.graphics.Matrix +import android.graphics.Shader +import android.graphics.RenderEffect +import android.graphics.RuntimeShader +import android.os.Bundle +import android.view.View + +class RenderEffectViewActivity : Activity() { + + private val mDropsShader = RuntimeShader(dropsAGSL, false) + private var mDropsAnimator = ValueAnimator.ofFloat(0f, 1f) + private var mStartTime = System.currentTimeMillis() + private lateinit var mScratchesImage: Bitmap + private lateinit var mScratchesShader: BitmapShader + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.view_runtime_shader) + + val dropsView = findViewById<View>(R.id.CardView)!! + dropsView.isClickable = true + dropsView.setOnClickListener { + if (mDropsAnimator.isRunning) { + mDropsAnimator.cancel() + dropsView.setRenderEffect(null) + } else { + mDropsAnimator.start() + } + } + + val imgSource = ImageDecoder.createSource(resources, R.drawable.scratches) + mScratchesImage = ImageDecoder.decodeBitmap(imgSource) + mScratchesShader = BitmapShader(mScratchesImage, + Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) + + mDropsAnimator.duration = 1000 + mDropsAnimator.repeatCount = ValueAnimator.INFINITE + mDropsAnimator.addUpdateListener { _ -> + val viewWidth = dropsView.width.toFloat() + val viewHeight = dropsView.height.toFloat() + val scratchesMatrix = Matrix() + scratchesMatrix.postScale(viewWidth / mScratchesImage.width, + viewHeight / mScratchesImage.height) + mScratchesShader.setLocalMatrix(scratchesMatrix) + + mDropsShader.setInputShader("scratches", mScratchesShader) + mDropsShader.setFloatUniform("elapsedSeconds", + (System.currentTimeMillis() - mStartTime) / 1000f) + mDropsShader.setFloatUniform("viewDimensions", viewWidth, viewHeight) + + val dropsEffect = RenderEffect.createRuntimeShaderEffect(mDropsShader, "background") + val blurEffect = RenderEffect.createBlurEffect(10f, 10f, Shader.TileMode.CLAMP) + + dropsView.setRenderEffect(RenderEffect.createChainEffect(dropsEffect, blurEffect)) + } + } + + private companion object { + const val dropsAGSL = """ + uniform float elapsedSeconds; + uniform vec2 viewDimensions; + uniform shader background; + uniform shader scratches; + + vec2 dropsUV(vec2 fragCoord ) { + vec2 uv = fragCoord.xy / viewDimensions.xy; // 0 <> 1 + vec2 offs = vec2(0.); + return (offs + uv).xy; + } + + const vec3 iFrostColorRGB = vec3(0.5, 0.5, 0.5); + const float iFrostColorAlpha = .3; + + half4 main(float2 fragCoord) { + half4 bg = background.eval(dropsUV(fragCoord)*viewDimensions.xy); + float2 scratchCoord = fragCoord.xy / viewDimensions.xy;; + scratchCoord += 1.5; + scratchCoord = mod(scratchCoord, 1); + half scratch = scratches.eval(scratchCoord*viewDimensions.xy).r; + bg.rgb = mix(bg.rgb, iFrostColorRGB, iFrostColorAlpha); + bg.rgb = mix(bg.rgb, half3(1), pow(scratch,3)); + return bg; + } + """ + } +}
\ No newline at end of file |