From 43d485b41744456662a79b76dc4190f9b7de42f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Thu, 13 Jun 2024 08:04:43 +0200 Subject: [PATCH] image distortion mask (#862) --- .../ScriptingAPI-Documentation.md | 12 +++- Editor/MeshWindow.cpp | 2 +- WickedEngine/CommonInclude.h | 36 +++++++++++ WickedEngine/shaders/ShaderInterop_Image.h | 1 + WickedEngine/shaders/imagePS.hlsl | 18 +++++- WickedEngine/wiImage.cpp | 13 +++- WickedEngine/wiImage.h | 11 ++++ WickedEngine/wiImageParams_BindLua.cpp | 18 ++++++ WickedEngine/wiImageParams_BindLua.h | 3 + WickedEngine/wiMath.h | 24 ++++--- WickedEngine/wiPathQuery.cpp | 2 +- WickedEngine/wiRenderPath3D_BindLua.cpp | 11 ++++ WickedEngine/wiRenderPath3D_BindLua.h | 2 + WickedEngine/wiRenderer.cpp | 2 +- WickedEngine/wiScene.cpp | 38 +++++++----- WickedEngine/wiScene_Components.h | 6 +- WickedEngine/wiSprite.h | 1 + WickedEngine/wiSprite_BindLua.cpp | 25 ++++++++ WickedEngine/wiSprite_BindLua.h | 2 + WickedEngine/wiTerrain.cpp | 6 +- WickedEngine/wiTerrain.h | 2 +- WickedEngine/wiTextureHelper.cpp | 62 +++++++++++++++++-- WickedEngine/wiTextureHelper.h | 20 +++++- WickedEngine/wiVersion.cpp | 2 +- 24 files changed, 270 insertions(+), 49 deletions(-) diff --git a/Content/Documentation/ScriptingAPI-Documentation.md b/Content/Documentation/ScriptingAPI-Documentation.md index 577281d0e..7ae1f754d 100644 --- a/Content/Documentation/ScriptingAPI-Documentation.md +++ b/Content/Documentation/ScriptingAPI-Documentation.md @@ -197,6 +197,8 @@ Render images on the screen. - GetTexture() : Texture - SetMaskTexture(Texture texture) - GetMaskTexture() : Texture +- SetBackgroundTexture(Texture texture) +- GetBackgroundTexture() : Texture - SetHidden(bool value) - IsHidden() : bool @@ -232,7 +234,8 @@ Specify Sprite properties, like position, size, etc. - IsDrawRectEnabled() : bool result - IsDrawRect2Enabled() : bool result - IsMirrorEnabled() : bool result -- IsBackgroundBlurEnabled() : bool result +- IsBackgroundEnabled() : bool result +- IsDistortionMaskEnabled() : bool result - SetPos(Vector pos) - SetSize(Vector size) - SetPivot(Vector value) @@ -254,8 +257,10 @@ Specify Sprite properties, like position, size, etc. - DisableDrawRect2() - EnableMirror() - DisableMirror() -- EnableBackgroundBlur(opt float mip = 0) -- DisableBackgroundBlur() +- EnableBackground() +- DisableBackground() +- EnableDistortionMask() +- DisableDistortionMask() - SetMaskAlphaRange(float start, end) - GetMaskAlphaRange() : float start, end @@ -1533,6 +1538,7 @@ It inherits functions from RenderPath2D, so it can render a 2D overlay. - SetCropTop(float value) -- Sets cropping from top of the screen in logical units - SetCropRight(float value) -- Sets cropping from right of the screen in logical units - SetCropBottom(float value) -- Sets cropping from bottom of the screen in logical units +- GetLastPostProcessRT() : Texture -- returns the last post process render texture ```lua FSR2_Preset = { diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index ad374036c..dad29896c 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -749,7 +749,7 @@ void MeshWindow::Create(EditorComponent* _editor) { const MeshComponent::MeshSubset& subset = mesh->subsets[subsetIndex]; - float threshold = wi::math::Lerp(0, 0.9f, wi::math::saturate(lodQualitySlider.GetValue())); + float threshold = wi::math::Lerp(0, 0.9f, saturate(lodQualitySlider.GetValue())); for (size_t i = 1; i < lod_count; ++i) { wi::vector& lod = lods[i].subsets[subsetIndex].indices; diff --git a/WickedEngine/CommonInclude.h b/WickedEngine/CommonInclude.h index 40ab05194..6770add4c 100644 --- a/WickedEngine/CommonInclude.h +++ b/WickedEngine/CommonInclude.h @@ -13,6 +13,42 @@ #define NOMINMAX #endif // NOMINMAX +// Simple common math helpers: + +template +constexpr T sqr(T x) { return x * x; } + +template +constexpr T clamp(T x, T a, T b) +{ + return x < a ? a : (x > b ? b : x); +} + +template +constexpr T saturate(T x) +{ + return clamp(x, T(0), T(1)); +} + +template +constexpr float lerp(T x, T y, T a) +{ + return x * (1 - a) + y * a; +} + +template +constexpr T inverse_lerp(T value1, T value2, T pos) +{ + return value2 == value1 ? T(0) : ((pos - value1) / (value2 - value1)); +} + +template +constexpr T smoothstep(T edge0, T edge1, T x) +{ + const T t = saturate((x - edge0) / (edge1 - edge0)); + return t * t * (T(3) - T(2) * t); +} + // CPU intrinsics: #if defined(_WIN32) // Windows, Xbox: diff --git a/WickedEngine/shaders/ShaderInterop_Image.h b/WickedEngine/shaders/ShaderInterop_Image.h index 2d5646706..ea23d0f14 100644 --- a/WickedEngine/shaders/ShaderInterop_Image.h +++ b/WickedEngine/shaders/ShaderInterop_Image.h @@ -10,6 +10,7 @@ static const uint IMAGE_FLAG_MIRROR = 1u << 4u; static const uint IMAGE_FLAG_CORNER_ROUNDING = 1u << 5u; static const uint IMAGE_FLAG_ANGULAR_DOUBLESIDED = 1u << 6u; static const uint IMAGE_FLAG_ANGULAR_INVERSE = 1u << 7u; +static const uint IMAGE_FLAG_DISTORTION_MASK = 1u << 8u; struct ImageConstants { diff --git a/WickedEngine/shaders/imagePS.hlsl b/WickedEngine/shaders/imagePS.hlsl index 6777fe0bf..2d2f57be2 100644 --- a/WickedEngine/shaders/imagePS.hlsl +++ b/WickedEngine/shaders/imagePS.hlsl @@ -30,12 +30,26 @@ float4 main(VertextoPixel input) : SV_TARGET const float2 mask_alpha_range = unpack_half2(image.mask_alpha_range); mask.a = smoothstep(mask_alpha_range.x, mask_alpha_range.y, mask.a); - color *= mask; + if(image.flags & IMAGE_FLAG_DISTORTION_MASK) + { + // Only mask alpha is used for multiplying, rg is used for distorting background: + color.a *= mask.a; + } + else + { + color *= mask; + } [branch] if (image.texture_background_index >= 0) { - float3 background = bindless_textures[image.texture_background_index].Sample(sam, input.uv_screen()).rgb; + Texture2D backgroundTexture = bindless_textures[image.texture_background_index]; + float2 uv_screen = input.uv_screen(); + if(image.flags & IMAGE_FLAG_DISTORTION_MASK) + { + uv_screen += mask.rg * 2 - 1; + } + float3 background = backgroundTexture.Sample(sam, uv_screen).rgb; color = float4(lerp(background, color.rgb, color.a), mask.a); } diff --git a/WickedEngine/wiImage.cpp b/WickedEngine/wiImage.cpp index 5d547e898..baee16a74 100644 --- a/WickedEngine/wiImage.cpp +++ b/WickedEngine/wiImage.cpp @@ -85,7 +85,14 @@ namespace wi::image image.texture_mask_index = device->GetDescriptorIndex(params.maskMap, SubresourceType::SRV, params.mask_subresource); if (params.isBackgroundEnabled()) { - image.texture_background_index = device->GetDescriptorIndex(&backgroundTexture, SubresourceType::SRV); + if (params.backgroundMap != nullptr) + { + image.texture_background_index = device->GetDescriptorIndex(params.backgroundMap, SubresourceType::SRV, params.background_subresource); + } + else + { + image.texture_background_index = device->GetDescriptorIndex(&backgroundTexture, SubresourceType::SRV); + } } else { @@ -152,6 +159,10 @@ namespace wi::image { image.flags |= IMAGE_FLAG_ANGULAR_INVERSE; } + if (params.isDistortionMaskEnabled()) + { + image.flags |= IMAGE_FLAG_DISTORTION_MASK; + } image.border_soften = params.border_soften; image.mask_alpha_range = XMConvertFloatToHalf(params.mask_alpha_range_start) | (XMConvertFloatToHalf(params.mask_alpha_range_end) << 16u); diff --git a/WickedEngine/wiImage.h b/WickedEngine/wiImage.h index 92809a024..870dd8261 100644 --- a/WickedEngine/wiImage.h +++ b/WickedEngine/wiImage.h @@ -60,6 +60,7 @@ namespace wi::image DEPTH_TEST = 1 << 9, ANGULAR_DOUBLESIDED = 1 << 10, ANGULAR_INVERSE = 1 << 11, + DISTORTION_MASK = 1 << 12, }; uint32_t _flags = EMPTY; @@ -107,11 +108,17 @@ namespace wi::image QUALITY quality = QUALITY_LINEAR; const wi::graphics::Texture* maskMap = nullptr; + const wi::graphics::Texture* backgroundMap = nullptr; int image_subresource = -1; int mask_subresource = -1; + int background_subresource = -1; // Set a mask map that will be used to multiply the base image constexpr void setMaskMap(const wi::graphics::Texture* tex) { maskMap = tex; } + // Set a texture that will be used to blend to the transparent part of the image with screen coordinates + // Will be used if using enableBackground() + // If you don't set this per image, then wi::image::SetBackground() will be used instead + constexpr void setBackgroundMap(const wi::graphics::Texture* tex) { backgroundMap = tex; } constexpr bool isDrawRectEnabled() const { return _flags & DRAWRECT; } constexpr bool isDrawRect2Enabled() const { return _flags & DRAWRECT2; } @@ -125,6 +132,7 @@ namespace wi::image constexpr bool isDepthTestEnabled() const { return _flags & DEPTH_TEST; } constexpr bool isAngularSoftnessDoubleSided() const { return _flags & ANGULAR_DOUBLESIDED; } constexpr bool isAngularSoftnessInverse() const { return _flags & ANGULAR_INVERSE; } + constexpr bool isDistortionMaskEnabled() const { return _flags & DISTORTION_MASK; } // enables draw rectangle for base texture (cutout texture outside draw rectangle) constexpr void enableDrawRect(const XMFLOAT4& rect) { _flags |= DRAWRECT; drawRect = rect; } @@ -147,6 +155,8 @@ namespace wi::image constexpr void enableDepthTest() { _flags |= DEPTH_TEST; } constexpr void enableAngularSoftnessDoubleSided() { _flags |= ANGULAR_DOUBLESIDED; } constexpr void enableAngularSoftnessInverse() { _flags |= ANGULAR_INVERSE; } + // Mask texture RG will be used for distortion of screen UVs for background image, A will be used as opacity + constexpr void enableDistortionMask() { _flags |= DISTORTION_MASK; } // disable draw rectangle for base texture (whole texture will be drawn, no cutout) constexpr void disableDrawRect() { _flags &= ~DRAWRECT; } @@ -162,6 +172,7 @@ namespace wi::image constexpr void disableDepthTest() { _flags &= ~DEPTH_TEST; } constexpr void disableAngularSoftnessDoubleSided() { _flags &= ~ANGULAR_DOUBLESIDED; } constexpr void disableAngularSoftnessInverse() { _flags &= ~ANGULAR_INVERSE; } + constexpr void disableDistortionMask() { _flags &= ~DISTORTION_MASK; } Params() = default; diff --git a/WickedEngine/wiImageParams_BindLua.cpp b/WickedEngine/wiImageParams_BindLua.cpp index 35acef66d..02387ddc3 100644 --- a/WickedEngine/wiImageParams_BindLua.cpp +++ b/WickedEngine/wiImageParams_BindLua.cpp @@ -20,6 +20,7 @@ namespace wi::lua lunamethod(ImageParams_BindLua, IsMirrorEnabled), lunamethod(ImageParams_BindLua, IsBackgroundBlurEnabled), lunamethod(ImageParams_BindLua, IsBackgroundEnabled), + lunamethod(ImageParams_BindLua, IsDistortionMaskEnabled), lunamethod(ImageParams_BindLua, SetPos), lunamethod(ImageParams_BindLua, SetSize), @@ -45,6 +46,8 @@ namespace wi::lua lunamethod(ImageParams_BindLua, DisableBackgroundBlur), lunamethod(ImageParams_BindLua, EnableBackground), lunamethod(ImageParams_BindLua, DisableBackground), + lunamethod(ImageParams_BindLua, EnableDistortionMask), + lunamethod(ImageParams_BindLua, DisableDistortionMask), lunamethod(ImageParams_BindLua, SetMaskAlphaRange), lunamethod(ImageParams_BindLua, GetMaskAlphaRange), { nullptr, nullptr } @@ -147,6 +150,11 @@ namespace wi::lua wi::lua::SSetBool(L, params.isBackgroundEnabled()); return 1; } + int ImageParams_BindLua::IsDistortionMaskEnabled(lua_State* L) + { + wi::lua::SSetBool(L, params.isDistortionMaskEnabled()); + return 1; + } int ImageParams_BindLua::SetPos(lua_State* L) { @@ -433,6 +441,16 @@ namespace wi::lua params.disableBackground(); return 0; } + int ImageParams_BindLua::EnableDistortionMask(lua_State* L) + { + params.enableDistortionMask(); + return 0; + } + int ImageParams_BindLua::DisableDistortionMask(lua_State* L) + { + params.disableDistortionMask(); + return 0; + } int ImageParams_BindLua::SetMaskAlphaRange(lua_State* L) { int argc = wi::lua::SGetArgCount(L); diff --git a/WickedEngine/wiImageParams_BindLua.h b/WickedEngine/wiImageParams_BindLua.h index 7c415f910..5989cd8d7 100644 --- a/WickedEngine/wiImageParams_BindLua.h +++ b/WickedEngine/wiImageParams_BindLua.h @@ -33,6 +33,7 @@ namespace wi::lua int IsMirrorEnabled(lua_State* L); int IsBackgroundBlurEnabled(lua_State* L); int IsBackgroundEnabled(lua_State* L); + int IsDistortionMaskEnabled(lua_State* L); int SetPos(lua_State* L); int SetSize(lua_State* L); @@ -58,6 +59,8 @@ namespace wi::lua int DisableBackgroundBlur(lua_State* L); int EnableBackground(lua_State* L); int DisableBackground(lua_State* L); + int EnableDistortionMask(lua_State* L); + int DisableDistortionMask(lua_State* L); int SetMaskAlphaRange(lua_State* L); int GetMaskAlphaRange(lua_State* L); diff --git a/WickedEngine/wiMath.h b/WickedEngine/wiMath.h index f651b1934..80b3cdad8 100644 --- a/WickedEngine/wiMath.h +++ b/WickedEngine/wiMath.h @@ -36,18 +36,26 @@ namespace wi::math return (std::abs(f1 - f2) <= std::numeric_limits::epsilon() * std::max(std::abs(f1), std::abs(f2))); } - constexpr float saturate(float x) { return std::min(std::max(x, 0.0f), 1.0f); } - - template - constexpr T sqr(T x) { return x * x; } + constexpr float saturate(float x) + { + return ::saturate(x); + } + inline float LengthSquared(const XMFLOAT2& v) + { + return v.x * v.x + v.y * v.y; + } + inline float LengthSquared(const XMFLOAT3& v) + { + return v.x * v.x + v.y * v.y + v.z * v.z; + } inline float Length(const XMFLOAT2& v) { - return std::sqrt(v.x*v.x + v.y*v.y); + return std::sqrt(LengthSquared(v)); } inline float Length(const XMFLOAT3& v) { - return std::sqrt(v.x*v.x + v.y*v.y + v.z*v.z); + return std::sqrt(LengthSquared(v)); } inline float Distance(XMVECTOR v1, XMVECTOR v2) { @@ -124,7 +132,7 @@ namespace wi::math } constexpr float InverseLerp(float value1, float value2, float pos) { - return value2 == value1 ? 0 : ((pos - value1) / (value2 - value1)); + return ::inverse_lerp(value1, value2, pos); } constexpr XMFLOAT2 InverseLerp(const XMFLOAT2& value1, const XMFLOAT2& value2, const XMFLOAT2& pos) { @@ -144,7 +152,7 @@ namespace wi::math } constexpr float Lerp(float value1, float value2, float amount) { - return value1 + (value2 - value1) * amount; + return ::lerp(value1, value2, amount); } constexpr XMFLOAT2 Lerp(const XMFLOAT2& a, const XMFLOAT2& b, float i) { diff --git a/WickedEngine/wiPathQuery.cpp b/WickedEngine/wiPathQuery.cpp index 5c625ac50..aef51611a 100644 --- a/WickedEngine/wiPathQuery.cpp +++ b/WickedEngine/wiPathQuery.cpp @@ -657,7 +657,7 @@ namespace wi B *= width; Vertex vert; - vert.color = wi::math::Lerp(color0, color1, wi::math::saturate(std::sin(segmenti + debugtimer) * 0.5f + 0.5f)); + vert.color = wi::math::Lerp(color0, color1, saturate(std::sin(segmenti + debugtimer) * 0.5f + 0.5f)); XMStoreFloat4(&vert.position, XMVectorSetW(P - B + topalign, 1)); std::memcpy(vertices + numVertices, &vert, sizeof(vert)); diff --git a/WickedEngine/wiRenderPath3D_BindLua.cpp b/WickedEngine/wiRenderPath3D_BindLua.cpp index 24fb6fc8f..a0bbb86d0 100644 --- a/WickedEngine/wiRenderPath3D_BindLua.cpp +++ b/WickedEngine/wiRenderPath3D_BindLua.cpp @@ -66,6 +66,8 @@ namespace wi::lua lunamethod(RenderPath3D_BindLua, SetCropRight), lunamethod(RenderPath3D_BindLua, SetCropBottom), + lunamethod(RenderPath3D_BindLua, GetLastPostProcessRT), + lunamethod(RenderPath2D_BindLua, CopyFrom), { NULL, NULL } }; @@ -622,6 +624,15 @@ namespace wi::lua return 0; } + int RenderPath3D_BindLua::GetLastPostProcessRT(lua_State* L) + { + const wi::graphics::Texture* tex = ((RenderPath3D*)component)->GetLastPostprocessRT(); + if (tex == nullptr) + return 0; + Luna::push(L, *tex); + return 1; + } + static const std::string value_bindings = R"( AO_DISABLED = 0 AO_SSAO = 1 diff --git a/WickedEngine/wiRenderPath3D_BindLua.h b/WickedEngine/wiRenderPath3D_BindLua.h index ab66cded7..234679fae 100644 --- a/WickedEngine/wiRenderPath3D_BindLua.h +++ b/WickedEngine/wiRenderPath3D_BindLua.h @@ -71,6 +71,8 @@ namespace wi::lua int SetCropRight(lua_State* L); int SetCropBottom(lua_State* L); + int GetLastPostProcessRT(lua_State* L); + static void Bind(); }; diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 7c6f66078..f3261aa5e 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -16372,7 +16372,7 @@ void Postprocess_FSR2( // convert delta time to seconds and clamp to [0, 1]. //context->constants.deltaTime = std::max(0.0f, std::min(1.0f, params->frameTimeDelta / 1000.0f)); - fsr2_constants.deltaTime = wi::math::saturate(dt); + fsr2_constants.deltaTime = saturate(dt); fsr2_constants.frameIndex++; diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 2bf3394cf..5f9dfc97f 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -2210,7 +2210,7 @@ namespace wi::scene { t = (animation.timer - left) / (right - left); } - t = wi::math::saturate(t); + t = saturate(t); switch (path_data_type) { @@ -2290,7 +2290,7 @@ namespace wi::scene { t = (animation.timer - left) / (right - left); } - t = wi::math::saturate(t); + t = saturate(t); const float t2 = t * t; const float t3 = t2 * t; @@ -2775,12 +2775,12 @@ namespace wi::scene if (blink_state < 0.5f) { // closing - expression.weight = wi::math::Lerp(0, 1, wi::math::saturate(blink_state * 2)); + expression.weight = wi::math::Lerp(0, 1, saturate(blink_state * 2)); } else { // opening - expression.weight = wi::math::Lerp(1, 0, wi::math::saturate((blink_state - 0.5f) * 2)); + expression.weight = wi::math::Lerp(1, 0, saturate((blink_state - 0.5f) * 2)); } if (expression_mastering.blink_timer >= 1 + all_blink_length) { @@ -2797,10 +2797,10 @@ namespace wi::scene // Roll new random look direction for next look away event: float vertical = wi::random::GetRandom(-1.0f, 1.0f); float horizontal = wi::random::GetRandom(-1.0f, 1.0f); - expression_mastering.look_weights[0] = wi::math::saturate(vertical); - expression_mastering.look_weights[1] = wi::math::saturate(-vertical); - expression_mastering.look_weights[2] = wi::math::saturate(horizontal); - expression_mastering.look_weights[3] = wi::math::saturate(-horizontal); + expression_mastering.look_weights[0] = saturate(vertical); + expression_mastering.look_weights[1] = saturate(-vertical); + expression_mastering.look_weights[2] = saturate(horizontal); + expression_mastering.look_weights[3] = saturate(-horizontal); } expression_mastering.look_timer += expression_mastering.look_frequency * dt; if (expression_mastering.look_timer >= 1) @@ -2821,11 +2821,11 @@ namespace wi::scene float look_state = wi::math::InverseLerp(0, expression_mastering.look_length * expression_mastering.look_frequency, expression_mastering.look_timer - 1); if (look_state < 0.25f) { - expression.weight = wi::math::Lerp(0, weight, wi::math::saturate(look_state * 4)); + expression.weight = wi::math::Lerp(0, weight, saturate(look_state * 4)); } else { - expression.weight = wi::math::Lerp(weight, 0, wi::math::saturate((look_state - 0.75f) * 4)); + expression.weight = wi::math::Lerp(weight, 0, saturate((look_state - 0.75f) * 4)); } expression.SetDirty(); } @@ -3004,7 +3004,7 @@ namespace wi::scene if (mouth >= 0 && mouth < expression_mastering.expressions.size()) { ExpressionComponent::Expression& expression = expression_mastering.expressions[mouth]; - expression.weight *= 1 - wi::math::saturate(overrideMouthBlend); + expression.weight *= 1 - saturate(overrideMouthBlend); } } const int blinks[] = { @@ -3017,7 +3017,7 @@ namespace wi::scene if (blink >= 0 && blink < expression_mastering.expressions.size()) { ExpressionComponent::Expression& expression = expression_mastering.expressions[blink]; - expression.weight *= 1 - wi::math::saturate(overrideBlinkBlend); + expression.weight *= 1 - saturate(overrideBlinkBlend); } } const int looks[] = { @@ -3031,7 +3031,7 @@ namespace wi::scene if (look >= 0 && look < expression_mastering.expressions.size()) { ExpressionComponent::Expression& expression = expression_mastering.expressions[look]; - expression.weight *= 1 - wi::math::saturate(overrideLookBlend); + expression.weight *= 1 - saturate(overrideLookBlend); } } @@ -5068,7 +5068,8 @@ namespace wi::scene if (filterMask & FILTER_OBJECT_ALL) { - for (size_t objectIndex = 0; objectIndex < aabb_objects.size(); ++objectIndex) + const size_t objectCount = std::min(objects.GetCount(), aabb_objects.size()); + for (size_t objectIndex = 0; objectIndex < objectCount; ++objectIndex) { const AABB& aabb = aabb_objects[objectIndex]; if (!ray.intersects(aabb) || (layerMask & aabb.layerMask) == 0) @@ -5286,7 +5287,8 @@ namespace wi::scene if (filterMask & FILTER_OBJECT_ALL) { - for (size_t objectIndex = 0; objectIndex < aabb_objects.size(); ++objectIndex) + const size_t objectCount = std::min(objects.GetCount(), aabb_objects.size()); + for (size_t objectIndex = 0; objectIndex < objectCount; ++objectIndex) { const AABB& aabb = aabb_objects[objectIndex]; if (!ray.intersects(aabb) || (layerMask & aabb.layerMask) == 0) @@ -5460,7 +5462,8 @@ namespace wi::scene if (filterMask & FILTER_OBJECT_ALL) { - for (size_t objectIndex = 0; objectIndex < aabb_objects.size(); ++objectIndex) + const size_t objectCount = std::min(objects.GetCount(), aabb_objects.size()); + for (size_t objectIndex = 0; objectIndex < objectCount; ++objectIndex) { const AABB& aabb = aabb_objects[objectIndex]; if (!sphere.intersects(aabb) || (layerMask & aabb.layerMask) == 0) @@ -5743,7 +5746,8 @@ namespace wi::scene if (filterMask & FILTER_OBJECT_ALL) { - for (size_t objectIndex = 0; objectIndex < aabb_objects.size(); ++objectIndex) + const size_t objectCount = std::min(objects.GetCount(), aabb_objects.size()); + for (size_t objectIndex = 0; objectIndex < objectCount; ++objectIndex) { const AABB& aabb = aabb_objects[objectIndex]; if (capsule_aabb.intersects(aabb) == AABB::INTERSECTION_TYPE::OUTSIDE || (layerMask & aabb.layerMask) == 0) diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index 72d4fc0db..1201f0cb7 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -529,9 +529,9 @@ namespace wi::scene constexpr void FromFULL(const wi::primitive::AABB& aabb, XMFLOAT3 pos, uint8_t wind) { pos = wi::math::InverseLerp(aabb._min, aabb._max, pos); // UNORM remap - x = uint32_t(wi::math::saturate(pos.x) * 1023.0f); - y = uint32_t(wi::math::saturate(pos.y) * 1023.0f); - z = uint32_t(wi::math::saturate(pos.z) * 1023.0f); + x = uint32_t(saturate(pos.x) * 1023.0f); + y = uint32_t(saturate(pos.y) * 1023.0f); + z = uint32_t(saturate(pos.z) * 1023.0f); w = uint32_t((float(wind) / 255.0f) * 3); } inline XMVECTOR LoadPOS(const wi::primitive::AABB& aabb) const diff --git a/WickedEngine/wiSprite.h b/WickedEngine/wiSprite.h index 83d7b8748..28d612cf5 100644 --- a/WickedEngine/wiSprite.h +++ b/WickedEngine/wiSprite.h @@ -46,6 +46,7 @@ namespace wi wi::image::Params params; wi::Resource textureResource; wi::Resource maskResource; + wi::Resource backgroundResource; const wi::graphics::Texture* GetTexture() const; diff --git a/WickedEngine/wiSprite_BindLua.cpp b/WickedEngine/wiSprite_BindLua.cpp index e43f63346..aa1ba81c7 100644 --- a/WickedEngine/wiSprite_BindLua.cpp +++ b/WickedEngine/wiSprite_BindLua.cpp @@ -15,6 +15,8 @@ namespace wi::lua lunamethod(Sprite_BindLua, GetTexture), lunamethod(Sprite_BindLua, SetMaskTexture), lunamethod(Sprite_BindLua, GetMaskTexture), + lunamethod(Sprite_BindLua, SetBackgroundTexture), + lunamethod(Sprite_BindLua, GetBackgroundTexture), lunamethod(Sprite_BindLua, SetHidden), lunamethod(Sprite_BindLua, IsHidden), @@ -134,6 +136,29 @@ namespace wi::lua Luna::push(L, sprite.maskResource); return 1; } + int Sprite_BindLua::SetBackgroundTexture(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc > 0) + { + Texture_BindLua* tex = Luna::check(L, 1); + if (tex != nullptr) + { + sprite.backgroundResource = tex->resource; + sprite.params.setBackgroundMap(&tex->resource.GetTexture()); + } + } + else + { + wi::lua::SError(L, "SetBackgroundTexture(Texture texture) not enough arguments!"); + } + return 0; + } + int Sprite_BindLua::GetBackgroundTexture(lua_State* L) + { + Luna::push(L, sprite.backgroundResource); + return 1; + } int Sprite_BindLua::SetHidden(lua_State* L) { int argc = wi::lua::SGetArgCount(L); diff --git a/WickedEngine/wiSprite_BindLua.h b/WickedEngine/wiSprite_BindLua.h index 2d0babf80..e1f72dc0f 100644 --- a/WickedEngine/wiSprite_BindLua.h +++ b/WickedEngine/wiSprite_BindLua.h @@ -25,6 +25,8 @@ namespace wi::lua int GetTexture(lua_State* L); int SetMaskTexture(lua_State* L); int GetMaskTexture(lua_State* L); + int SetBackgroundTexture(lua_State* L); + int GetBackgroundTexture(lua_State* L); int SetHidden(lua_State* L); int IsHidden(lua_State* L); diff --git a/WickedEngine/wiTerrain.cpp b/WickedEngine/wiTerrain.cpp index 6067e8672..56b29c361 100644 --- a/WickedEngine/wiTerrain.cpp +++ b/WickedEngine/wiTerrain.cpp @@ -970,14 +970,14 @@ namespace wi::terrain XMFLOAT3 normal; XMStoreFloat3(&normal, N); - const float slope_amount = 1.0f - wi::math::saturate(normal.y); + const float slope_amount = 1.0f - saturate(normal.y); if (slope_amount > 0.1f) slope_cast_shadow.store(true); const float region_base = 1; const float region_slope = std::pow(slope_amount, region1); - const float region_low_altitude = bottomLevel == 0 ? 0 : std::pow(wi::math::saturate(wi::math::InverseLerp(0, bottomLevel, height)), region2); - const float region_high_altitude = topLevel == 0 ? 0 : std::pow(wi::math::saturate(wi::math::InverseLerp(0, topLevel, height)), region3); + const float region_low_altitude = bottomLevel == 0 ? 0 : std::pow(saturate(wi::math::InverseLerp(0, bottomLevel, height)), region2); + const float region_high_altitude = topLevel == 0 ? 0 : std::pow(saturate(wi::math::InverseLerp(0, topLevel, height)), region3); XMFLOAT4 materialBlendWeights(region_base, region_slope, region_low_altitude, region_high_altitude); diff --git a/WickedEngine/wiTerrain.h b/WickedEngine/wiTerrain.h index d531f9ecd..faeced6e4 100644 --- a/WickedEngine/wiTerrain.h +++ b/WickedEngine/wiTerrain.h @@ -443,7 +443,7 @@ namespace wi::terrain p.y += std::cos(angle) * perturbation; } wi::noise::voronoi::Result res = wi::noise::voronoi::compute(p.x, p.y, (float)seed); - float weight = std::pow(1 - wi::math::saturate((res.distance - shape) * fade), std::max(0.0001f, falloff)); + float weight = std::pow(1 - saturate((res.distance - shape) * fade), std::max(0.0001f, falloff)); Blend(height, weight); } }; diff --git a/WickedEngine/wiTextureHelper.cpp b/WickedEngine/wiTextureHelper.cpp index 321c973c2..f80cb4beb 100644 --- a/WickedEngine/wiTextureHelper.cpp +++ b/WickedEngine/wiTextureHelper.cpp @@ -245,7 +245,7 @@ namespace wi::texturehelper bool CreateTexture( Texture& texture, - const uint8_t* data, + const void* data, uint32_t width, uint32_t height, Format format, @@ -322,7 +322,7 @@ namespace wi::texturehelper const XMFLOAT2 uv = XMFLOAT2((float(x) + 0.5f) / float(width), (float(y) + 0.5f) / float(height)); const XMVECTOR point_on_line = wi::math::ClosestPointOnLineSegment(a, b, XMLoadFloat2(&uv)); const float uv_distance = XMVectorGetX(XMVector3Length(point_on_line - a)); - float gradient = wi::math::saturate(wi::math::InverseLerp(0, distance, uv_distance)); + float gradient = saturate(wi::math::InverseLerp(0, distance, uv_distance)); if (has_flag(flags, GradientFlags::Inverse)) { gradient = 1 - gradient; @@ -335,7 +335,7 @@ namespace wi::texturehelper { gradient *= perlin.compute(uv.x * perlin_scale2.x, uv.y * perlin_scale2.y, 0, perlin_octaves, perlin_persistence) * 0.5f + 0.5f; } - gradient = wi::math::saturate(gradient); + gradient = saturate(gradient); if (has_flag(flags, GradientFlags::R16Unorm)) { data16[x + y * width] = uint16_t(gradient * 65535); @@ -360,7 +360,7 @@ namespace wi::texturehelper { const XMFLOAT2 uv = XMFLOAT2((float(x) + 0.5f) / float(width), (float(y) + 0.5f) / float(height)); const float uv_distance = wi::math::Clamp(XMVectorGetX(XMVector3Length(XMLoadFloat2(&uv) - a)), 0, distance); - float gradient = wi::math::saturate(wi::math::InverseLerp(0, distance, uv_distance)); + float gradient = saturate(wi::math::InverseLerp(0, distance, uv_distance)); if (has_flag(flags, GradientFlags::Inverse)) { gradient = 1 - gradient; @@ -373,7 +373,7 @@ namespace wi::texturehelper { gradient *= perlin.compute(uv.x * perlin_scale2.x, uv.y * perlin_scale2.y, 0, perlin_octaves, perlin_persistence) * 0.5f + 0.5f; } - gradient = wi::math::saturate(gradient); + gradient = saturate(gradient); if (has_flag(flags, GradientFlags::R16Unorm)) { data16[x + y * width] = uint16_t(gradient * 65535); @@ -410,7 +410,7 @@ namespace wi::texturehelper { gradient *= perlin.compute(uv.x * perlin_scale2.x, uv.y * perlin_scale2.y, 0, perlin_octaves, perlin_persistence) * 0.5f + 0.5f; } - gradient = wi::math::saturate(gradient); + gradient = saturate(gradient); if (has_flag(flags, GradientFlags::R16Unorm)) { data16[x + y * width] = uint16_t(gradient * 65535); @@ -466,4 +466,54 @@ namespace wi::texturehelper return texture; } + wi::graphics::Texture CreateLensDistortionNormalMap( + uint32_t width, + uint32_t height, + const XMFLOAT2& uv_start, + float radius, + float squish, + float blend, + float edge_smoothness + ) + { + XMFLOAT2 offset = XMFLOAT2(uv_start.x * 2 - 1, uv_start.y * 2 - 1); + float scale = 1.0f / (radius * 2); + float edge = 1.0f - edge_smoothness; + + wi::vector data(width * height); + for (uint32_t y = 0; y < height; ++y) + { + for (uint32_t x = 0; x < width; ++x) + { + XMFLOAT2 uv = XMFLOAT2(float(x) / float(width - 1) * 2 - 1, float(y) / float(height - 1) * 2 - 1); + + uv.x -= offset.x; + uv.y -= offset.y; + uv.x *= scale; + uv.y *= scale; + + if (width > height) + uv.x *= float(width) / float(height); + else + uv.y *= float(height) / float(width); + + const float d = wi::math::Length(uv); + const float dp = std::pow(saturate(d), squish); + uv.x = uv.x * dp; + uv.y = uv.y * dp; + + XMFLOAT4 color = XMFLOAT4(uv.x * 0.5f + 0.5f, uv.y * 0.5f + 0.5f, 1, 1); + float s = smoothstep(1.0f, edge, d) * blend; + color.x = lerp(0.5f, color.x, s); + color.y = lerp(0.5f, color.y, s); + color.z = lerp(1.0f, color.z, s); + data[x + y * width] = wi::Color16::fromFloat4(color); + } + } + + Texture texture; + CreateTexture(texture, data.data(), width, height, Format::R16G16B16A16_UNORM); + return texture; + } + } diff --git a/WickedEngine/wiTextureHelper.h b/WickedEngine/wiTextureHelper.h index 30b344d4c..86f195d93 100644 --- a/WickedEngine/wiTextureHelper.h +++ b/WickedEngine/wiTextureHelper.h @@ -22,7 +22,7 @@ namespace wi::texturehelper bool CreateTexture( wi::graphics::Texture& texture, - const uint8_t* data, + const void* data, uint32_t width, uint32_t height, wi::graphics::Format format = wi::graphics::Format::R8G8B8A8_UNORM, @@ -65,6 +65,24 @@ namespace wi::texturehelper bool counter_clockwise = false, wi::graphics::Swizzle swizzle = { wi::graphics::ComponentSwizzle::R, wi::graphics::ComponentSwizzle::R, wi::graphics::ComponentSwizzle::R, wi::graphics::ComponentSwizzle::R } ); + + // Create a lens distortion normal map (16-bit precision) + // width : texture width in pixels + // height : texture height in pixels + // uv_start : center of lens in uv-space [0,1] + // radius : radius of lens in uv_space [0,1] + // squish : squish the lens (higher value is more squished down) + // blend : blend out the distortion by a constant amount + // edge_smoothness : smoothen the edge of the circle + wi::graphics::Texture CreateLensDistortionNormalMap( + uint32_t width, + uint32_t height, + const XMFLOAT2& uv_start = XMFLOAT2(0.5f, 0.5f), + float radius = 0.5f, + float squish = 1, + float blend = 1, + float edge_smoothness = 0.04f + ); }; template<> diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 5c753461c..cd54f1e83 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 483; + const int revision = 484; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);