Capsule shadows (#1055)

This commit is contained in:
Turánszki János
2025-03-04 09:19:24 +01:00
committed by GitHub
parent 4357dc5b90
commit 545e859ca7
23 changed files with 589 additions and 176 deletions
+53
View File
@@ -826,6 +826,53 @@ void GraphicsWindow::Create(EditorComponent* _editor)
});
AddWidget(&lightShaftsStrengthStrengthSlider);
capsuleshadowCheckbox.Create("Capsule Shadows: ");
capsuleshadowCheckbox.SetTooltip("Enable ambient occlusion capsule shadows.");
capsuleshadowCheckbox.SetSize(XMFLOAT2(hei, hei));
capsuleshadowCheckbox.SetPos(XMFLOAT2(x, y += step));
if (editor->main->config.GetSection("graphics").Has("capsule_shadows"))
{
wi::renderer::SetCapsuleShadowEnabled(editor->main->config.GetSection("graphics").GetBool("capsule_shadows"));
}
capsuleshadowCheckbox.OnClick([=](wi::gui::EventArgs args) {
wi::renderer::SetCapsuleShadowEnabled(args.bValue);
editor->main->config.GetSection("graphics").Set("capsule_shadows", args.bValue);
editor->main->config.Commit();
});
AddWidget(&capsuleshadowCheckbox);
capsuleshadowFadeSlider.Create(0, 1, 0.2f, 100, "CapsuleShadow.Fade: ");
capsuleshadowFadeSlider.SetText("Capsule Shadow Fade: ");
capsuleshadowFadeSlider.SetTooltip("Set capsule shadow fading.");
capsuleshadowFadeSlider.SetSize(XMFLOAT2(mod_wid, hei));
capsuleshadowFadeSlider.SetPos(XMFLOAT2(x + 100, y));
if (editor->main->config.GetSection("graphics").Has("capsule_shadow_fade"))
{
wi::renderer::SetCapsuleShadowFade(editor->main->config.GetSection("graphics").GetFloat("capsule_shadow_fade"));
}
capsuleshadowFadeSlider.OnSlide([=](wi::gui::EventArgs args) {
wi::renderer::SetCapsuleShadowFade(args.fValue);
editor->main->config.GetSection("graphics").Set("capsule_shadow_fade", args.fValue);
editor->main->config.Commit();
});
AddWidget(&capsuleshadowFadeSlider);
capsuleshadowAngleSlider.Create(0, 90, 45, 90, "CapsuleShadow.Angle: ");
capsuleshadowAngleSlider.SetText("Angle: ");
capsuleshadowAngleSlider.SetTooltip("Set capsule shadow spread angle.");
capsuleshadowAngleSlider.SetSize(XMFLOAT2(mod_wid, hei));
capsuleshadowAngleSlider.SetPos(XMFLOAT2(x + 100, y));
if (editor->main->config.GetSection("graphics").Has("capsule_shadow_angle"))
{
wi::renderer::SetCapsuleShadowAngle(wi::math::DegreesToRadians(editor->main->config.GetSection("graphics").GetFloat("capsule_shadow_angle")));
}
capsuleshadowAngleSlider.OnSlide([=](wi::gui::EventArgs args) {
wi::renderer::SetCapsuleShadowAngle(wi::math::DegreesToRadians(args.fValue));
editor->main->config.GetSection("graphics").Set("capsule_shadow_angle", args.fValue);
editor->main->config.Commit();
});
AddWidget(&capsuleshadowAngleSlider);
aoComboBox.Create("AO: ");
aoComboBox.SetTooltip("Choose Ambient Occlusion type. RTAO is only available if hardware supports ray tracing");
aoComboBox.SetScriptTip("RenderPath3D::SetAO(int value)");
@@ -1558,6 +1605,9 @@ void GraphicsWindow::Update()
lensFlareCheckBox.SetCheck(editor->renderPath->getLensFlareEnabled());
lightShaftsCheckBox.SetCheck(editor->renderPath->getLightShaftsEnabled());
lightShaftsStrengthStrengthSlider.SetValue(editor->renderPath->getLightShaftsStrength());
capsuleshadowCheckbox.SetCheck(wi::renderer::IsCapsuleShadowEnabled());
capsuleshadowAngleSlider.SetValue(wi::math::RadiansToDegrees(wi::renderer::GetCapsuleShadowAngle()));
capsuleshadowFadeSlider.SetValue(wi::renderer::GetCapsuleShadowFade());
aoComboBox.SetSelectedWithoutCallback(editor->renderPath->getAO());
aoPowerSlider.SetValue((float)editor->renderPath->getAOPower());
@@ -1845,6 +1895,9 @@ void GraphicsWindow::ResizeLayout()
add_right(lensFlareCheckBox);
add_right(lightShaftsStrengthStrengthSlider);
lightShaftsCheckBox.SetPos(XMFLOAT2(lightShaftsStrengthStrengthSlider.GetPos().x - lightShaftsCheckBox.GetSize().x - 80, lightShaftsStrengthStrengthSlider.GetPos().y));
add_right(capsuleshadowAngleSlider);
add_right(capsuleshadowFadeSlider);
capsuleshadowCheckbox.SetPos(XMFLOAT2(capsuleshadowAngleSlider.GetPos().x - capsuleshadowCheckbox.GetSize().x - 80, capsuleshadowAngleSlider.GetPos().y));
add(aoComboBox);
add(aoPowerSlider);
add(aoRangeSlider);
+3
View File
@@ -56,6 +56,9 @@ public:
wi::gui::CheckBox lensFlareCheckBox;
wi::gui::CheckBox lightShaftsCheckBox;
wi::gui::Slider lightShaftsStrengthStrengthSlider;
wi::gui::CheckBox capsuleshadowCheckbox;
wi::gui::Slider capsuleshadowFadeSlider;
wi::gui::Slider capsuleshadowAngleSlider;
wi::gui::ComboBox aoComboBox;
wi::gui::Slider aoPowerSlider;
wi::gui::Slider aoRangeSlider;
+15
View File
@@ -80,6 +80,19 @@ void HumanoidWindow::Create(EditorComponent* _editor)
});
AddWidget(&ragdollCheckBox);
capsuleShadowCheckBox.Create("Capsule Shadow Disabled: ");
capsuleShadowCheckBox.SetTooltip("Disable capsule shadow for this specific humanoid.");
capsuleShadowCheckBox.SetSize(XMFLOAT2(hei, hei));
capsuleShadowCheckBox.OnClick([=](wi::gui::EventArgs args) {
wi::scene::Scene& scene = editor->GetCurrentScene();
HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity);
if (humanoid != nullptr)
{
humanoid->SetCapsuleShadowDisabled(args.bValue);
}
});
AddWidget(&capsuleShadowCheckBox);
headRotMaxXSlider.Create(0, 90, 60, 180, "Head horizontal: ");
headRotMaxXSlider.SetTooltip("Limit horizontal head movement (input in degrees)");
headRotMaxXSlider.SetSize(XMFLOAT2(wid, hei));
@@ -275,6 +288,7 @@ void HumanoidWindow::SetEntity(Entity entity)
{
lookatCheckBox.SetCheck(humanoid->IsLookAtEnabled());
ragdollCheckBox.SetCheck(humanoid->IsRagdollPhysicsEnabled());
capsuleShadowCheckBox.SetCheck(humanoid->IsCapsuleShadowDisabled());
headRotMaxXSlider.SetValue(wi::math::RadiansToDegrees(humanoid->head_rotation_max.x));
headRotMaxYSlider.SetValue(wi::math::RadiansToDegrees(humanoid->head_rotation_max.y));
headRotSpeedSlider.SetValue(humanoid->head_rotation_speed);
@@ -572,6 +586,7 @@ void HumanoidWindow::ResizeLayout()
lookatMouseCheckBox.SetPos(XMFLOAT2(lookatCheckBox.GetPos().x - 120, lookatCheckBox.GetPos().y));
add(lookatEntityCombo);
add_right(ragdollCheckBox);
add_right(capsuleShadowCheckBox);
add(headRotMaxXSlider);
add(headRotMaxYSlider);
add(headRotSpeedSlider);
+1
View File
@@ -16,6 +16,7 @@ public:
wi::gui::CheckBox lookatCheckBox;
wi::gui::ComboBox lookatEntityCombo;
wi::gui::CheckBox ragdollCheckBox;
wi::gui::CheckBox capsuleShadowCheckBox;
wi::gui::Slider headRotMaxXSlider;
wi::gui::Slider headRotMaxYSlider;
wi::gui::Slider headRotSpeedSlider;
+18
View File
@@ -262,6 +262,22 @@ void MaterialWindow::Create(EditorComponent* _editor)
});
AddWidget(&coplanarCheckBox);
capsuleShadowCheckBox.Create("Capsule Shadow Disabled: ");
capsuleShadowCheckBox.SetTooltip("Disable receiving capsule shadows for this material.");
capsuleShadowCheckBox.SetPos(XMFLOAT2(x, y += step));
capsuleShadowCheckBox.SetSize(XMFLOAT2(hei, hei));
capsuleShadowCheckBox.OnClick([&](wi::gui::EventArgs args) {
wi::scene::Scene& scene = editor->GetCurrentScene();
for (auto& x : editor->translator.selected)
{
MaterialComponent* material = get_material(scene, x);
if (material == nullptr)
continue;
material->SetCapsuleShadowDisabled(args.bValue);
}
});
AddWidget(&capsuleShadowCheckBox);
shaderTypeComboBox.Create("Shader: ");
shaderTypeComboBox.SetTooltip("Select a shader for this material. \nCustom shaders (*) will also show up here (see wi::renderer:RegisterCustomShader() for more info.)\nNote that custom shaders (*) can't select between blend modes, as they are created with an explicit blend mode.");
@@ -1187,6 +1203,7 @@ void MaterialWindow::SetEntity(Entity entity)
preferUncompressedCheckBox.SetCheck(material->IsPreferUncompressedTexturesEnabled());
disableStreamingCheckBox.SetCheck(material->IsTextureStreamingDisabled());
coplanarCheckBox.SetCheck(material->IsCoplanarBlending());
capsuleShadowCheckBox.SetCheck(material->IsCapsuleShadowDisabled());
normalMapSlider.SetValue(material->normalMapStrength);
roughnessSlider.SetValue(material->roughness);
reflectanceSlider.SetValue(material->reflectance);
@@ -1379,6 +1396,7 @@ void MaterialWindow::ResizeLayout()
add_right(preferUncompressedCheckBox);
add_right(disableStreamingCheckBox);
add_right(coplanarCheckBox);
add_right(capsuleShadowCheckBox);
add(shaderTypeComboBox);
add(blendModeComboBox);
add(shadingRateComboBox);
+1
View File
@@ -24,6 +24,7 @@ public:
wi::gui::CheckBox preferUncompressedCheckBox;
wi::gui::CheckBox disableStreamingCheckBox;
wi::gui::CheckBox coplanarCheckBox;
wi::gui::CheckBox capsuleShadowCheckBox;
wi::gui::ComboBox shaderTypeComboBox;
wi::gui::ComboBox blendModeComboBox;
wi::gui::ComboBox shadingRateComboBox;
+14 -2
View File
@@ -81,6 +81,7 @@ enum SHADERMATERIAL_OPTIONS
SHADERMATERIAL_OPTION_BIT_ADDITIVE = 1 << 9,
SHADERMATERIAL_OPTION_BIT_UNLIT = 1 << 10,
SHADERMATERIAL_OPTION_BIT_USE_VERTEXAO = 1 << 11,
SHADERMATERIAL_OPTION_BIT_CAPSULE_SHADOW_DISABLED = 1 << 12,
};
// Same as MaterialComponent::TEXTURESLOT
@@ -460,6 +461,7 @@ struct alignas(16) ShaderMaterial
inline bool IsTransparent() { return GetOptions() & SHADERMATERIAL_OPTION_BIT_TRANSPARENT; }
inline bool IsAdditive() { return GetOptions() & SHADERMATERIAL_OPTION_BIT_ADDITIVE; }
inline bool IsDoubleSided() { return GetOptions() & SHADERMATERIAL_OPTION_BIT_DOUBLE_SIDED; }
inline bool IsCapsuleShadowDisabled() { return GetOptions() & SHADERMATERIAL_OPTION_BIT_CAPSULE_SHADOW_DISABLED; }
};
// For binning shading based on shader types:
@@ -1017,9 +1019,13 @@ enum SHADER_ENTITY_FLAGS
{
ENTITY_FLAG_LIGHT_STATIC = 1 << 0,
ENTITY_FLAG_LIGHT_VOLUMETRICCLOUDS = 1 << 1,
ENTITY_FLAG_DECAL_BASECOLOR_ONLY_ALPHA = 1 << 0,
ENTITY_FLAG_DECAL_BASECOLOR_ONLY_ALPHA = 1 << 2,
ENTITY_FLAG_CAPSULE_SHADOW_COLLIDER = 1 << 3,
};
static const float CAPSULE_SHADOW_AFFECTION_RANGE = 2; // how far away the capsule shadow can reach outside of their own radius
static const float CAPSULE_SHADOW_BOLDEN = 1.2f;
static const uint SHADER_ENTITY_COUNT = 256;
static const uint SHADER_ENTITY_TILE_BUCKET_COUNT = SHADER_ENTITY_COUNT / 32;
@@ -1131,6 +1137,7 @@ enum FRAME_OPTIONS
OPTION_BIT_REALISTIC_SKY_HIGH_QUALITY = 1 << 17,
OPTION_BIT_REALISTIC_SKY_RECEIVE_SHADOW = 1 << 18,
OPTION_BIT_VOLUMETRICCLOUDS_RECEIVE_SHADOW = 1 << 19,
OPTION_BIT_CAPSULE_SHADOW_ENABLED = 1 << 20,
};
// ---------- Common Constant buffers: -----------------
@@ -1158,6 +1165,11 @@ struct alignas(16) FrameCB
uint giboost_packed; // force fp16 load
uint entity_culling_count;
uint capsuleshadow_fade_angle;
int indirect_debugbufferindex;
int padding0;
int padding1;
float blue_noise_phase;
int texture_random64x64_index;
int texture_bluenoise_index;
@@ -1193,7 +1205,7 @@ struct alignas(16) FrameCB
uint lights;
uint decals;
uint forces;
int indirect_debugbufferindex;
uint padding2;
ShaderEntity entityArray[SHADER_ENTITY_COUNT];
float4x4 matrixArray[SHADER_ENTITY_COUNT];
@@ -18,6 +18,7 @@
<None Include="$(MSBuildThisFileDirectory)bitonicSortHF.hlsli" />
<None Include="$(MSBuildThisFileDirectory)BlockCompress.hlsli" />
<None Include="$(MSBuildThisFileDirectory)brdf.hlsli" />
<None Include="$(MSBuildThisFileDirectory)capsuleShadowHF.hlsli" />
<None Include="$(MSBuildThisFileDirectory)circle.hlsli" />
<None Include="$(MSBuildThisFileDirectory)ColorSpaceUtility.hlsli" />
<None Include="$(MSBuildThisFileDirectory)cone.hlsli" />
@@ -174,6 +174,9 @@
<None Include="$(MSBuildThisFileDirectory)objectHF_mesh_shading.hlsli">
<Filter>HF</Filter>
</None>
<None Include="$(MSBuildThisFileDirectory)capsuleShadowHF.hlsli">
<Filter>HF</Filter>
</None>
</ItemGroup>
<ItemGroup>
<FxCompile Include="$(MSBuildThisFileDirectory)hairparticle_simulateCS.hlsl">
@@ -0,0 +1,69 @@
#ifndef CAPSULE_SHADOW_HF
#define CAPSULE_SHADOW_HF
// Source: https://www.shadertoy.com/view/3stcD4
float acosFast(float x) {
// Lagarde 2014, "Inverse trigonometric functions GPU optimization for AMD GCN architecture"
// This is the approximation of degree 1, with a max absolute error of 9.0x10^-3
float y = abs(x);
float p = -0.1565827 * y + 1.570796;
p *= sqrt(1.0 - y);
return x >= 0.0 ? p : PI - p;
}
float acosFastPositive(float x) {
// Lagarde 2014, "Inverse trigonometric functions GPU optimization for AMD GCN architecture"
float p = -0.1565827 * x + 1.570796;
return p * sqrt(1.0 - x);
}
float sphericalCapsIntersection(float cosCap1, float cosCap2, float cap2, float cosDistance) {
// Oat and Sander 2007, "Ambient Aperture Lighting"
// Approximation mentioned by Jimenez et al. 2016
float r1 = acosFastPositive(cosCap1);
float r2 = cap2;
float d = acosFast(cosDistance);
// We work with cosine angles, replace the original paper's use of
// cos(min(r1, r2)_ with max(cosCap1, cosCap2)
// We also remove a multiplication by 2 * PI to simplify the computation
// since we divide by 2 * PI at the call site
if (min(r1, r2) <= max(r1, r2) - d) {
return 1.0 - max(cosCap1, cosCap2);
} else if (r1 + r2 <= d) {
return 0.0;
}
float delta = abs(r1 - r2);
float x = 1.0 - saturate((d - delta) / max(r1 + r2 - delta, 0.0001));
// simplified smoothstep()
float area = sqr(x) * (-2.0 * x + 3.0);
return area * (1.0 - max(cosCap1, cosCap2));
}
float directionalOcclusionSphere(in float3 pos, in float4 sphere, in float4 cone) {
float3 occluder = sphere.xyz - pos;
float occluderLength2 = dot(occluder, occluder);
float3 occluderDir = occluder * rsqrt(occluderLength2);
float cosPhi = dot(occluderDir, cone.xyz);
// sqr(sphere.w) should be a uniform --> capsuleRadius^2
float cosTheta = sqrt(occluderLength2 / (sqr(sphere.w) + occluderLength2));
float cosCone = cos(cone.w);
return 1.0 - sphericalCapsIntersection(cosTheta, cosCone, cone.w, cosPhi) / (1.0 - cosCone);
}
float directionalOcclusionCapsule(in float3 pos, in float3 capsuleA, in float3 capsuleB, in float capsuleRadius, in float4 cone) {
float3 Ld = capsuleB - capsuleA;
float3 L0 = capsuleA - pos;
float a = dot(cone.xyz, Ld);
float t = saturate(dot(L0, a * cone.xyz - Ld) / (dot(Ld, Ld) - a * a));
float3 posToRay = capsuleA + t * Ld;
return directionalOcclusionSphere(pos, float4(posToRay, capsuleRadius), cone);
}
#endif // CAPSULE_SHADOW_HF
+14 -1
View File
@@ -871,7 +871,7 @@ inline half3 clipspace_to_uv(in half3 clipspace)
}
inline half3 GetSunColor() { return unpack_half3(GetWeather().sun_color); } // sun color with intensity applied
inline half3 GetSunDirection() { return unpack_half3(GetWeather().sun_direction); }
inline half3 GetSunDirection() { return normalize(unpack_half3(GetWeather().sun_direction)); }
inline half3 GetHorizonColor() { return unpack_half3(GetWeather().horizon); }
inline half3 GetZenithColor() { return unpack_half3(GetWeather().zenith); }
inline half3 GetAmbientColor() { return unpack_half3(GetWeather().ambient); }
@@ -881,6 +881,8 @@ inline float GetTime() { return GetFrame().time; }
inline float GetTimePrev() { return GetFrame().time_previous; }
inline float GetFrameCount() { return GetFrame().frame_count; }
inline min16uint2 GetTemporalAASampleRotation() { return uint2(GetFrame().temporalaa_samplerotation & 0xFF, (GetFrame().temporalaa_samplerotation >> 8u) & 0xFF); }
inline half GetCapsuleShadowFade() { return f16tof32(GetFrame().capsuleshadow_fade_angle); }
inline half GetCapsuleShadowAngle() { return f16tof32(GetFrame().capsuleshadow_fade_angle >> 16u); }
inline bool IsStaticSky() { return GetScene().globalenvmap >= 0; }
inline half GetGIBoost() { return unpack_half2(GetFrame().giboost_packed).x; }
@@ -1762,6 +1764,17 @@ inline half sphere_volume(in half radius)
return 4.0 / 3.0 * PI * radius * radius * radius;
}
inline float distance_squared(float3 a, float3 b)
{
float3 diff = b - a;
return dot(diff, diff);
}
inline half distance_squared(half3 a, half3 b)
{
half3 diff = b - a;
return dot(diff, diff);
}
float plane_point_distance(float3 planeOrigin, float3 planeNormal, float3 P)
{
+33
View File
@@ -442,6 +442,39 @@ void main(uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid :
}
}
}
// Capsule shadows:
for (uint i = forces().first_item() + groupIndex; i < forces().end_item(); i += TILED_CULLING_THREADSIZE * TILED_CULLING_THREADSIZE)
{
ShaderEntity entity = load_entity(i);
if ((entity.GetFlags() & ENTITY_FLAG_CAPSULE_SHADOW_COLLIDER) == 0)
continue;
float3 A = entity.position;
float3 B = entity.GetColliderTip();
half radius = entity.GetRange() * CAPSULE_SHADOW_BOLDEN;
// culling based on capsule-sphere:
float3 center = lerp(A, B, 0.5);
half range = distance(center, A) + radius + CAPSULE_SHADOW_AFFECTION_RANGE;
float3 positionVS = mul(GetCamera().view, float4(center, 1)).xyz;
Sphere sphere = { positionVS.xyz, range };
if (SphereInsideFrustum(sphere, GroupFrustum, nearClipVS, maxDepthVS))
{
AppendEntity_Transparent(i);
if (SphereIntersectsAABB(sphere, GroupAABB)) // tighter fit than sphere-frustum culling
{
#ifdef ADVANCED_CULLING
if (depth_mask & ConstructEntityMask(minDepthVS, __depthRangeRecip, sphere))
#endif
{
AppendEntity_Opaque(i);
}
}
}
}
#endif
+52
View File
@@ -6,6 +6,7 @@
#include "brdf.hlsli"
#include "ShaderInterop_SurfelGI.h"
#include "ShaderInterop_DDGI.h"
#include "capsuleShadowHF.hlsli"
inline void LightMapping(in int lightmap, in float2 ATLAS, inout Lighting lighting, inout Surface surface)
{
@@ -492,6 +493,57 @@ inline void TiledLighting(inout Surface surface, inout Lighting lighting, uint f
}
}
// Capsule shadows:
[branch]
if ((GetFrame().options & OPTION_BIT_CAPSULE_SHADOW_ENABLED) && !surface.IsCapsuleShadowDisabled() && !forces().empty()) // capsule shadows are contained in forces array for now...
{
half4 cone = half4(GetSunDirection() * half3(-1, 1, -1), GetCapsuleShadowAngle()); // horizontally reverse of sun direction (better would be precomputed dominant light dir)
half capsuleshadow = 1;
// Loop through light buckets in the tile:
ShaderEntityIterator iterator = forces();
for (uint bucket = iterator.first_bucket(); (bucket <= iterator.last_bucket()) && (capsuleshadow > 0); ++bucket)
{
uint bucket_bits = load_entitytile(flatTileIndex + bucket);
bucket_bits = iterator.mask_entity(bucket, bucket_bits);
#ifndef ENTITY_TILE_UNIFORM
// Bucket scalarizer - Siggraph 2017 - Improved Culling [Michal Drobot]:
bucket_bits = WaveReadLaneFirst(WaveActiveBitOr(bucket_bits));
#endif // ENTITY_TILE_UNIFORM
[loop]
while ((bucket_bits != 0) && (capsuleshadow > 0))
{
// Retrieve global entity index from local bucket, then remove bit from local bucket:
const uint bucket_bit_index = firstbitlow(bucket_bits);
const uint entity_index = bucket * 32 + bucket_bit_index;
bucket_bits ^= 1u << bucket_bit_index;
ShaderEntity entity = load_entity(entity_index);
if ((entity.GetFlags() & ENTITY_FLAG_CAPSULE_SHADOW_COLLIDER) == 0)
continue;
float3 A = entity.position;
float3 B = entity.GetColliderTip();
half radius = entity.GetRange() * CAPSULE_SHADOW_BOLDEN;
half occ = directionalOcclusionCapsule(surface.P, A, B, radius, cone);
// attenutaion based on capsule-sphere:
float3 center = lerp(A, B, 0.5);
half range = distance(center, A) + radius + CAPSULE_SHADOW_AFFECTION_RANGE;
half range2 = range * range;
half dist2 = distance_squared(surface.P, center);
occ = 1 - saturate((1 - occ) * saturate(attenuation_pointlight(dist2, range, range2)));
capsuleshadow *= occ;
}
}
capsuleshadow = lerp(capsuleshadow, 1, GetCapsuleShadowFade());
capsuleshadow = saturate(capsuleshadow);
surface.occlusion *= capsuleshadow;
}
}
inline void TiledDecals(inout Surface surface, uint flatTileIndex, inout half4 surfaceMap, SamplerState sam)
+5
View File
@@ -98,6 +98,7 @@ struct Surface
bool receiveshadow;
bool is_backface;
bool gi_applied;
bool capsuleshadow_disabled;
// These will be computed when calling Update():
half NdotV; // cos(angle between normal and view vector)
@@ -150,6 +151,7 @@ struct Surface
receiveshadow = true;
is_backface = false;
gi_applied = false;
capsuleshadow_disabled = true;
uid_validate = 0;
hit_depth = 0;
@@ -181,6 +183,7 @@ struct Surface
sss = material.GetSSS();
sss_inv = material.GetSSSInverse();
SetReceiveShadow(material.IsReceiveShadow());
SetCapsuleShadowDisabled(material.IsCapsuleShadowDisabled());
}
inline void create(
@@ -305,10 +308,12 @@ struct Surface
inline bool IsReceiveShadow() { return receiveshadow; }
inline bool IsBackface() { return is_backface; }
inline bool IsGIApplied() { return gi_applied; }
inline bool IsCapsuleShadowDisabled() { return capsuleshadow_disabled; }
inline void SetReceiveShadow(bool value) { receiveshadow = value; }
inline void SetBackface(bool value) { is_backface = value; }
inline void SetGIApplied(bool value) { gi_applied = value; }
inline void SetCapsuleShadowDisabled(bool value) { capsuleshadow_disabled = value; }
ShaderMeshInstance inst;
+14 -9
View File
@@ -190,20 +190,25 @@ namespace wi::jobsystem
#ifdef PLATFORM_LINUX
std::thread& worker = res.threads.emplace_back([threadID, priority, &res] {
// from the sched(2) manpage:
// In the current [Linux 2.6.23+] implementation, each unit of
// difference in the nice values of two processes results in a
// factor of 1.25 in the degree to which the scheduler favors
// the higher priority process.
//
// so 3 would mean that other (prio 0) threads are around twice as important
switch (priority) {
case Priority::Low:
case Priority::Streaming:
// from the sched(2) manpage:
// In the current [Linux 2.6.23+] implementation, each unit of
// difference in the nice values of two processes results in a
// factor of 1.25 in the degree to which the scheduler favors
// the higher priority process.
//
// so 3 would mean that other (prio 0) threads are around twice as important
if (setpriority(PRIO_PROCESS, 0, 3) != 0)
{
perror("setpriority");
}
case Priority::Streaming:
if (setpriority(PRIO_PROCESS, 0, 2) != 0)
{
perror("setpriority");
}
break;
case Priority::High:
// nothing to do
@@ -262,7 +267,7 @@ namespace wi::jobsystem
}
else if (priority == Priority::Streaming)
{
BOOL priority_result = SetThreadPriority(handle, THREAD_PRIORITY_LOWEST);
BOOL priority_result = SetThreadPriority(handle, THREAD_PRIORITY_BELOW_NORMAL);
assert(priority_result != 0);
std::wstring wthreadname = L"wi::job_st_" + std::to_wstring(threadID);
+9
View File
@@ -132,6 +132,15 @@ namespace wi::primitive
{
assert(radius >= 0);
}
inline Sphere getSphere() const
{
XMVECTOR B = XMLoadFloat3(&base);
XMVECTOR T = XMLoadFloat3(&tip);
Sphere ret;
XMStoreFloat3(&ret.center, XMVectorLerp(B, T, 0.5f));
XMStoreFloat(&ret.radius, XMVector3Length(B - T) * 0.5f);
return ret;
}
inline AABB getAABB() const
{
XMFLOAT3 halfWidth = XMFLOAT3(radius, radius, radius);
File diff suppressed because it is too large Load Diff
+12 -3
View File
@@ -117,9 +117,10 @@ namespace wi::renderer
ALLOW_ENVPROBES = 1 << 3,
ALLOW_EMITTERS = 1 << 4,
ALLOW_HAIRS = 1 << 5,
ALLOW_REQUEST_REFLECTION = 1 << 6,
ALLOW_OCCLUSION_CULLING = 1 << 7,
ALLOW_SHADOW_ATLAS_PACKING = 1 << 8,
ALLOW_COLLIDERS = 1 << 6,
ALLOW_REQUEST_REFLECTION = 1 << 7,
ALLOW_OCCLUSION_CULLING = 1 << 8,
ALLOW_SHADOW_ATLAS_PACKING = 1 << 9,
ALLOW_EVERYTHING = ~0u
};
@@ -133,6 +134,7 @@ namespace wi::renderer
wi::vector<uint32_t> visibleEmitters;
wi::vector<uint32_t> visibleHairs;
wi::vector<uint32_t> visibleLights;
wi::vector<wi::scene::ColliderComponent> visibleColliders;
wi::rectpacker::State shadow_packer;
wi::rectpacker::Rect rain_blocker_shadow_rect;
wi::vector<wi::rectpacker::Rect> visibleLightShadowRects;
@@ -155,6 +157,7 @@ namespace wi::renderer
visibleEnvProbes.clear();
visibleEmitters.clear();
visibleHairs.clear();
visibleColliders.clear();
object_counter.store(0);
light_counter.store(0);
@@ -1129,6 +1132,12 @@ namespace wi::renderer
void SetMeshletOcclusionCullingEnabled(bool value);
bool IsMeshletOcclusionCullingEnabled();
void Workaround( const int bug, wi::graphics::CommandList cmd);
void SetCapsuleShadowEnabled(bool value);
bool IsCapsuleShadowEnabled();
void SetCapsuleShadowAngle(float value); // cone angle in radians
float GetCapsuleShadowAngle();
void SetCapsuleShadowFade(float value);
float GetCapsuleShadowFade();
// Gets pick ray according to the current screen resolution and pointer coordinates. Can be used as input into RayIntersectWorld()
wi::primitive::Ray GetPickRay(long cursorX, long cursorY, const wi::Canvas& canvas, const wi::scene::CameraComponent& camera = wi::scene::GetCamera());
+8 -2
View File
@@ -1093,12 +1093,14 @@ namespace wi::scene
collider_allocator_cpu.store(0u);
collider_allocator_gpu.store(0u);
collider_deinterleaved_data.reserve(
sizeof(wi::primitive::AABB) * colliders.GetCount() +
sizeof(wi::primitive::AABB) * colliders.GetCount() +
sizeof(ColliderComponent) * colliders.GetCount() +
sizeof(ColliderComponent) * colliders.GetCount()
);
aabb_colliders_cpu = (wi::primitive::AABB*)collider_deinterleaved_data.data();
colliders_cpu = (ColliderComponent*)(aabb_colliders_cpu + colliders.GetCount());
aabb_colliders_gpu = aabb_colliders_cpu + colliders.GetCount();
colliders_cpu = (ColliderComponent*)(aabb_colliders_gpu + colliders.GetCount());
colliders_gpu = colliders_cpu + colliders.GetCount();
for (size_t i = 0; i < colliders.GetCount(); ++i)
@@ -1167,6 +1169,7 @@ namespace wi::scene
{
uint32_t index = collider_allocator_gpu.fetch_add(1u);
colliders_gpu[index] = collider;
aabb_colliders_gpu[index] = aabb;
}
}
collider_count_cpu = collider_allocator_cpu.load();
@@ -3726,12 +3729,14 @@ namespace wi::scene
collider_allocator_cpu.store(0u);
collider_allocator_gpu.store(0u);
collider_deinterleaved_data.reserve(
sizeof(wi::primitive::AABB)* colliders.GetCount() +
sizeof(wi::primitive::AABB) * colliders.GetCount() +
sizeof(ColliderComponent) * colliders.GetCount() +
sizeof(ColliderComponent) * colliders.GetCount()
);
aabb_colliders_cpu = (wi::primitive::AABB*)collider_deinterleaved_data.data();
colliders_cpu = (ColliderComponent*)(aabb_colliders_cpu + colliders.GetCount());
aabb_colliders_gpu = aabb_colliders_cpu + colliders.GetCount();
colliders_cpu = (ColliderComponent*)(aabb_colliders_gpu + colliders.GetCount());
colliders_gpu = colliders_cpu + colliders.GetCount();
wi::jobsystem::Dispatch(ctx, (uint32_t)colliders.GetCount(), small_subtask_groupsize, [&](wi::jobsystem::JobArgs args) {
@@ -3806,6 +3811,7 @@ namespace wi::scene
{
uint32_t index = collider_allocator_gpu.fetch_add(1u);
colliders_gpu[index] = collider;
aabb_colliders_gpu[index] = aabb;
}
});
+1
View File
@@ -279,6 +279,7 @@ namespace wi::scene
uint32_t collider_count_cpu = 0;
uint32_t collider_count_gpu = 0;
wi::primitive::AABB* aabb_colliders_cpu = nullptr;
wi::primitive::AABB* aabb_colliders_gpu = nullptr;
ColliderComponent* colliders_cpu = nullptr;
ColliderComponent* colliders_gpu = nullptr;
wi::BVH collider_bvh;
+4
View File
@@ -374,6 +374,10 @@ namespace wi::scene
{
material.options_stencilref |= SHADERMATERIAL_OPTION_BIT_USE_VERTEXAO;
}
if (IsCapsuleShadowDisabled())
{
material.options_stencilref |= SHADERMATERIAL_OPTION_BIT_CAPSULE_SHADOW_DISABLED;
}
material.options_stencilref |= wi::renderer::CombineStencilrefs(engineStencilRef, userStencilRef) << 24u;
+12
View File
@@ -134,6 +134,7 @@ namespace wi::scene
DISABLE_VERTEXAO = 1 << 14,
DISABLE_TEXTURE_STREAMING = 1 << 15,
COPLANAR_BLENDING = 1 << 16, // force transparent material draw in opaque pass (useful for coplanar polygons)
DISABLE_CAPSULE_SHADOW = 1 << 17,
};
uint32_t _flags = CAST_SHADOW;
@@ -364,6 +365,10 @@ namespace wi::scene
interiorMappingRotation = value;
}
constexpr bool IsCapsuleShadowDisabled() const { return _flags & DISABLE_CAPSULE_SHADOW; }
constexpr void SetCapsuleShadowDisabled(bool value = true) { if (value) { _flags |= DISABLE_CAPSULE_SHADOW; } else { _flags &= ~DISABLE_CAPSULE_SHADOW; } }
void SetPreferUncompressedTexturesEnabled(bool value = true) { if (value) { _flags |= PREFER_UNCOMPRESSED_TEXTURES; } else { _flags &= ~PREFER_UNCOMPRESSED_TEXTURES; } CreateRenderData(true); }
// The MaterialComponent will be written to ShaderMaterial (a struct that is optimized for GPU use)
@@ -1842,14 +1847,17 @@ namespace wi::scene
EMPTY = 0,
CPU = 1 << 0,
GPU = 1 << 1,
CAPSULE_SHADOW = 1 << 2,
};
uint32_t _flags = CPU;
constexpr void SetCPUEnabled(bool value = true) { if (value) { _flags |= CPU; } else { _flags &= ~CPU; } }
constexpr void SetGPUEnabled(bool value = true) { if (value) { _flags |= GPU; } else { _flags &= ~GPU; } }
constexpr void SetCapsuleShadowEnabled(bool value = true) { if (value) { _flags |= CAPSULE_SHADOW; } else { _flags &= ~CAPSULE_SHADOW; } }
constexpr bool IsCPUEnabled() const { return _flags & CPU; }
constexpr bool IsGPUEnabled() const { return _flags & GPU; }
constexpr bool IsCapsuleShadowEnabled() const { return _flags & CAPSULE_SHADOW; }
enum class Shape
{
@@ -1868,6 +1876,7 @@ namespace wi::scene
wi::primitive::Capsule capsule;
wi::primitive::Plane plane;
uint32_t layerMask = ~0u;
float dist = 0;
void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri);
};
@@ -2034,6 +2043,7 @@ namespace wi::scene
LOOKAT = 1 << 0,
RAGDOLL_PHYSICS = 1 << 1,
DISABLE_INTERSECTION = 1 << 2,
DISABLE_CAPSULE_SHADOW = 1 << 3,
};
uint32_t _flags = LOOKAT;
@@ -2112,10 +2122,12 @@ namespace wi::scene
constexpr bool IsLookAtEnabled() const { return _flags & LOOKAT; }
constexpr bool IsRagdollPhysicsEnabled() const { return _flags & RAGDOLL_PHYSICS; }
constexpr bool IsIntersectionDisabled() const { return _flags & DISABLE_INTERSECTION; }
constexpr bool IsCapsuleShadowDisabled() const { return _flags & DISABLE_CAPSULE_SHADOW; }
constexpr void SetLookAtEnabled(bool value = true) { if (value) { _flags |= LOOKAT; } else { _flags &= ~LOOKAT; } }
constexpr void SetRagdollPhysicsEnabled(bool value = true) { if (value) { _flags |= RAGDOLL_PHYSICS; } else { _flags &= ~RAGDOLL_PHYSICS; } }
constexpr void SetIntersectionDisabled(bool value = true) { if (value) { _flags |= DISABLE_INTERSECTION; } else { _flags &= ~DISABLE_INTERSECTION; } }
constexpr void SetCapsuleShadowDisabled(bool value = true) { if (value) { _flags |= DISABLE_CAPSULE_SHADOW; } else { _flags &= ~DISABLE_CAPSULE_SHADOW; } }
XMFLOAT2 head_rotation_max = XMFLOAT2(XM_PI / 3.0f, XM_PI / 6.0f);
float head_rotation_speed = 0.1f;
+1 -1
View File
@@ -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 = 694;
const int revision = 695;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);