diff --git a/Content/Documentation/ScriptingAPI-Documentation.md b/Content/Documentation/ScriptingAPI-Documentation.md index e89a9f290..13f6326fb 100644 --- a/Content/Documentation/ScriptingAPI-Documentation.md +++ b/Content/Documentation/ScriptingAPI-Documentation.md @@ -1553,6 +1553,7 @@ Implementation of basic character controller features such as movement in the sc - GetVelocity() : Vector -- Get current velocity - GetMovement() : Vector -- Get current movement direction - IsGrounded() : bool -- returns whether the character is currently standing on ground or not +- IsWallIntersect() : bool -- returns whether the character is currently intersecting a wall or not - IsSwimming() : bool -- returns whether the character is currently swimming or not - IsFootPlacementEnabled() : bool -- Returns whether foot placement with inverse kinematics is currently enabled or not - IsCharacterToCharacterCollisionDisabled() -- returns whether character collision with other characters is disabled or not for this character (default: false) diff --git a/Content/scripts/character_controller/character_controller.lua b/Content/scripts/character_controller/character_controller.lua index e7098864a..921dde506 100644 --- a/Content/scripts/character_controller/character_controller.lua +++ b/Content/scripts/character_controller/character_controller.lua @@ -470,7 +470,7 @@ local function Character(model_scene, start_transform, controllable, anim_scene) dir = vector.TransformNormal(dir.Normalize(), rotation_matrix) dir.SetY(0) charactercomponent.Turn(dir.Normalize()) - local speed = 0 + local speed = self.walk_speed if self.state == States.WALK then speed = self.walk_speed elseif self.state == States.JOG then @@ -580,15 +580,17 @@ local function Character(model_scene, start_transform, controllable, anim_scene) if self.state == States.SWIM_IDLE then self.state = States.SWIM self:MoveDirection(lookDir) - elseif self.ground_intersect then - if(input.Down(KEYBOARD_BUTTON_LSHIFT) or input.Down(GAMEPAD_BUTTON_6)) then - if input.Down(string.byte('E')) or input.Down(GAMEPAD_BUTTON_5) then - self.state = States.RUN + elseif self.ground_intersect or charactercomponent.IsWallIntersect() then + if self.ground_intersect then + if(input.Down(KEYBOARD_BUTTON_LSHIFT) or input.Down(GAMEPAD_BUTTON_6)) then + if input.Down(string.byte('E')) or input.Down(GAMEPAD_BUTTON_5) then + self.state = States.RUN + else + self.state = States.JOG + end else - self.state = States.JOG + self.state = States.WALK end - else - self.state = States.WALK end self:MoveDirection(lookDir) end diff --git a/WickedEngine/shaders/oceanSurfacePS.hlsl b/WickedEngine/shaders/oceanSurfacePS.hlsl index 7a0ebdbb5..e96aba2b4 100644 --- a/WickedEngine/shaders/oceanSurfacePS.hlsl +++ b/WickedEngine/shaders/oceanSurfacePS.hlsl @@ -53,6 +53,8 @@ float4 main(PSIn input) : SV_TARGET Lighting lighting; lighting.create(0, 0, GetAmbient(surface.N), 0); + TiledLighting(surface, lighting, GetFlatTileIndex(pixel)); + const float bump_strength = 0.1; float4 water_plane = GetCamera().reflection_plane; @@ -75,6 +77,10 @@ float4 main(PSIn input) : SV_TARGET } lighting.indirect.specular = reflectiveColor.rgb * surface.F * saturate(dist * 0.1); // fade out very close to camera, doesn't look good } + else + { + lighting.indirect.specular = EnvironmentReflection_Global(surface); + } float water_depth = FLT_MAX; @@ -142,8 +148,6 @@ float4 main(PSIn input) : SV_TARGET surface.refraction.a = saturate(surface.refraction.a + saturate(exp(-water_depth_diff * 4))); #endif - TiledLighting(surface, lighting, GetFlatTileIndex(pixel)); - ApplyLighting(surface, lighting, color); // Blend out at distance: diff --git a/WickedEngine/shaders/shadingHF.hlsli b/WickedEngine/shaders/shadingHF.hlsli index aac6bd261..8fc092140 100644 --- a/WickedEngine/shaders/shadingHF.hlsli +++ b/WickedEngine/shaders/shadingHF.hlsli @@ -100,6 +100,13 @@ inline void ForwardLighting(inout Surface surface, inout Lighting lighting) VoxelGI(surface, lighting); #endif //DISABLE_VOXELGI + [branch] + if (!surface.IsGIApplied() && GetScene().ddgi.color_texture >= 0) + { + lighting.indirect.diffuse = ddgi_sample_irradiance(surface.P, surface.N); + surface.SetGIApplied(true); + } + [branch] if (any(xForwardLightMask)) { @@ -145,13 +152,6 @@ inline void ForwardLighting(inout Surface surface, inout Lighting lighting) } } - [branch] - if (!surface.IsGIApplied() && GetScene().ddgi.color_texture >= 0) - { - lighting.indirect.diffuse = ddgi_sample_irradiance(surface.P, surface.N); - surface.SetGIApplied(true); - } - } inline void ForwardDecals(inout Surface surface, inout half4 surfaceMap, SamplerState sam) @@ -339,6 +339,42 @@ inline void TiledLighting(inout Surface surface, inout Lighting lighting, uint f #endif // TRANSPARENT #endif //DISABLE_VOXELGI +#ifndef TRANSPARENT + [branch] + if (!surface.IsGIApplied() && GetCamera().texture_rtdiffuse_index >= 0) + { + lighting.indirect.diffuse = (half3)bindless_textures[GetCamera().texture_rtdiffuse_index][surface.pixel].rgb; + surface.SetGIApplied(true); + } + + [branch] + if (!surface.IsGIApplied() && GetFrame().options & OPTION_BIT_SURFELGI_ENABLED && GetCamera().texture_surfelgi_index >= 0 && surfel_cellvalid(surfel_cell(surface.P))) + { + lighting.indirect.diffuse = (half3)bindless_textures[GetCamera().texture_surfelgi_index][surface.pixel].rgb; + surface.SetGIApplied(true); + } + + [branch] + if (!surface.IsGIApplied() && GetCamera().texture_vxgi_diffuse_index >= 0) + { + lighting.indirect.diffuse = (half3)bindless_textures[GetCamera().texture_vxgi_diffuse_index][surface.pixel].rgb; + surface.SetGIApplied(true); + } + [branch] + if (GetCamera().texture_vxgi_specular_index >= 0) + { + half4 vxgi_specular = (half4)bindless_textures[GetCamera().texture_vxgi_specular_index][surface.pixel]; + lighting.indirect.specular = vxgi_specular.rgb * surface.F + lighting.indirect.specular * (1 - vxgi_specular.a); + } +#endif // TRANSPARENT + + [branch] + if (!surface.IsGIApplied() && GetScene().ddgi.color_texture >= 0) + { + lighting.indirect.diffuse = ddgi_sample_irradiance(surface.P, surface.N); + surface.SetGIApplied(true); + } + #if 0 // Combined light loops: @@ -543,42 +579,6 @@ inline void TiledLighting(inout Surface surface, inout Lighting lighting, uint f } #endif -#ifndef TRANSPARENT - [branch] - if (!surface.IsGIApplied() && GetCamera().texture_rtdiffuse_index >= 0) - { - lighting.indirect.diffuse = (half3)bindless_textures[GetCamera().texture_rtdiffuse_index][surface.pixel].rgb; - surface.SetGIApplied(true); - } - - [branch] - if (!surface.IsGIApplied() && GetFrame().options & OPTION_BIT_SURFELGI_ENABLED && GetCamera().texture_surfelgi_index >= 0 && surfel_cellvalid(surfel_cell(surface.P))) - { - lighting.indirect.diffuse = (half3)bindless_textures[GetCamera().texture_surfelgi_index][surface.pixel].rgb; - surface.SetGIApplied(true); - } - - [branch] - if (!surface.IsGIApplied() && GetCamera().texture_vxgi_diffuse_index >= 0) - { - lighting.indirect.diffuse = (half3)bindless_textures[GetCamera().texture_vxgi_diffuse_index][surface.pixel].rgb; - surface.SetGIApplied(true); - } - [branch] - if (GetCamera().texture_vxgi_specular_index >= 0) - { - half4 vxgi_specular = (half4)bindless_textures[GetCamera().texture_vxgi_specular_index][surface.pixel]; - lighting.indirect.specular = vxgi_specular.rgb * surface.F + lighting.indirect.specular * (1 - vxgi_specular.a); - } -#endif // TRANSPARENT - - [branch] - if (!surface.IsGIApplied() && GetScene().ddgi.color_texture >= 0) - { - lighting.indirect.diffuse = ddgi_sample_irradiance(surface.P, surface.N); - surface.SetGIApplied(true); - } - } inline void TiledDecals(inout Surface surface, uint flatTileIndex, inout half4 surfaceMap, SamplerState sam) diff --git a/WickedEngine/wiRenderPath3D.cpp b/WickedEngine/wiRenderPath3D.cpp index 121e03922..a2c0c3596 100644 --- a/WickedEngine/wiRenderPath3D.cpp +++ b/WickedEngine/wiRenderPath3D.cpp @@ -354,6 +354,8 @@ namespace wi RenderPath2D::Update(dt); + wi::renderer::SetShadowsEnabled(getShadowsEnabled()); + float update_speed = 0; const bool hw_raytrace = device->CheckCapability(GraphicsDeviceCapability::RAYTRACING); @@ -1202,7 +1204,7 @@ namespace wi }); } - if (visibility_main.IsRequestedPlanarReflections()) + if (getReflectionsEnabled() && visibility_main.IsRequestedPlanarReflections()) { // Planar reflections depth prepass: cmd = device->BeginCommandList(); diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 88d53e69f..cd84e28c3 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -129,6 +129,7 @@ bool raytracedShadows = false; bool tessellationEnabled = true; bool disableAlbedoMaps = false; bool forceDiffuseLighting = false; +bool SHADOWS_ENABLED = true; bool SCREENSPACESHADOWS = false; bool SURFELGI = false; SURFEL_DEBUG SURFELGI_DEBUG = SURFEL_DEBUG_NONE; @@ -3617,7 +3618,7 @@ void UpdateVisibility(Visibility& vis) } // Shadow atlas packing: - if ((vis.flags & Visibility::ALLOW_SHADOW_ATLAS_PACKING) && !vis.visibleLights.empty() || vis.scene->weather.rain_amount > 0) + if (IsShadowsEnabled() && (vis.flags & Visibility::ALLOW_SHADOW_ATLAS_PACKING) && !vis.visibleLights.empty() || vis.scene->weather.rain_amount > 0) { auto range = wi::profiler::BeginRangeCPU("Shadowmap packing"); float iterative_scaling = 1; @@ -4283,7 +4284,7 @@ void UpdatePerFrameData( // mark as no shadow by default: shaderentity.indices = ~0; - bool shadow = light.IsCastingShadow() && !light.IsStatic(); + bool shadow = IsShadowsEnabled() && light.IsCastingShadow() && !light.IsStatic(); const wi::rectpacker::Rect& shadow_rect = vis.visibleLightShadowRects[lightIndex]; if (shadow) @@ -4295,62 +4296,18 @@ void UpdatePerFrameData( shaderentity.SetIndices(matrixCounter, 0); } - switch (light.GetType()) - { - case LightComponent::DIRECTIONAL: - { - const uint cascade_count = std::min((uint)light.cascade_distances.size(), MATRIXARRAY_COUNT - matrixCounter); - shaderentity.SetShadowCascadeCount(cascade_count); + const uint cascade_count = std::min((uint)light.cascade_distances.size(), MATRIXARRAY_COUNT - matrixCounter); + shaderentity.SetShadowCascadeCount(cascade_count); - if (shadow && !light.cascade_distances.empty()) + if (shadow && !light.cascade_distances.empty()) + { + SHCAM* shcams = (SHCAM*)alloca(sizeof(SHCAM) * cascade_count); + CreateDirLightShadowCams(light, *vis.camera, shcams, cascade_count, shadow_rect); + for (size_t cascade = 0; cascade < cascade_count; ++cascade) { - SHCAM* shcams = (SHCAM*)alloca(sizeof(SHCAM) * cascade_count); - CreateDirLightShadowCams(light, *vis.camera, shcams, cascade_count, shadow_rect); - for (size_t cascade = 0; cascade < cascade_count; ++cascade) - { - XMStoreFloat4x4(&matrixArray[matrixCounter++], shcams[cascade].view_projection); - } + XMStoreFloat4x4(&matrixArray[matrixCounter++], shcams[cascade].view_projection); } } - break; - case LightComponent::POINT: - { - if (shadow) - { - const float FarZ = 0.1f; // watch out: reversed depth buffer! Also, light near plane is constant for simplicity, this should match on cpu side! - const float NearZ = std::max(1.0f, light.GetRange()); // watch out: reversed depth buffer! - const float fRange = FarZ / (FarZ - NearZ); - const float cubemapDepthRemapNear = fRange; - const float cubemapDepthRemapFar = -fRange * NearZ; - shaderentity.SetCubeRemapNear(cubemapDepthRemapNear); - shaderentity.SetCubeRemapFar(cubemapDepthRemapFar); - } - } - break; - case LightComponent::SPOT: - { - const float outerConeAngle = light.outerConeAngle; - const float innerConeAngle = std::min(light.innerConeAngle, outerConeAngle); - const float outerConeAngleCos = std::cos(outerConeAngle); - const float innerConeAngleCos = std::cos(innerConeAngle); - - // https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_lights_punctual#inner-and-outer-cone-angles - const float lightAngleScale = 1.0f / std::max(0.001f, innerConeAngleCos - outerConeAngleCos); - const float lightAngleOffset = -outerConeAngleCos * lightAngleScale; - - shaderentity.SetConeAngleCos(outerConeAngleCos); - shaderentity.SetAngleScale(lightAngleScale); - shaderentity.SetAngleOffset(lightAngleOffset); - - if (shadow) - { - SHCAM shcam; - CreateSpotLightShadowCam(light, shcam); - XMStoreFloat4x4(&matrixArray[matrixCounter++], shcam.view_projection); - } - } - break; - } if (light.IsStatic()) { @@ -4402,7 +4359,7 @@ void UpdatePerFrameData( // mark as no shadow by default: shaderentity.indices = ~0; - bool shadow = light.IsCastingShadow() && !light.IsStatic(); + bool shadow = IsShadowsEnabled() && light.IsCastingShadow() && !light.IsStatic(); const wi::rectpacker::Rect& shadow_rect = vis.visibleLightShadowRects[lightIndex]; if (shadow) @@ -4484,7 +4441,7 @@ void UpdatePerFrameData( // mark as no shadow by default: shaderentity.indices = ~0; - bool shadow = light.IsCastingShadow() && !light.IsStatic(); + bool shadow = IsShadowsEnabled() && light.IsCastingShadow() && !light.IsStatic(); const wi::rectpacker::Rect& shadow_rect = vis.visibleLightShadowRects[lightIndex]; if (shadow) @@ -6108,7 +6065,7 @@ void DrawShadowmaps( CommandList cmd ) { - if (IsWireRender()) + if (IsWireRender() || !IsShadowsEnabled()) return; if ((!vis.visibleLights.empty() || vis.scene->weather.rain_amount > 0) && shadowMapAtlas.IsValid()) @@ -18066,6 +18023,14 @@ void SetVXGIReflectionsEnabled(bool enabled) { VXGI_REFLECTIONS_ENABLED = enable bool GetVXGIReflectionsEnabled() { return VXGI_REFLECTIONS_ENABLED; } void SetGameSpeed(float value) { GameSpeed = std::max(0.0f, value); } float GetGameSpeed() { return GameSpeed; } +void SetShadowsEnabled(bool value) +{ + SHADOWS_ENABLED = value; +} +bool IsShadowsEnabled() +{ + return SHADOWS_ENABLED; +} void SetRaytraceBounceCount(uint32_t bounces) { raytraceBounceCount = bounces; diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index 421ffbdb7..64a317a57 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -1079,6 +1079,8 @@ namespace wi::renderer bool GetVXGIReflectionsEnabled(); void SetGameSpeed(float value); float GetGameSpeed(); + void SetShadowsEnabled(bool value); + bool IsShadowsEnabled(); void SetRaytraceBounceCount(uint32_t bounces); uint32_t GetRaytraceBounceCount(); void SetRaytraceDebugBVHVisualizerEnabled(bool value); diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 5f5b410c3..c5277dae8 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -5355,6 +5355,7 @@ namespace wi::scene const float fixed_update_fps = character.fixed_update_fps; const float timestep = 1.0f / fixed_update_fps; const float ground_friction = character.ground_friction; + const XMVECTOR wall_friction = XMVectorSet(character.ground_friction, 1, character.ground_friction, 1); const float water_friction = character.water_friction; const float slope_threshold = character.slope_threshold; const float leaning_limit = character.leaning_limit; @@ -5430,6 +5431,7 @@ namespace wi::scene if (timestep_occurred) { character.ground_intersect = false; + character.wall_intersect = false; } // Fixed timestep logic: @@ -5459,7 +5461,7 @@ namespace wi::scene XMVECTOR collisionNormal = XMLoadFloat3(&result.normal); const float slope = XMVectorGetX(XMVector3Dot(collisionNormal, up)); if (slope > slope_threshold) - { +{ character.ground_intersect = true; velocity *= ground_friction; position += XMVectorSet(0, result.depth, 0, 0); @@ -5477,6 +5479,11 @@ namespace wi::scene const float slope = XMVectorGetX(XMVector3Dot(collisionNormal, up)); if (slope <= slope_threshold) { + character.wall_intersect = true; + if (!character.ground_intersect) + { + velocity *= wall_friction; + } float velocityLen = XMVectorGetX(XMVector3Length(velocity)); XMVECTOR velocityNormalized = XMVector3Normalize(velocity); XMVECTOR undesiredMotion = collisionNormal * XMVector3Dot(velocityNormalized, collisionNormal); diff --git a/WickedEngine/wiScene_BindLua.cpp b/WickedEngine/wiScene_BindLua.cpp index b26a39901..bd5174690 100644 --- a/WickedEngine/wiScene_BindLua.cpp +++ b/WickedEngine/wiScene_BindLua.cpp @@ -7532,6 +7532,7 @@ Luna::FunctionType CharacterComponent_BindLua::metho lunamethod(CharacterComponent_BindLua, GetMovement), lunamethod(CharacterComponent_BindLua, IsActive), lunamethod(CharacterComponent_BindLua, IsGrounded), + lunamethod(CharacterComponent_BindLua, IsWallIntersect), lunamethod(CharacterComponent_BindLua, IsSwimming), lunamethod(CharacterComponent_BindLua, IsFootPlacementEnabled), lunamethod(CharacterComponent_BindLua, IsCharacterToCharacterCollisionDisabled), @@ -7948,6 +7949,11 @@ int CharacterComponent_BindLua::IsGrounded(lua_State* L) wi::lua::SSetBool(L, component->IsGrounded()); return 1; } +int CharacterComponent_BindLua::IsWallIntersect(lua_State* L) +{ + wi::lua::SSetBool(L, component->IsWallIntersect()); + return 1; +} int CharacterComponent_BindLua::IsSwimming(lua_State* L) { wi::lua::SSetBool(L, component->IsSwimming()); diff --git a/WickedEngine/wiScene_BindLua.h b/WickedEngine/wiScene_BindLua.h index 43ba33e0b..bfaaecaa6 100644 --- a/WickedEngine/wiScene_BindLua.h +++ b/WickedEngine/wiScene_BindLua.h @@ -1899,6 +1899,7 @@ namespace wi::lua::scene int GetMovement(lua_State* L); int IsActive(lua_State* L); int IsGrounded(lua_State* L); + int IsWallIntersect(lua_State* L); int IsSwimming(lua_State* L); int GetCapsule(lua_State* L); int GetFacing(lua_State* L); diff --git a/WickedEngine/wiScene_Components.cpp b/WickedEngine/wiScene_Components.cpp index af4cc1bbd..9b6bf5e62 100644 --- a/WickedEngine/wiScene_Components.cpp +++ b/WickedEngine/wiScene_Components.cpp @@ -848,6 +848,10 @@ namespace wi::scene for (uint32_t subsetIndex = first_subset; subsetIndex < last_subset; ++subsetIndex) { const MeshSubset& subset = subsets[subsetIndex]; + SubsetClusterRange& meshlet_range = cluster_ranges.emplace_back(); + + if (subset.indexCount == 0) + continue; size_t max_meshlets = meshopt_buildMeshletsBound(subset.indexCount, max_vertices, max_triangles); std::vector meshopt_meshlets(max_meshlets); @@ -871,7 +875,6 @@ namespace wi::scene clusters.reserve(clusters.size() + meshlet_count); cluster_bounds.reserve(cluster_bounds.size() + meshlet_count); - SubsetClusterRange& meshlet_range = cluster_ranges.emplace_back(); meshlet_range.clusterOffset = (uint32_t)clusters.size(); meshlet_range.clusterCount = (uint32_t)meshlet_count; @@ -2640,6 +2643,10 @@ namespace wi::scene { return ground_intersect; } + bool CharacterComponent::IsWallIntersect() const + { + return wall_intersect; + } bool CharacterComponent::IsSwimming() const { return swimming; diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index 29a2b64c6..4660b783b 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -2121,6 +2121,7 @@ namespace wi::scene float leaning = 0; // sideways leaning (smoothed) float leaning_next = 0; // sideways leaning (immediate) bool ground_intersect = false; + bool wall_intersect = false; bool swimming = false; wi::ecs::Entity humanoidEntity = wi::ecs::INVALID_ENTITY; wi::ecs::Entity left_foot = wi::ecs::INVALID_ENTITY; @@ -2202,6 +2203,9 @@ namespace wi::scene // Returns whether the character is currently stading on ground or not bool IsGrounded() const; + // Returns whether the character is currently stading on ground or not + bool IsWallIntersect() const; + // Returns whether the character is currently swimming or not bool IsSwimming() const; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 4faaebf17..afa9b2f56 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 = 551; + const int revision = 552; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);