added light color mask texture support

This commit is contained in:
Turánszki János
2025-03-28 08:58:56 +01:00
parent 528977b013
commit d1578b0179
12 changed files with 128 additions and 24 deletions
+10 -1
View File
@@ -319,7 +319,12 @@ void LightWindow::Create(EditorComponent* _editor)
shadowResolutionComboBox.SetSelected(0);
AddWidget(&shadowResolutionComboBox);
y += step * 0.5f;
tipLabel.Create("TipLabel");
tipLabel.SetText("Tip: you can add a material to this entity, and the base color texture of it will be used to tint the light color.");
tipLabel.SetPos(XMFLOAT2(mod_x, y += step));
tipLabel.SetSize(XMFLOAT2(100, 50));
AddWidget(&tipLabel);
lensflare_Label.Create("Lens flare textures: ");
lensflare_Label.SetPos(XMFLOAT2(mod_x, y += step));
@@ -590,6 +595,10 @@ void LightWindow::ResizeLayout()
y += jump;
add_fullwidth(tipLabel);
y += jump;
add_fullwidth(lensflare_Label);
add_fullwidth(lensflare_Button[0]);
add_fullwidth(lensflare_Button[1]);
+2
View File
@@ -28,6 +28,8 @@ public:
wi::gui::ComboBox typeSelectorComboBox;
wi::gui::ComboBox shadowResolutionComboBox;
wi::gui::Label tipLabel;
wi::gui::Label lensflare_Label;
wi::gui::Button lensflare_Button[7];
@@ -791,9 +791,6 @@ enum SHADER_ENTITY_FLAGS
ENTITY_FLAG_CAPSULE_SHADOW_COLLIDER = 1 << 4,
};
// Warning: the size of this structure directly affects shader performance.
// Try to reduce it as much as possible!
// Keep it aligned to 16 bytes for best performance!
struct alignas(16) ShaderEntity
{
float3 position;
@@ -874,11 +871,11 @@ struct alignas(16) ShaderEntity
}
inline min16uint GetMatrixIndex()
{
return indices & 0xFFFF;
return indices & 0xFFF;
}
inline min16uint GetTextureIndex()
{
return indices >> 16u;
return indices >> 12u;
}
inline bool IsCastingShadow()
{
@@ -958,8 +955,8 @@ struct alignas(16) ShaderEntity
}
inline void SetIndices(uint matrixIndex, uint textureIndex)
{
indices = matrixIndex & 0xFFFF;
indices |= (textureIndex & 0xFFFF) << 16u;
indices = matrixIndex & 0xFFF;
indices |= (textureIndex & 0xFFFFF) << 12u;
}
inline void SetGravity(float value)
{
+25
View File
@@ -156,6 +156,31 @@ inline uint2 unpack_pixel(uint value)
return retVal;
}
uint pack_unorm16x2(float2 value)
{
return uint(saturate(value.x) * 65535.0) | (uint(saturate(value.x) * 65535.0) << 16u);
}
uint2 pack_unorm16x4(float4 value)
{
return uint2(pack_unorm16x2(value.xy), pack_unorm16x2(value.zw));
}
float2 unpack_unorm16x2(uint value)
{
float2 retVal;
retVal.x = (value & 0xFFFF) / 65535.0;
retVal.y = (value >> 16u) / 65535.0;
return retVal;
}
float4 unpack_unorm16x4(uint2 value)
{
float4 retVal;
retVal.x = (value.x & 0xFFFF) / 65535.0;
retVal.y = (value.x >> 16u) / 65535.0;
retVal.z = (value.y & 0xFFFF) / 65535.0;
retVal.w = (value.y >> 16u) / 65535.0;
return retVal;
}
template<typename T>
T inverse_lerp(T value1, T value2, T pos)
{
+20 -1
View File
@@ -210,6 +210,14 @@ inline void light_point(in ShaderEntity light, in Surface surface, inout Lightin
if (!any(light_color))
return; // light color lost after shadow
}
const uint maskTex = light.GetTextureIndex();
[branch]
if (maskTex > 0)
{
half4 mask = bindless_cubemaps_half4[descriptor_index(maskTex)].SampleLevel(sampler_linear_clamp, -LunnormalizedShadow, 0);
light_color *= mask.rgb * mask.a;
}
light_color *= attenuation_pointlight(dist2, range, range2);
@@ -295,7 +303,7 @@ inline void light_spot(in ShaderEntity light, in Surface surface, inout Lighting
return; // outside spotlight cone
half3 light_color = light.GetColor().rgb * shadow_mask;
[branch]
if (light.IsCastingShadow() && surface.IsReceiveShadow())
{
@@ -317,6 +325,17 @@ inline void light_spot(in ShaderEntity light, in Surface surface, inout Lighting
if (!any(light_color))
return; // light color lost after shadow
}
const uint maskTex = light.GetTextureIndex();
[branch]
if (maskTex > 0)
{
float4 shadow_pos = mul(load_entitymatrix(light.GetMatrixIndex() + 0), float4(surface.P, 1));
shadow_pos.xyz /= shadow_pos.w;
float2 shadow_uv = clipspace_to_uv(shadow_pos.xy);
half4 mask = bindless_textures_half4[descriptor_index(maskTex)].SampleLevel(sampler_linear_clamp, shadow_uv, 0);
light_color *= mask.rgb * mask.a;
}
light_color *= attenuation_spotlight(dist2, range, range2, spot_factor, light.GetAngleScale(), light.GetAngleOffset());
@@ -46,6 +46,8 @@ float4 main(VertexToPixel input) : SV_TARGET
// dither ray start to help with undersampling:
P = P + V * stepSize * dither(input.pos.xy);
const uint maskTex = light.GetTextureIndex();
// Perform ray marching to integrate light volume along view ray:
[loop]
@@ -66,6 +68,13 @@ float4 main(VertexToPixel input) : SV_TARGET
{
attenuation *= shadow_cube(light, Lunnormalized, input.pos.xy);
}
[branch]
if (maskTex > 0)
{
half4 mask = bindless_cubemaps_half4[descriptor_index(maskTex)].Sample(sampler_linear_clamp, -Lunnormalized);
attenuation *= mask.rgb * mask.a;
}
// Evaluate sample height for height fog calculation, given 0 for V:
attenuation *= (half)g_xColor.y + GetFogAmount(cameraDistance - marchedDistance, P, 0);
@@ -87,6 +87,8 @@ float4 main(VertexToPixel input) : SV_TARGET
// dither ray start to help with undersampling:
P = P + V * stepSize * dither(input.pos.xy);
const uint maskTex = light.GetTextureIndex();
// Perform ray marching to integrate light volume along view ray:
[loop]
@@ -119,6 +121,16 @@ float4 main(VertexToPixel input) : SV_TARGET
attenuation *= shadow_2D(light, shadow_pos.xyz, shadow_uv.xy, 0, input.pos.xy);
}
}
[branch]
if (maskTex > 0)
{
float4 shadow_pos = mul(load_entitymatrix(light.GetMatrixIndex() + 0), float4(P, 1));
shadow_pos.xyz /= shadow_pos.w;
float2 shadow_uv = shadow_pos.xy * float2(0.5f, -0.5f) + float2(0.5f, 0.5f);
half4 mask = bindless_textures_half4[descriptor_index(maskTex)].Sample(sampler_linear_clamp, shadow_uv);
attenuation *= mask.rgb * mask.a;
}
// Evaluate sample height for exponential fog calculation, given 0 for V:
attenuation *= g_xColor.y + GetFogAmount(cameraDistance - marchedDistance, P, 0);
+17
View File
@@ -527,6 +527,23 @@ namespace wi::math
}
constexpr uint32_t pack_unorm16x2(float x, float y)
{
return uint32_t(saturate(x) * 65535.0f) | (uint32_t(saturate(y) * 65535.0f) << 16u);
}
constexpr uint32_t pack_unorm16x2(XMFLOAT2 value)
{
return pack_unorm16x2(value.x, value.y);
}
constexpr XMUINT2 pack_unorm16x4(float x, float y, float z, float w)
{
return XMUINT2(pack_unorm16x2(x, y), pack_unorm16x2(z, w));
}
constexpr XMUINT2 pack_unorm16x4(XMFLOAT4 value)
{
return pack_unorm16x4(value.x, value.y, value.z, value.w);
}
//-----------------------------------------------------------------------------
// Compute the intersection of a ray (Origin, Direction) with a triangle
+12 -14
View File
@@ -4412,9 +4412,6 @@ void UpdatePerFrameData(
shaderentity.SetDirection(light.direction);
shaderentity.SetColor(float4(light.color.x * light.intensity, light.color.y * light.intensity, light.color.z * light.intensity, 1));
// mark as no shadow by default:
shaderentity.indices = ~0;
const bool shadowmap = IsShadowsEnabled() && light.IsCastingShadow() && !light.IsStatic();
const wi::rectpacker::Rect& shadow_rect = vis.visibleLightShadowRects[lightIndex];
@@ -4424,9 +4421,10 @@ void UpdatePerFrameData(
shaderentity.shadowAtlasMulAdd.y = shadow_rect.h * atlas_dim_rcp.y;
shaderentity.shadowAtlasMulAdd.z = shadow_rect.x * atlas_dim_rcp.x;
shaderentity.shadowAtlasMulAdd.w = shadow_rect.y * atlas_dim_rcp.y;
shaderentity.SetIndices(matrixCounter, 0);
}
shaderentity.SetIndices(matrixCounter, 0);
const uint cascade_count = std::min((uint)light.cascade_distances.size(), MATRIXARRAY_COUNT - matrixCounter);
shaderentity.SetShadowCascadeCount(cascade_count);
@@ -4491,21 +4489,21 @@ void UpdatePerFrameData(
shaderentity.SetDirection(light.direction);
shaderentity.SetColor(float4(light.color.x * light.intensity, light.color.y * light.intensity, light.color.z * light.intensity, 1));
// mark as no shadow by default:
shaderentity.indices = ~0;
const bool shadowmap = IsShadowsEnabled() && light.IsCastingShadow() && !light.IsStatic();
const wi::rectpacker::Rect& shadow_rect = vis.visibleLightShadowRects[lightIndex];
const uint maskTex = light.maskTexDescriptor < 0 ? 0 : light.maskTexDescriptor;
if (shadowmap)
{
shaderentity.shadowAtlasMulAdd.x = shadow_rect.w * atlas_dim_rcp.x;
shaderentity.shadowAtlasMulAdd.y = shadow_rect.h * atlas_dim_rcp.y;
shaderentity.shadowAtlasMulAdd.z = shadow_rect.x * atlas_dim_rcp.x;
shaderentity.shadowAtlasMulAdd.w = shadow_rect.y * atlas_dim_rcp.y;
shaderentity.SetIndices(matrixCounter, 0);
}
shaderentity.SetIndices(matrixCounter, maskTex);
const float outerConeAngle = light.outerConeAngle;
const float innerConeAngle = std::min(light.innerConeAngle, outerConeAngle);
const float outerConeAngleCos = std::cos(outerConeAngle);
@@ -4519,7 +4517,7 @@ void UpdatePerFrameData(
shaderentity.SetAngleScale(lightAngleScale);
shaderentity.SetAngleOffset(lightAngleOffset);
if (shadowmap)
if (shadowmap || (maskTex > 0))
{
SHCAM shcam;
CreateSpotLightShadowCam(light, shcam);
@@ -4577,21 +4575,21 @@ void UpdatePerFrameData(
shaderentity.SetDirection(light.direction);
shaderentity.SetColor(float4(light.color.x * light.intensity, light.color.y * light.intensity, light.color.z * light.intensity, 1));
// mark as no shadow by default:
shaderentity.indices = ~0;
const bool shadowmap = IsShadowsEnabled() && light.IsCastingShadow() && !light.IsStatic();
const wi::rectpacker::Rect& shadow_rect = vis.visibleLightShadowRects[lightIndex];
const uint maskTex = light.maskTexDescriptor < 0 ? 0 : light.maskTexDescriptor;
if (shadowmap)
{
shaderentity.shadowAtlasMulAdd.x = shadow_rect.w * atlas_dim_rcp.x;
shaderentity.shadowAtlasMulAdd.y = shadow_rect.h * atlas_dim_rcp.y;
shaderentity.shadowAtlasMulAdd.z = shadow_rect.x * atlas_dim_rcp.x;
shaderentity.shadowAtlasMulAdd.w = shadow_rect.y * atlas_dim_rcp.y;
shaderentity.SetIndices(matrixCounter, 0);
}
shaderentity.SetIndices(matrixCounter, maskTex);
if (shadowmap)
{
const float FarZ = 0.1f; // watch out: reversed depth buffer! Also, light near plane is constant for simplicity, this should match on cpu side!
@@ -4660,7 +4658,7 @@ void UpdatePerFrameData(
shaderentity.SetType(ENTITY_TYPE_COLLIDER_PLANE);
shaderentity.position = collider.plane.origin;
shaderentity.SetDirection(collider.plane.normal);
shaderentity.SetIndices(matrixCounter, ~0u);
shaderentity.SetIndices(matrixCounter, 0);
matrixArray[matrixCounter++] = collider.plane.projection;
break;
default:
+15
View File
@@ -4836,6 +4836,21 @@ namespace wi::scene
break;
}
light.maskTexDescriptor = -1;
const MaterialComponent* material = materials.GetComponent(entity);
if (material != nullptr && material->textures[MaterialComponent::BASECOLORMAP].resource.IsValid())
{
const Texture& tex = material->textures[MaterialComponent::BASECOLORMAP].resource.GetTexture();
if (
(light.type == LightComponent::SPOT && !has_flag(tex.desc.misc_flags, ResourceMiscFlag::TEXTURECUBE)) ||
(light.type == LightComponent::POINT && has_flag(tex.desc.misc_flags, ResourceMiscFlag::TEXTURECUBE))
)
{
light.maskTexDescriptor = GetDevice()->GetDescriptorIndex(&tex, SubresourceType::SRV, material->textures[MaterialComponent::BASECOLORMAP].resource.GetTextureSRGBSubresource());
}
}
});
}
void Scene::RunParticleUpdateSystem(wi::jobsystem::context& ctx)
+1
View File
@@ -1220,6 +1220,7 @@ namespace wi::scene
mutable int occlusionquery = -1;
XMFLOAT4 rotation = XMFLOAT4(0, 0, 0, 1);
XMFLOAT3 scale = XMFLOAT3(1, 1, 1);
int maskTexDescriptor = -1;
wi::vector<wi::Resource> lensFlareRimTextures;
+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 = 724;
const int revision = 725;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);