Skip to content
This repository was archived by the owner on Dec 4, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Tests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ function(add_dz_test TEST_NAME TEST_SRC)
)
add_test(NAME ${TEST_NAME} COMMAND $<TARGET_FILE_DIR:${TEST_NAME}>/${TEST_NAME}${TEST_EXT})
endfunction()
add_dz_test(DZ_ShaderReflect tests/ShaderReflect.cpp)
add_dz_test(DZ_Particle2D tests/Particle2D.cpp)
add_dz_test(DZ_AssetStream tests/AssetStream.cpp)
add_dz_test(DZ_LineGrid tests/LineGrid.cpp)
add_dz_test(DZ_D7Stream tests/D7Stream.cpp)
add_dz_test(DZ_ImGuiTest tests/ImGui.cpp)
# add_dz_test(DZ_ShaderReflect tests/ShaderReflect.cpp)
# add_dz_test(DZ_Particle2D tests/Particle2D.cpp)
# add_dz_test(DZ_AssetStream tests/AssetStream.cpp)
# add_dz_test(DZ_LineGrid tests/LineGrid.cpp)
# add_dz_test(DZ_D7Stream tests/D7Stream.cpp)
# add_dz_test(DZ_ImGuiTest tests/ImGui.cpp)
add_dz_test(DZ_ECSTest tests/ECS.cpp)
file(COPY images/Suzuho-Ueda.bmp DESTINATION ${CMAKE_BINARY_DIR}/images)
file(COPY images/hi.bmp DESTINATION ${CMAKE_BINARY_DIR}/images)
Expand Down
7 changes: 2 additions & 5 deletions include/dz/ECS/HDRI.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ vec4 SampleIrradiance(in int hdri_index, in vec3 v) {
vec2 packed_rect = HDRIs.data[hdri_index].irradiance_atlas_pack.zw;
return SampleAtlas(SampleSphericalMap(v), image_size, packed_rect, IrradianceAtlas);
}
vec4 SampleRadiance(in int hdri_index, in vec3 v) {
vec4 SampleRadiance(in int hdri_index, in vec3 v, float lod) {
vec2 image_size = HDRIs.data[hdri_index].radiance_atlas_pack.xy;
if (image_size.x == -1.0)
return vec4(0.0);
vec2 packed_rect = HDRIs.data[hdri_index].radiance_atlas_pack.zw;
return SampleAtlas(SampleSphericalMap(v), image_size, packed_rect, RadianceAtlas);
return SampleAtlasLOD(SampleSphericalMap(v), image_size, packed_rect, RadianceAtlas, lod);
}
)" }
};
Expand All @@ -82,9 +82,6 @@ layout(binding = @BINDING@) uniform sampler2D RadianceAtlas;
{0.5f, R"(
)", ShaderModuleType::Vertex},
{0.5f, R"(
vec4 hdri_sample = SampleHDRI(0, inLocalPosition);
vec4 irradiance_sample = SampleIrradiance(0, inLocalPosition);
vec4 radiance_sample = SampleRadiance(0, inLocalPosition);
)", ShaderModuleType::Fragment}
};

Expand Down
7 changes: 7 additions & 0 deletions include/dz/ECS/Material.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ vec4 SampleAtlas(in vec2 uv, in vec2 image_size, in vec2 packed_rect, in sampler
vec2 packed_uv = offset_uv + uv * scale_uv;
return texture(atlas, packed_uv);
}
vec4 SampleAtlasLOD(in vec2 uv, in vec2 image_size, in vec2 packed_rect, in sampler2D atlas, in float lod) {
vec2 resolution = vec2(textureSize(atlas, 0));
vec2 offset_uv = packed_rect / resolution;
vec2 scale_uv = image_size / resolution;
vec2 packed_uv = offset_uv + uv * scale_uv;
return textureLod(atlas, packed_uv, lod);
}
void EnsureMaterialFragColor(in vec2 uv, in SubMesh submesh, inout vec4 current_color) {
vec2 image_size = Materials.data[submesh.material_index].albedo_atlas_pack.xy;
if (image_size.x == -1.0)
Expand Down
58 changes: 40 additions & 18 deletions include/dz/ECS/PhysicallyBasedLighting.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,44 @@ float gaSchlickGGX(float cosLi, float NdotV, float roughness)
}

vec3 IBL(vec3 F0, vec3 N, vec3 V) {
// diffuse IBL (view-independent) //
vec3 irradiance = SampleIrradiance( 0, N ).rgb;
vec3 diffuseBRDF = mParams.albedo / PI;
vec3 diffuse = diffuseBRDF * irradiance;

// specular IBL (view-dependent) //
float NdotV = max( dot( N, V ), 0.0 );
vec3 R = reflect( -V, N ); // reflection vector
int maxMips = textureQueryLevels( RadianceAtlas );
float mip = mParams.roughness * mParams.roughness * float( maxMips );
vec3 radiance = SampleRadiance( 0, R ).rgb;
vec2 brdfLUT = texture( brdfLUT, vec2( NdotV, 1.0 - mParams.roughness ) ).rg;
vec3 F = fresnelSchlickRoughness( F0, NdotV, mParams.roughness );
vec3 specular = radiance * ( F * brdfLUT.x + brdfLUT.y );
// irradiance / diffuse
vec3 irradiance = SampleIrradiance(0, N).rgb;
vec3 kd = (1.0 - F0) * (1.0 - mParams.metalness);
vec3 diffuseBRDF = kd * mParams.albedo;
vec3 diffuse = diffuseBRDF * irradiance;

// reflection vector and radiance LOD
vec3 R = reflect(-V, N);
R.y = -R.y;
float maxMip = float(textureQueryLevels(RadianceAtlas)) - 1.0;
float lod = clamp(mParams.roughness * maxMip, 0.0, maxMip);
vec3 radiance = SampleRadiance(0, R, lod).rgb;

// safe-guard radiance (avoid NaN / negative)
radiance = max(radiance, vec3(0.0));

// --- BRDF LUT and Fresnel ---
// clamp / bias coordinates to safe range
float safeNdotV = clamp(lParams.NdotV, 0.0001, 1.0); // avoid exact zero
float safeRoughness = clamp(mParams.roughness, 0.0, 1.0);
vec2 brdfUV = vec2(safeNdotV, safeRoughness);

// Use explicit LOD 0 for BRDF LUT (typical LUT has no mips)
vec2 brdf = textureLod(brdfLUT, brdfUV, 0.0).rg;

// ensure brdf components are sane (clamp to avoid negative / huge values)
brdf = clamp(brdf, vec2(0.0), vec2(16.0));

vec3 F = fresnelSchlickRoughness(F0, safeNdotV, safeRoughness);

// combine
vec3 specular = radiance * (F * brdf.x + brdf.y);

// debug toggles — uncomment to diagnose:
// return radiance; // shows raw radiance
// return vec3(brdf.x); // visualise BRDF.x
// return vec3(brdf.y); // visualise BRDF.y
// return vec3(F.x); // visualise Fresnel (F)

return diffuse + specular;
}
Expand All @@ -76,18 +100,16 @@ vec3 PBDL(vec3 F0, in Light light) {
vec3 Lradiance = vec3(light.intensity);
vec3 Lh = normalize(Li + lParams.viewDirection);

// Calculate angles between surface normal and various light vectors.
float cosLi = max(0.0, dot(lParams.normal, Li));
float cosLh = max(0.0, dot(lParams.normal, Lh));

vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, lParams.viewDirection)));
float D = ndfGGX(cosLh, mParams.roughness);
float G = gaSchlickGGX(cosLi, lParams.NdotV, mParams.roughness);

vec3 kd = (1.0 - F) * (1.0 - mParams.metalness);
vec3 diffuseBRDF = kd * mParams.albedo;

// Cook-Torrance

vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * lParams.NdotV);

result += (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
Expand Down
11 changes: 9 additions & 2 deletions src/ECS/Material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ vec2 Hammersley(uint i, uint N)

vec2 IntegrateBRDF(float NdotV, float Roughness)
{
// Clamp NdotV to avoid division by zero in geometry visibility term
NdotV = max(NdotV, 0.0001);

vec3 V;
V.x = sqrt(1.0 - NdotV * NdotV);
V.y = 0.0;
Expand All @@ -171,7 +174,10 @@ vec2 IntegrateBRDF(float NdotV, float Roughness)
if (NdotL > 0.0)
{
float G = GeometrySmith(NdotV, NdotL, Roughness);
float G_Vis = (G * VdotH) / (NdotH * NdotV);

// Guard against divide-by-zero in NdotH * NdotV
float G_Vis = (G * VdotH) / max(NdotH * NdotV, 0.0001);

float Fc = pow(1.0 - VdotH, 5.0);

A += (1.0 - Fc) * G_Vis;
Expand All @@ -190,11 +196,12 @@ void main()
if (pixelCoord.x >= 512 || pixelCoord.y >= 512)
return;

vec2 uv = vec2(pixelCoord) / vec2(511.0, 511.0);
vec2 uv = vec2(pixelCoord) / vec2(512.0, 512.0);
float NdotV = uv.x;
float Roughness = uv.y;

vec2 integratedBRDF = IntegrateBRDF(NdotV, Roughness);
integratedBRDF = clamp(integratedBRDF, 0.0, 1.0);

imageStore(brdfLUT, pixelCoord, vec4(integratedBRDF, 0.0, 1.0));
}
Expand Down
Loading