Skip to content

Commit a5edf28

Browse files
committed
the lighting in the PBR scene *looks* better. There's still a bit that doesn't quite feel right. Need to investigate. But position was getting set close to the origin so something screwy is still going on.
1 parent 067ea74 commit a5edf28

File tree

6 files changed

+67
-62
lines changed

6 files changed

+67
-62
lines changed

attachments/simple_engine/descriptor_manager.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,12 @@ bool DescriptorManager::createUniformBuffers(Entity* entity, uint32_t maxFramesI
5252
vk::DeviceSize bufferSize = sizeof(UniformBufferObject);
5353

5454
// Create entity resources if they don't exist
55-
if (entityResources.find(entity) == entityResources.end()) {
56-
entityResources[entity] = EntityResources();
57-
}
55+
auto entityResourcesIt = entityResources.try_emplace( entity ).first;
5856

5957
// Clear existing uniform buffers
60-
entityResources[entity].uniformBuffers.clear();
61-
entityResources[entity].uniformBuffersMemory.clear();
62-
entityResources[entity].uniformBuffersMapped.clear();
58+
entityResourcesIt->second.uniformBuffers.clear();
59+
entityResourcesIt->second.uniformBuffersMemory.clear();
60+
entityResourcesIt->second.uniformBuffersMapped.clear();
6361

6462
// Create uniform buffers
6563
for (size_t i = 0; i < maxFramesInFlight; i++) {
@@ -74,9 +72,9 @@ bool DescriptorManager::createUniformBuffers(Entity* entity, uint32_t maxFramesI
7472
void* data = bufferMemory.mapMemory(0, bufferSize);
7573

7674
// Store resources
77-
entityResources[entity].uniformBuffers.push_back(std::move(buffer));
78-
entityResources[entity].uniformBuffersMemory.push_back(std::move(bufferMemory));
79-
entityResources[entity].uniformBuffersMapped.push_back(data);
75+
entityResourcesIt->second.uniformBuffers.push_back(std::move(buffer));
76+
entityResourcesIt->second.uniformBuffersMemory.push_back(std::move(bufferMemory));
77+
entityResourcesIt->second.uniformBuffersMapped.push_back(data);
8078
}
8179

8280
return true;

attachments/simple_engine/model_loader.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static bool LoadKTX2FileToRGBA(const std::string& filePath, std::vector<uint8_t>
4141

4242
// Emissive scaling factor to convert from Blender units to engine units
4343
#define EMISSIVE_SCALE_FACTOR (1.0f / 638.0f)
44-
#define LIGHT_SCALE_FACTOR (1.0f / 2.0f) // The sun is way too bright
44+
#define LIGHT_SCALE_FACTOR (1.0f / 638.0f)
4545

4646
ModelLoader::~ModelLoader() {
4747
// Destructor implementation
@@ -184,6 +184,7 @@ bool ModelLoader::ParseGLTF(const std::string& filename, Model* model) {
184184
std::cout << "Blender generator detected, applying blender factor" << std::endl;
185185
light_scale = EMISSIVE_SCALE_FACTOR;
186186
}
187+
light_scale = EMISSIVE_SCALE_FACTOR;
187188

188189
// Track loaded textures to prevent loading the same texture multiple times
189190
std::set<std::string> loadedTextures;
@@ -1061,8 +1062,19 @@ bool ModelLoader::ParseGLTF(const std::string& filename, Model* model) {
10611062
} else {
10621063
std::cerr << " Failed to load embedded normal texture: " << textureId << std::endl;
10631064
}
1065+
} else if (!image.uri.empty()) {
1066+
// Fallback: load KTX2 from a file and upload to memory
1067+
std::vector<uint8_t> data; int w=0,h=0,c=0;
1068+
std::string filePath = baseTexturePath + image.uri;
1069+
if (LoadKTX2FileToRGBA(filePath, data, w, h, c) &&
1070+
renderer->LoadTextureFromMemory(textureId, data.data(), w, h, c)) {
1071+
materialMesh.normalTexturePath = textureId;
1072+
std::cout << " Loaded normal KTX2 file: " << filePath << std::endl;
1073+
} else {
1074+
std::cerr << " Failed to load normal KTX2 file: " << filePath << std::endl;
1075+
}
10641076
} else {
1065-
std::cerr << " Warning: No decoded bytes for normal texture index " << texIndex << std::endl;
1077+
std::cerr << " Warning: No decoded bytes for normal texture index " << texIndex << std::endl;
10661078
}
10671079
}
10681080
}
@@ -1265,7 +1277,7 @@ bool ModelLoader::ParseGLTF(const std::string& filename, Model* model) {
12651277
std::cout << "Extracting lights from GLTF model..." << std::endl;
12661278

12671279
// Extract punctual lights (KHR_lights_punctual extension)
1268-
if (!ExtractPunctualLights(gltfModel, filename)) {
1280+
if (ExtractPunctualLights(gltfModel, filename)) {
12691281
std::cerr << "Warning: Failed to extract punctual lights from " << filename << std::endl;
12701282
}
12711283

@@ -1294,7 +1306,7 @@ std::vector<ExtractedLight> ModelLoader::GetExtractedLights(const std::string& m
12941306

12951307
// Check if this material has emissive properties (no threshold filtering)
12961308
float emissiveIntensity = glm::length(material->emissive) * material->emissiveStrength;
1297-
if (emissiveIntensity >= 0.0f) { // Accept all emissive materials, including zero intensities
1309+
if (emissiveIntensity >= 0.1f) {
12981310
// Calculate the center position of the emissive surface
12991311
glm::vec3 center(0.0f);
13001312
if (!materialMesh.vertices.empty()) {
@@ -1315,18 +1327,13 @@ std::vector<ExtractedLight> ModelLoader::GetExtractedLights(const std::string& m
13151327
avgNormal = glm::vec3(0.0f, -1.0f, 0.0f); // Default downward direction
13161328
}
13171329

1318-
// CRITICAL FIX: Offset the light position away from the surface
1319-
// This allows the emissive light to properly illuminate the surface from outside
1320-
float offsetDistance = 0.5f; // Offset distance from surface
1321-
glm::vec3 lightPosition = center + avgNormal * offsetDistance;
1322-
13231330
// Create an emissive light source
13241331
ExtractedLight emissiveLight;
13251332
emissiveLight.type = ExtractedLight::Type::Emissive;
1326-
emissiveLight.position = lightPosition; // Use the offset position
1333+
emissiveLight.position = center;
13271334
emissiveLight.color = material->emissive;
13281335
emissiveLight.intensity = material->emissiveStrength;
1329-
emissiveLight.range = 10.0f; // Default range for emissive lights
1336+
emissiveLight.range = 1.0f; // Default range for emissive lights
13301337
emissiveLight.sourceMaterial = material->GetName();
13311338
emissiveLight.direction = avgNormal;
13321339

@@ -1485,4 +1492,3 @@ bool ModelLoader::ExtractPunctualLights(const tinygltf::Model& gltfModel, const
14851492
std::cout << " Extracted " << lights.size() << " total lights from model" << std::endl;
14861493
return lights.empty();
14871494
}
1488-

attachments/simple_engine/physics_system.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,15 +1158,13 @@ void PhysicsSystem::ReadbackGPUPhysicsData() const {
11581158
if (vulkanResources.persistentCounterMemory) {
11591159
static uint32_t lastPairCount = UINT32_MAX;
11601160
static uint32_t lastCollisionCount = UINT32_MAX;
1161-
static int debugFrames = 0;
11621161
const uint32_t* counters = static_cast<const uint32_t*>(vulkanResources.persistentCounterMemory);
11631162
uint32_t pairCount = counters[0];
11641163
uint32_t collisionCount = counters[1];
1165-
if (debugFrames < 120 && (pairCount != lastPairCount || collisionCount != lastCollisionCount)) {
1166-
std::cout << "Physics GPU counters - pairs: " << pairCount << ", collisions: " << collisionCount << std::endl;
1164+
if (pairCount != lastPairCount || collisionCount != lastCollisionCount) {
1165+
// std::cout << "Physics GPU counters - pairs: " << pairCount << ", collisions: " << collisionCount << std::endl;
11671166
lastPairCount = pairCount;
11681167
lastCollisionCount = collisionCount;
1169-
debugFrames++;
11701168
}
11711169
}
11721170

attachments/simple_engine/renderer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ struct SwapChainSupportDetails {
4545
* @brief Structure for individual light data in the storage buffer.
4646
*/
4747
struct LightData {
48-
alignas(16) glm::vec4 position; // Light position (w component unused)
48+
alignas(16) glm::vec4 position; // Light position (w component used for direction vs position)
4949
alignas(16) glm::vec4 color; // Light color and intensity
5050
alignas(16) glm::mat4 lightSpaceMatrix; // Light space matrix for shadow mapping
5151
alignas(4) int lightType; // 0=Point, 1=Directional, 2=Spot, 3=Emissive

attachments/simple_engine/renderer_resources.cpp

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,13 +1218,6 @@ bool Renderer::createDescriptorSets(Entity* entity, const std::string& texturePa
12181218
descriptor_path_resolved: ;
12191219
}
12201220

1221-
// Debug: report resolved baseColor texture binding for this entity
1222-
if (meshComponent) {
1223-
const std::string& bc = pbrTexturePaths[0];
1224-
bool present = textureResources.find(bc) != textureResources.end();
1225-
std::cout << "PBR baseColor for entity '" << entity->GetName() << "': '" << bc
1226-
<< "' (" << (present ? "loaded" : "not in cache") << ")" << std::endl;
1227-
}
12281221
// Create descriptor writes for all 5 texture bindings
12291222
for (int binding = 1; binding <= 5; binding++) {
12301223
descriptorWrites[binding] = vk::WriteDescriptorSet{
@@ -1934,11 +1927,7 @@ bool Renderer::updateLightStorageBuffer(uint32_t frameIndex, const std::vector<E
19341927
lightData[i].position = glm::vec4(light.position, 1.0f); // w=1 indicates position
19351928
}
19361929

1937-
// Set light color with proper intensity (remove the division by 683 that was making lights too dim)
1938-
float intensity = light.intensity;
1939-
if (intensity < 5.0f) intensity = 5.0f; // Minimum intensity to prevent completely dark lights
1940-
1941-
lightData[i].color = glm::vec4(light.color * intensity, 1.0f);
1930+
lightData[i].color = glm::vec4(light.color * light.intensity, 1.0f);
19421931

19431932
// Calculate light space matrix for shadow mapping
19441933
glm::mat4 lightProjection, lightView;

attachments/simple_engine/shaders/pbr.slang

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ struct VSOutput {
2323

2424
// Light data structure for storage buffer
2525
struct LightData {
26-
float4 position; // Light position (w component unused)
26+
float4 position; // Light position (w component 1 for directional)
2727
float4 color; // Light color and intensity
2828
float4x4 lightSpaceMatrix; // Light space matrix for shadow mapping
2929
int lightType; // 0=Point, 1=Directional, 2=Spot, 3=Emissive
@@ -217,40 +217,64 @@ float4 PSMain(VSOutput input) : SV_TARGET
217217
// Calculate lighting for each light (dynamic count - no limit)
218218
for (int i = 0; i < ubo.lightCount; i++) {
219219
LightData light = lightBuffer[i];
220-
float3 lightPos = light.position.xyz;
220+
float3 lightPos = mul(light.lightSpaceMatrix, float4(input.WorldPos, 1.0)).xyz;
221+
float3 lightVec = light.position.xyz;
221222
float3 lightColor = light.color.rgb;
222223

223224
// Handle emissive lights differently
224225
if (light.lightType == 3) { // Emissive light
225-
// For emissive lights, treat them as area lights with enhanced contribution
226-
// Calculate light direction and distance
226+
// Treat emissive like a positional contributor from its stored position
227227
float3 L = normalize(lightPos - input.WorldPos);
228228
float distance = length(lightPos - input.WorldPos);
229+
float attenuation = 1.0 / (distance * distance);
230+
float3 radiance = lightColor * attenuation;
231+
232+
float3 H = normalize(V + L);
233+
234+
float NdotL = max(dot(N, L), 0.0);
235+
float NdotV = max(dot(N, V), 0.0);
236+
float NdotH = max(dot(N, H), 0.0);
237+
float HdotV = max(dot(H, V), 0.0);
238+
239+
float shadow = 0.0;
240+
if (i < ubo.shadowMapCount) {
241+
float4 fragPosLightSpace = mul(light.lightSpaceMatrix, float4(input.WorldPos, 1.0));
242+
shadow = calculateShadow(fragPosLightSpace, i, N, L);
243+
}
229244

230-
// Enhanced attenuation for emissive lights to make them more effective
231-
float attenuation = 1.0 / (1.0 + 0.1 * distance + 0.01 * distance * distance);
245+
float D = DistributionGGX(NdotH, roughness);
246+
float G = GeometrySmith(NdotV, NdotL, roughness);
247+
float3 F = FresnelSchlick(HdotV, F0);
248+
249+
float3 numerator = D * G * F;
250+
float denominator = 4.0 * NdotV * NdotL + 0.0001;
251+
float3 specular = numerator / denominator;
252+
253+
float3 kS = F;
254+
float3 kD = float3(1.0, 1.0, 1.0) - kS;
255+
kD *= 1.0 - metallic;
256+
257+
float shadowFactor = 1.0 - shadow;
258+
Lo += (kD * baseColor.rgb / PI + specular) * radiance * NdotL * shadowFactor;
232259

233-
// Boost emissive light intensity to make them more visible
234-
float3 radiance = lightColor * attenuation * 2.0; // 2x multiplier for emissive lights
260+
} else if (light.lightType == 1) { // Directional light
261+
// For directional lights, position field stores direction; use no distance attenuation
262+
float3 L = normalize(-lightVec); // light direction towards the surface
263+
float3 radiance = lightColor; // No attenuation with distance
235264

236-
// Calculate half vector
237265
float3 H = normalize(V + L);
238266

239-
// Calculate BRDF terms
240267
float NdotL = max(dot(N, L), 0.0);
241268
float NdotV = max(dot(N, V), 0.0);
242269
float NdotH = max(dot(N, H), 0.0);
243270
float HdotV = max(dot(H, V), 0.0);
244271

245-
// Calculate shadow factor for emissive lights
246272
float shadow = 0.0;
247273
if (i < ubo.shadowMapCount) {
248-
// Transform fragment position to light space
249274
float4 fragPosLightSpace = mul(light.lightSpaceMatrix, float4(input.WorldPos, 1.0));
250275
shadow = calculateShadow(fragPosLightSpace, i, N, L);
251276
}
252277

253-
// Specular BRDF
254278
float D = DistributionGGX(NdotH, roughness);
255279
float G = GeometrySmith(NdotV, NdotL, roughness);
256280
float3 F = FresnelSchlick(HdotV, F0);
@@ -259,40 +283,32 @@ float4 PSMain(VSOutput input) : SV_TARGET
259283
float denominator = 4.0 * NdotV * NdotL + 0.0001;
260284
float3 specular = numerator / denominator;
261285

262-
// Energy conservation
263286
float3 kS = F;
264287
float3 kD = float3(1.0, 1.0, 1.0) - kS;
265288
kD *= 1.0 - metallic;
266289

267-
// Apply shadow factor to lighting
268290
float shadowFactor = 1.0 - shadow;
269291
Lo += (kD * baseColor.rgb / PI + specular) * radiance * NdotL * shadowFactor;
270292

271-
} else { // Regular lights (Point, Directional, Spot)
272-
// Calculate light direction and distance
293+
} else { // Point/Spot lights
273294
float3 L = normalize(lightPos - input.WorldPos);
274295
float distance = length(lightPos - input.WorldPos);
275296
float attenuation = 1.0 / (distance * distance);
276297
float3 radiance = lightColor * attenuation;
277298

278-
// Calculate half vector
279299
float3 H = normalize(V + L);
280300

281-
// Calculate BRDF terms
282301
float NdotL = max(dot(N, L), 0.0);
283302
float NdotV = max(dot(N, V), 0.0);
284303
float NdotH = max(dot(N, H), 0.0);
285304
float HdotV = max(dot(H, V), 0.0);
286305

287-
// Calculate shadow factor
288306
float shadow = 0.0;
289307
if (i < ubo.shadowMapCount) {
290-
// Transform fragment position to light space
291308
float4 fragPosLightSpace = mul(light.lightSpaceMatrix, float4(input.WorldPos, 1.0));
292309
shadow = calculateShadow(fragPosLightSpace, i, N, L);
293310
}
294311

295-
// Specular BRDF
296312
float D = DistributionGGX(NdotH, roughness);
297313
float G = GeometrySmith(NdotV, NdotL, roughness);
298314
float3 F = FresnelSchlick(HdotV, F0);
@@ -301,12 +317,10 @@ float4 PSMain(VSOutput input) : SV_TARGET
301317
float denominator = 4.0 * NdotV * NdotL + 0.0001;
302318
float3 specular = numerator / denominator;
303319

304-
// Energy conservation
305320
float3 kS = F;
306321
float3 kD = float3(1.0, 1.0, 1.0) - kS;
307322
kD *= 1.0 - metallic;
308323

309-
// Apply shadow factor to lighting (1.0 - shadow means 0 shadow = full light, 1 shadow = no light)
310324
float shadowFactor = 1.0 - shadow;
311325
Lo += (kD * baseColor.rgb / PI + specular) * radiance * NdotL * shadowFactor;
312326
}

0 commit comments

Comments
 (0)