diff --git a/BUILD.gn b/BUILD.gn index 744c4e33cedd3543797c863128ae3c5d59bfd669..9b63cbbaeb28e3b78957a086d4878fc01354a08e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -63,6 +63,7 @@ ohos_source_set("graphics_effect_src") { "src/ge_magnifier_shader_filter.cpp", "src/ge_mesa_blur_shader_filter.cpp", "src/ge_render.cpp", + "src/ge_sound_wave_filter.cpp", "src/ge_system_properties.cpp", "src/ge_visual_effect.cpp", "src/ge_visual_effect_container.cpp", diff --git a/include/ge_shader_filter_params.h b/include/ge_shader_filter_params.h index 43ef6c9f08289e31642f7e13f15d9c302ee9cce9..d6593a1fadf271aa43ef0eeab53680f9db556368 100644 --- a/include/ge_shader_filter_params.h +++ b/include/ge_shader_filter_params.h @@ -20,6 +20,7 @@ #include #include "utils/matrix.h" +#include "common/rs_color.h" namespace OHOS { namespace Rosen { @@ -53,6 +54,33 @@ struct GEWaterRippleFilterParams { uint32_t rippleMode = 1; }; +constexpr char GE_FILTER_SOUND_WAVE[] = "SOUND_WAVE"; +constexpr char GE_FILTER_SOUND_WAVE_COLORONE[] = "COLORONE"; +constexpr char GE_FILTER_SOUND_WAVE_COLORTWO[] = "COLORTWO"; +constexpr char GE_FILTER_SOUND_WAVE_COLORTHREE[] = "COLORTHREE"; +constexpr char GE_FILTER_SOUND_WAVE_COLORPROGRESS[] = "COLORPROGRESS"; +constexpr char GE_FILTER_SOUND_WAVE_CENTERBRIGHTNESS[] = "CENTERBRIGHTNESS"; +constexpr char GE_FILTER_SOUND_WAVE_SOUNDINTENSITY[] = "SOUNDINTENSITY"; +constexpr char GE_FILTER_SOUND_WAVE_SHOCKWAVEALPHAONE[] = "SHOCKWAVEALPHAONE"; +constexpr char GE_FILTER_SOUND_WAVE_SHOCKWAVEALPHATWO[] = "SHOCKWAVEALPHATWO"; +constexpr char GE_FILTER_SOUND_WAVE_SHOCKWAVEPROGRESSONE[] = "SHOCKWAVEPROGRESSONE"; +constexpr char GE_FILTER_SOUND_WAVE_SHOCKWAVEPROGRESSTWO[] = "SHOCKWAVEPROGRESSTWO"; +struct GESoundWaveFilterParams { + //sound wave + uint32_t colorOne = 0xFFFFFFFF; + uint32_t colorTwo = 0xFFFFFFFF; + uint32_t colorThree = 0xFFFFFFFF; + float colorProgress = 0.0f; + float centerBrightness = 1.0f; + float soundIntensity = 0.0f; + + //shock wave + float shockWaveAlphaOne = 1.0f; + float shockWaveAlphaTwo = 1.0f; + float shockWaveProgressOne = 0.0f; + float shockWaveProgressTwo = 0.0f; +}; + constexpr char GE_FILTER_GREY[] = "GREY"; constexpr char GE_FILTER_GREY_COEF_1[] = "GREY_COEF_1"; constexpr char GE_FILTER_GREY_COEF_2[] = "GREY_COEF_2"; diff --git a/include/ge_sound_wave_filter.h b/include/ge_sound_wave_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..ac6b66871c6ad07f35e2ebd02f0c77693ad44331 --- /dev/null +++ b/include/ge_sound_wave_filter.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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. + */ +#ifndef GRAPHICS_EFFECT_GE_SOUND_WAVE_FILTER_H +#define GRAPHICS_EFFECT_GE_SOUND_WAVE_FILTER_H + +#include + +#include "ge_shader_filter.h" +#include "ge_visual_effect.h" + +#include "draw/canvas.h" +#include "effect/color_filter.h" +#include "effect/runtime_effect.h" +#include "effect/runtime_shader_builder.h" +#include "image/image.h" +#include "utils/matrix.h" +#include "utils/rect.h" + +namespace OHOS { +namespace Rosen { +class GESoundWaveFilter : public GEShaderFilter { +public: + GESoundWaveFilter(const Drawing::GESoundWaveFilterParams& params); + ~GESoundWaveFilter() override = default; + + std::shared_ptr ProcessImage(Drawing::Canvas& canvas, const std::shared_ptr image, + const Drawing::Rect& src, const Drawing::Rect& dst) override; + +private: + std::shared_ptr GetSoundWaveEffect(); + // sound wave + Drawing::Color colorOne_ = Drawing::Color::COLOR_WHITE; + Drawing::Color colorTwo_ = Drawing::Color::COLOR_WHITE; + Drawing::Color colorThree_ = Drawing::Color::COLOR_WHITE; + float colorProgress_ = 0.0f; + float centerBrightness_ = 1.0f; + float soundIntensity_ = 0.0f; + + // shock wave + float shockWaveAlphaOne_ = 1.0f; + float shockWaveAlphaTwo_ = 1.0f; + float shockWaveProgressOne_ = 0.0f; + float shockWaveProgressTwo_ = 0.0f; + + inline static const std::string shaderStringSoundWave = R"( + uniform shader image; + uniform half2 iResolution; + uniform vec3 colorOne; + uniform vec3 colorTwo; + uniform vec3 colorThree; + uniform half colorProgress; + uniform half centerBrightness; + uniform half soundIntensity; + uniform half shockWaveAlphaOne; + uniform half shockWaveAlphaTwo; + uniform half shockWaveProgressOne; + uniform half shockWaveProgressTwo; + + float smin(float a, float b, float k) + { + k *= 6.0; + float h = max(k-abs(a-b), 0.0)/k; + return min(a, b) - h*h*h*k*(1.0/6.0); + } + + // Create a smooth color gradient effect based on the threshold over X or Y or user defined + // Ideal for movement, but not for rotation + vec3 colorGradient(vec3 colorOne, vec3 colorTwo, float startPos, float endPos, float threshold) + { + float stepValue = (threshold >= startPos && threshold <= endPos) ? 1.0 : 0.0; + vec3 returnValue = mix(colorOne, colorTwo, smoothstep(startPos, endPos, threshold)) * stepValue; + return returnValue; + } + + vec3 colorWheel(vec2 uv, vec2 circleCenter, float circleRadius, float animationTime) + { + float mask = length(uv+circleCenter)/circleRadius; + float distanceFromCenter = fract(mask-animationTime); + + vec3 color = colorGradient(colorOne, colorTwo, 0.0, 0.2, distanceFromCenter) + + colorGradient(colorTwo, colorThree, 0.2, 0.6, distanceFromCenter) + + colorGradient(colorThree, colorOne, 0.6, 1.0, distanceFromCenter); + color *= (1.0 - step(1.0, mask)); + return color; + } + + vec4 soundWaveDistortionEffects(vec2 screenUVs, vec2 centeredUVs, float animationTime) + { + vec2 lightPulseUVs = centeredUVs + vec2(0.0, 1.12); // uv minus pulse center position + float frequency = fract(animationTime); // frequency of distortion waves + float radius = mix(0.17, 0.68, frequency); + float lightPulseDistance = length(lightPulseUVs) - radius; + + float lightPulseThickness = 0.12; + float lightPulse = smoothstep(lightPulseThickness, -0.025, abs(lightPulseDistance)); + if (lightPulse > 0.0) + { + float animationMask = smoothstep(1.0, 0.4, frequency); + + vec2 directionVector = normalize(lightPulseUVs); + vec2 normal = directionVector * lightPulseDistance * lightPulse*animationMask; + vec2 refractedUVs = clamp(mix(screenUVs, screenUVs - normal * 0.25, 0.3), 0.001, 0.999); + return vec4(refractedUVs, normal.y, lightPulse); + } + return vec4(screenUVs, 0.0, 0.0); + } + + vec3 soundWaveLightEffects(vec2 uv, vec2 centeredUVs, vec3 currentColor, vec3 centerColor) + { + float circleRadius = 0.125; + + // Control the height of the circle + float circleHeight = mix(-0.2, 0.03, soundIntensity); + float spreadX = pow(100.0, -soundIntensity) + 1.0;// Control the spread of the mask across X + + float smoothUnionThreshold = mix(0.0657, 0.09, soundIntensity); + float horizonOffset = -0.02; + vec2 circlePosition = vec2(0.0, circleHeight); + centeredUVs.y += 1.0; + centeredUVs.y += mix(0.09, 0.0, soundIntensity); + float circleSDF = length(centeredUVs-circlePosition)-circleRadius ; + circleSDF += smoothUnionThreshold; + float smoothUnionDistance = smin(circleSDF, centeredUVs.y-horizonOffset, smoothUnionThreshold); + float horizontalGradient = smoothstep(0.9 * spreadX, 0.0, abs(uv.x*2.0-1.0)); + float smoothGap = mix(0.08, 0.1085, horizontalGradient); + float smoothUnion = smoothstep(smoothGap, -0.035, mix(0.0, 0.66, smoothUnionDistance)); + + // Control the spread of the mask across X + smoothUnion *= mix(0.65, 1.0, horizontalGradient); + + float brightnessValue = centerBrightness *smoothstep(5.0, 0.0, circleSDF); + + return currentColor+centerColor*smoothUnion* brightnessValue; + } + + half4 main(float2 fragCoord) { + vec2 uv = fragCoord.xy/iResolution.xy; + uv.y = 1.0 - uv.y; + if (uv.y>0.3) { + return vec4(0.0); + } + float screenRatio = iResolution.x/iResolution.y; + vec2 centeredUVs = uv*2.0 - 1.0; + centeredUVs.x *= screenRatio; + vec2 screenUVs = uv; + + vec3 finalColor = vec3(0.); + vec3 centerColor = colorWheel(centeredUVs, vec2(0.0, 1.0), 0.125+2.0, colorProgress); + + // 声波畸变 + vec4 soundWaveDistortion = vec4(0.0); + vec4 soundWaveDistortion2 = vec4(0.0); + soundWaveDistortion = soundWaveDistortionEffects(uv, centeredUVs, shockWaveProgressOne); + uv = soundWaveDistortion.xy; + + soundWaveDistortion2 = soundWaveDistortionEffects(uv, centeredUVs, shockWaveProgressTwo); + uv = soundWaveDistortion2.xy; + + finalColor.rgb = image.eval(vec2(uv.x, 1.0 - uv.y) * iResolution.xy).rgb; + + finalColor.rgb = soundWaveLightEffects(screenUVs, centeredUVs, finalColor.rgb, centerColor); + + // 添加来自折射畸变的光线 Add sutil light from the refraction distortion + finalColor.rgb = soundWaveDistortion.z > 0.0 + ? finalColor.rgb + centerColor * vec3(soundWaveDistortion.z) * shockWaveAlphaOne + : finalColor.rgb; + finalColor.rgb = soundWaveDistortion.w > 0.0 + ? finalColor.rgb + centerColor * vec3(pow(soundWaveDistortion.w, 6.0))*0.3 * shockWaveAlphaOne + : finalColor.rgb; + + finalColor.rgb = soundWaveDistortion2.z > 0.0 + ? finalColor.rgb + centerColor * vec3(soundWaveDistortion2.z) * shockWaveAlphaTwo + : finalColor.rgb; + finalColor.rgb = soundWaveDistortion2.w > 0.0 + ? finalColor.rgb + centerColor * vec3(pow(soundWaveDistortion2.w, 6.0))*0.3 * shockWaveAlphaTwo + : finalColor.rgb; + + return vec4(finalColor, 1.0); + } + )"; +}; + +} // namespace Rosen +} // namespace OHOS + +#endif // GRAPHICS_EFFECT_GE_SOUND_WAVE_FILTER_H \ No newline at end of file diff --git a/include/ge_visual_effect_impl.h b/include/ge_visual_effect_impl.h index 66f87485767b6c78053d53e6eefb1776afe4092d..1f8efab284e9a5b7bbdd564a3db981ddda14de03 100644 --- a/include/ge_visual_effect_impl.h +++ b/include/ge_visual_effect_impl.h @@ -43,6 +43,7 @@ public: FLOW_LIGHT_SWEEP, COMPLEX_SHADER, EDGE_LIGHT, + SOUND_WAVE, MAX }; @@ -153,6 +154,16 @@ public: return edgeLightParams_; } + void MakeSoundWaveParams() + { + soundWaveParams_ = std::make_shared(); + } + + const std::shared_ptr& GetSoundWaveParams() const + { + return soundWaveParams_; + } + private: static std::map> g_initialMap; @@ -166,6 +177,8 @@ private: void SetWaterRippleParams(const std::string& tag, float param); void SetEdgeLightParams(const std::string& tag, float param); + void SetSoundWaveParamsUint32(const std::string& tag, uint32_t param); + void SetSoundWaveParamsFloat(const std::string& tag, float param); FilterType filterType_ = GEVisualEffectImpl::FilterType::NONE; @@ -178,7 +191,7 @@ private: std::shared_ptr magnifierParams_ = nullptr; std::shared_ptr waterRippleParams_ = nullptr; std::shared_ptr edgeLightParams_ = nullptr; - + std::shared_ptr soundWaveParams_ = nullptr; }; } // namespace Drawing diff --git a/src/ge_render.cpp b/src/ge_render.cpp index 684776efa4e121b946a65df62c2acd6b61db3138..920a675020d2c992a47c49108f41a0a5bf7545c0 100644 --- a/src/ge_render.cpp +++ b/src/ge_render.cpp @@ -24,6 +24,7 @@ #include "ge_visual_effect_impl.h" #include "ge_water_ripple_filter.h" #include "ge_edge_light_shader_filter.h" +#include "ge_sound_wave_filter.h" #include "ge_external_dynamic_loader.h" namespace OHOS { @@ -162,6 +163,11 @@ std::vector> GERender::GenerateShaderFilter( shaderFilter = GenerateExtShaderFilter(ve); break; } + case Drawing::GEVisualEffectImpl::FilterType::SOUND_WAVE: { + const auto& soundWaveParams = ve->GetSoundWaveParams(); + shaderFilter = std::make_shared(*soundWaveParams); + break; + } default: break; } diff --git a/src/ge_sound_wave_filter.cpp b/src/ge_sound_wave_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..66e10a790e5c9a16633ef3e13913aa86e22a28bd --- /dev/null +++ b/src/ge_sound_wave_filter.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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. + */ + +#include + +#include "ge_log.h" +#include "ge_sound_wave_filter.h" + +namespace OHOS { +namespace Rosen { + +namespace { +constexpr static uint8_t COLOR_CHANNEL = 3; // 3 len of rgb +} // namespace + +GESoundWaveFilter::GESoundWaveFilter(const Drawing::GESoundWaveFilterParams& params) + :colorProgress_(params.colorProgress), centerBrightness_(params.centerBrightness), + soundIntensity_(params.soundIntensity), shockWaveAlphaOne_(params.shockWaveAlphaOne), + shockWaveAlphaTwo_(params.shockWaveAlphaTwo), shockWaveProgressOne_(params.shockWaveProgressOne), + shockWaveProgressTwo_(params.shockWaveProgressTwo) +{ + colorOne_ = Drawing::Color(params.colorOne); + colorTwo_ = Drawing::Color(params.colorTwo); + colorThree_ = Drawing::Color(params.colorThree); +} + + +std::shared_ptr GESoundWaveFilter::ProcessImage(Drawing::Canvas& canvas, + const std::shared_ptr image, const Drawing::Rect& src, const Drawing::Rect& dst) +{ + if (image == nullptr) { + LOGE("GESoundWaveFilter::ProcessImage input is invalid"); + return nullptr; + } + + Drawing::Matrix matrix; + auto shader = Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::CLAMP, + Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix); + auto imageInfo = image->GetImageInfo(); + float height = imageInfo.GetHeight(); + float width = imageInfo.GetWidth(); + if (height < 1e-6 || width < 1e-6) { + return nullptr; + } + auto soundWaveShader = GetSoundWaveEffect(); + if (soundWaveShader == nullptr) { + LOGE("GESoundWaveFilter::ProcessImage g_SoundWaveEffect init failed"); + return nullptr; + } + + float colorOne[COLOR_CHANNEL] = {colorOne_.GetRedF(), colorOne_.GetGreenF(), colorOne_.GetBlueF()}; + float colorTwo[COLOR_CHANNEL] = {colorTwo_.GetRedF(), colorTwo_.GetGreenF(), colorTwo_.GetBlueF()}; + float colorThree[COLOR_CHANNEL] = {colorThree_.GetRedF(), colorThree_.GetGreenF(), colorThree_.GetBlueF()}; + + Drawing::RuntimeShaderBuilder builder(soundWaveShader); + builder.SetChild("image", shader); + builder.SetUniform("iResolution", width, height); + builder.SetUniform("colorOne", colorOne, COLOR_CHANNEL); + builder.SetUniform("colorTwo", colorTwo, COLOR_CHANNEL); + builder.SetUniform("colorThree", colorThree, COLOR_CHANNEL); + builder.SetUniform("colorProgress", colorProgress_); + builder.SetUniform("centerBrightness", centerBrightness_); + builder.SetUniform("soundIntensity", soundIntensity_); + builder.SetUniform("shockWaveAlphaOne", shockWaveAlphaOne_); + builder.SetUniform("shockWaveAlphaTwo", shockWaveAlphaTwo_); + builder.SetUniform("shockWaveProgressOne", shockWaveProgressOne_); + builder.SetUniform("shockWaveProgressTwo", shockWaveProgressTwo_); + + auto invertedImage = builder.MakeImage(canvas.GetGPUContext().get(), nullptr, imageInfo, false); + if (invertedImage == nullptr) { + LOGE("GESoundWaveFilter::ProcessImage make image failed"); + return nullptr; + } + return invertedImage; +} + +std::shared_ptr GESoundWaveFilter::GetSoundWaveEffect() +{ + static std::shared_ptr g_soundWaveShader = nullptr; + if (g_soundWaveShader == nullptr) { + g_soundWaveShader = Drawing::RuntimeEffect::CreateForShader(shaderStringSoundWave); + } + return g_soundWaveShader; +} + + +} // namespace Rosen +} // namespace OHOS \ No newline at end of file diff --git a/src/ge_visual_effect_impl.cpp b/src/ge_visual_effect_impl.cpp index cce0f0fda41ba19b1ced99ed1e56be2b67942776..bd992890671a3e58266e354ee61a9945495138f8 100644 --- a/src/ge_visual_effect_impl.cpp +++ b/src/ge_visual_effect_impl.cpp @@ -70,6 +70,12 @@ std::map> GEVisualEf impl->SetFilterType(GEVisualEffectImpl::FilterType::EDGE_LIGHT); impl->MakeEdgeLightParams(); } + }, + { GE_FILTER_SOUND_WAVE, + [](GEVisualEffectImpl* impl) { + impl->SetFilterType(GEVisualEffectImpl::FilterType::SOUND_WAVE); + impl->MakeSoundWaveParams(); + } } }; @@ -201,6 +207,10 @@ void GEVisualEffectImpl::SetParam(const std::string& tag, float param) SetEdgeLightParams(tag, param); break; } + case FilterType::SOUND_WAVE: { + SetSoundWaveParamsFloat(tag, param); + break; + } default: break; } @@ -276,6 +286,10 @@ void GEVisualEffectImpl::SetParam(const std::string& tag, const uint32_t param) } break; } + case FilterType::SOUND_WAVE: { + SetSoundWaveParamsUint32(tag, param); + break; + } default: break; } @@ -492,6 +506,58 @@ void GEVisualEffectImpl::SetEdgeLightParams(const std::string& tag, float param) } } +void GEVisualEffectImpl::SetSoundWaveParamsUint32(const std::string& tag, uint32_t param) +{ + if (soundWaveParams_ == nullptr) { + return; + } + + static std::unordered_map> actions = { + + { GE_FILTER_SOUND_WAVE_COLORONE, + [](GEVisualEffectImpl* obj, uint32_t p) { obj->soundWaveParams_->colorOne = p; } }, + { GE_FILTER_SOUND_WAVE_COLORTWO, + [](GEVisualEffectImpl* obj, uint32_t p) { obj->soundWaveParams_->colorTwo = p; } }, + { GE_FILTER_SOUND_WAVE_COLORTHREE, + [](GEVisualEffectImpl* obj, uint32_t p) { obj->soundWaveParams_->colorThree = p; } }, + }; + + auto it = actions.find(tag); + if (it != actions.end()) { + it->second(this, param); + } +} + +void GEVisualEffectImpl::SetSoundWaveParamsFloat(const std::string& tag, float param) +{ + if (soundWaveParams_ == nullptr) { + return; + } + + static std::unordered_map> actions = { + + { GE_FILTER_SOUND_WAVE_COLORPROGRESS, + [](GEVisualEffectImpl* obj, float p) { obj->soundWaveParams_->colorProgress = p; } }, + { GE_FILTER_SOUND_WAVE_CENTERBRIGHTNESS, + [](GEVisualEffectImpl* obj, float p) { obj->soundWaveParams_->centerBrightness = p; } }, + { GE_FILTER_SOUND_WAVE_SOUNDINTENSITY, + [](GEVisualEffectImpl* obj, float p) { obj->soundWaveParams_->soundIntensity = p; } }, + { GE_FILTER_SOUND_WAVE_SHOCKWAVEALPHAONE, + [](GEVisualEffectImpl* obj, float p) { obj->soundWaveParams_->shockWaveAlphaOne = p; } }, + { GE_FILTER_SOUND_WAVE_SHOCKWAVEALPHATWO, + [](GEVisualEffectImpl* obj, float p) { obj->soundWaveParams_->shockWaveAlphaTwo = p; } }, + { GE_FILTER_SOUND_WAVE_SHOCKWAVEPROGRESSONE, + [](GEVisualEffectImpl* obj, float p) { obj->soundWaveParams_->shockWaveProgressOne = p; } }, + { GE_FILTER_SOUND_WAVE_SHOCKWAVEPROGRESSTWO, + [](GEVisualEffectImpl* obj, float p) { obj->soundWaveParams_->shockWaveProgressTwo = p; } }, + }; + + auto it = actions.find(tag); + if (it != actions.end()) { + it->second(this, param); + } +} + } // namespace Drawing } // namespace Rosen } // namespace OHOS