Skip to content

Commit adf461e

Browse files
committed
Remove shadows for now. We'll concentrate on them in the samples version.
Add ability to set time of day so can experience the night with nice lights. Still have a bug in the emissive light textures as it looks like the bulbs aren't quite working right.
1 parent a5edf28 commit adf461e

File tree

10 files changed

+273
-399
lines changed

10 files changed

+273
-399
lines changed

attachments/simple_engine/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ set(SOURCES
102102
renderer_compute.cpp
103103
renderer_utils.cpp
104104
renderer_resources.cpp
105-
renderer_shadows.cpp
106105
memory_pool.cpp
107106
resource_manager.cpp
108107
entity.cpp

attachments/simple_engine/imgui_system.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -169,22 +169,28 @@ void ImGuiSystem::NewFrame() {
169169
std::cout << "Exposure reset to: " << exposure << std::endl;
170170
}
171171

172-
// Shadow toggle
173-
static bool shadowsEnabled = true; // Default shadows on
174-
if (ImGui::Checkbox("Enable Shadows", &shadowsEnabled)) {
175-
// Update shadows in renderer
176-
if (renderer) {
177-
renderer->SetShadowsEnabled(shadowsEnabled);
178-
}
179-
std::cout << "Shadows " << (shadowsEnabled ? "enabled" : "disabled") << std::endl;
180-
}
181-
182172
ImGui::Text("Tip: Adjust gamma if scene looks too dark/bright");
183173
ImGui::Text("Tip: Adjust exposure if scene looks washed out");
184174
} else {
185175
ImGui::Text("Note: Quality controls affect BRDF rendering only");
186176
}
187177

178+
ImGui::Separator();
179+
180+
// Sun position control (punctual light in GLTF)
181+
ImGui::Text("Sun Position in Sky:");
182+
if (renderer) {
183+
float sun = renderer->GetSunPosition();
184+
if (ImGui::SliderFloat("Sun Position", &sun, 0.0f, 1.0f, "%.2f")) {
185+
renderer->SetSunPosition(sun);
186+
}
187+
ImGui::SameLine();
188+
if (ImGui::Button("Noon")) { sun = 0.5f; renderer->SetSunPosition(sun); }
189+
ImGui::SameLine();
190+
if (ImGui::Button("Night")) { sun = 0.0f; renderer->SetSunPosition(sun); }
191+
ImGui::Text("Tip: 0/1 = Night, 0.5 = Noon. Warmer tint near horizon simulates evening.");
192+
}
193+
188194
ImGui::Separator();
189195
ImGui::Text("3D Audio Position Control");
190196

attachments/simple_engine/model_loader.cpp

Lines changed: 120 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ bool ModelLoader::ParseGLTF(const std::string& filename, Model* model) {
215215
gltfMaterial.emissiveFactor[0],
216216
gltfMaterial.emissiveFactor[1],
217217
gltfMaterial.emissiveFactor[2]
218-
) * light_scale;
218+
);
219219
}
220220

221221
// Parse KHR_materials_emissive_strength extension
@@ -1327,21 +1327,46 @@ std::vector<ExtractedLight> ModelLoader::GetExtractedLights(const std::string& m
13271327
avgNormal = glm::vec3(0.0f, -1.0f, 0.0f); // Default downward direction
13281328
}
13291329

1330-
// Create an emissive light source
1331-
ExtractedLight emissiveLight;
1332-
emissiveLight.type = ExtractedLight::Type::Emissive;
1333-
emissiveLight.position = center;
1334-
emissiveLight.color = material->emissive;
1335-
emissiveLight.intensity = material->emissiveStrength;
1336-
emissiveLight.range = 1.0f; // Default range for emissive lights
1337-
emissiveLight.sourceMaterial = material->GetName();
1338-
emissiveLight.direction = avgNormal;
1339-
1340-
lights.push_back(emissiveLight);
1341-
1342-
std::cout << "Created emissive light from material '" << material->GetName()
1343-
<< "' at position (" << center.x << ", " << center.y << ", " << center.z
1344-
<< ") with intensity " << emissiveIntensity << std::endl;
1330+
// Create emissive light(s) transformed by each instance's model matrix
1331+
if (!materialMesh.instances.empty()) {
1332+
for (const auto& inst : materialMesh.instances) {
1333+
glm::mat4 M = inst.getModelMatrix();
1334+
glm::vec3 worldCenter = glm::vec3(M * glm::vec4(center, 1.0f));
1335+
glm::mat3 normalMat = glm::transpose(glm::inverse(glm::mat3(M)));
1336+
glm::vec3 worldNormal = glm::normalize(normalMat * avgNormal);
1337+
1338+
ExtractedLight emissiveLight;
1339+
emissiveLight.type = ExtractedLight::Type::Emissive;
1340+
emissiveLight.position = worldCenter;
1341+
emissiveLight.color = material->emissive;
1342+
emissiveLight.intensity = material->emissiveStrength;
1343+
emissiveLight.range = 1.0f; // Default range for emissive lights
1344+
emissiveLight.sourceMaterial = material->GetName();
1345+
emissiveLight.direction = worldNormal;
1346+
1347+
lights.push_back(emissiveLight);
1348+
1349+
std::cout << "Created emissive light from material '" << material->GetName()
1350+
<< "' at world position (" << worldCenter.x << ", " << worldCenter.y << ", " << worldCenter.z
1351+
<< ") with intensity " << emissiveIntensity << std::endl;
1352+
}
1353+
} else {
1354+
// No explicit instances; use identity transform
1355+
ExtractedLight emissiveLight;
1356+
emissiveLight.type = ExtractedLight::Type::Emissive;
1357+
emissiveLight.position = center;
1358+
emissiveLight.color = material->emissive;
1359+
emissiveLight.intensity = material->emissiveStrength;
1360+
emissiveLight.range = 1.0f; // Default range for emissive lights
1361+
emissiveLight.sourceMaterial = material->GetName();
1362+
emissiveLight.direction = avgNormal;
1363+
1364+
lights.push_back(emissiveLight);
1365+
1366+
std::cout << "Created emissive light from material '" << material->GetName()
1367+
<< "' at position (" << center.x << ", " << center.y << ", " << center.z
1368+
<< ") with intensity " << emissiveIntensity << std::endl;
1369+
}
13451370
}
13461371
}
13471372
}
@@ -1446,35 +1471,90 @@ bool ModelLoader::ExtractPunctualLights(const tinygltf::Model& gltfModel, const
14461471
std::cout << " No KHR_lights_punctual extension found" << std::endl;
14471472
}
14481473

1449-
// Now find light nodes in the scene to get positions and directions
1450-
for (const auto& node : gltfModel.nodes) {
1474+
// Compute world transforms for all nodes in the default scene
1475+
std::vector<glm::mat4> nodeWorldTransforms(gltfModel.nodes.size(), glm::mat4(1.0f));
1476+
1477+
auto calcLocal = [](const tinygltf::Node& n) -> glm::mat4 {
1478+
// If matrix is provided, use it
1479+
if (n.matrix.size() == 16) {
1480+
glm::mat4 m(1.0f);
1481+
for (int r = 0; r < 4; ++r) {
1482+
for (int c = 0; c < 4; ++c) {
1483+
m[c][r] = static_cast<float>(n.matrix[r * 4 + c]);
1484+
}
1485+
}
1486+
return m;
1487+
}
1488+
// Otherwise compose TRS
1489+
glm::mat4 T(1.0f), R(1.0f), S(1.0f);
1490+
if (n.translation.size() == 3) {
1491+
T = glm::translate(glm::mat4(1.0f), glm::vec3(
1492+
static_cast<float>(n.translation[0]),
1493+
static_cast<float>(n.translation[1]),
1494+
static_cast<float>(n.translation[2])));
1495+
}
1496+
if (n.rotation.size() == 4) {
1497+
glm::quat q(
1498+
static_cast<float>(n.rotation[3]),
1499+
static_cast<float>(n.rotation[0]),
1500+
static_cast<float>(n.rotation[1]),
1501+
static_cast<float>(n.rotation[2]));
1502+
R = glm::mat4_cast(q);
1503+
}
1504+
if (n.scale.size() == 3) {
1505+
S = glm::scale(glm::mat4(1.0f), glm::vec3(
1506+
static_cast<float>(n.scale[0]),
1507+
static_cast<float>(n.scale[1]),
1508+
static_cast<float>(n.scale[2])));
1509+
}
1510+
return T * R * S;
1511+
};
1512+
1513+
std::function<void(int, const glm::mat4&)> traverseNode = [&](int nodeIndex, const glm::mat4& parent) {
1514+
if (nodeIndex < 0 || nodeIndex >= static_cast<int>(gltfModel.nodes.size())) return;
1515+
const tinygltf::Node& n = gltfModel.nodes[nodeIndex];
1516+
glm::mat4 local = calcLocal(n);
1517+
glm::mat4 world = parent * local;
1518+
nodeWorldTransforms[nodeIndex] = world;
1519+
for (int child : n.children) {
1520+
traverseNode(child, world);
1521+
}
1522+
};
1523+
1524+
if (!gltfModel.scenes.empty()) {
1525+
int sceneIndex = gltfModel.defaultScene >= 0 ? gltfModel.defaultScene : 0;
1526+
if (sceneIndex < static_cast<int>(gltfModel.scenes.size())) {
1527+
const tinygltf::Scene& scene = gltfModel.scenes[sceneIndex];
1528+
for (int root : scene.nodes) {
1529+
traverseNode(root, glm::mat4(1.0f));
1530+
}
1531+
}
1532+
} else {
1533+
// Fallback: traverse all nodes as roots
1534+
for (int i = 0; i < static_cast<int>(gltfModel.nodes.size()); ++i) {
1535+
traverseNode(i, glm::mat4(1.0f));
1536+
}
1537+
}
1538+
1539+
// Now assign positions and directions using world transforms
1540+
for (size_t nodeIndex = 0; nodeIndex < gltfModel.nodes.size(); ++nodeIndex) {
1541+
const auto& node = gltfModel.nodes[nodeIndex];
14511542
if (node.extensions.contains("KHR_lights_punctual")) {
14521543
const tinygltf::Value& nodeExtension = node.extensions.at("KHR_lights_punctual");
14531544
if (nodeExtension.Has("light") && nodeExtension.Get("light").IsInt()) {
14541545
int lightIndex = nodeExtension.Get("light").Get<int>();
14551546
if (lightIndex >= 0 && lightIndex < static_cast<int>(lights.size())) {
1456-
// Extract position from node transform
1457-
if (node.translation.size() >= 3) {
1458-
lights[lightIndex].position = glm::vec3(
1459-
static_cast<float>(node.translation[0]),
1460-
static_cast<float>(node.translation[1]),
1461-
static_cast<float>(node.translation[2])
1462-
);
1463-
}
1464-
1465-
// Extract direction from node rotation (for directional and spotlights)
1466-
if (node.rotation.size() >= 4 &&
1467-
(lights[lightIndex].type == ExtractedLight::Type::Directional ||
1468-
lights[lightIndex].type == ExtractedLight::Type::Spot)) {
1469-
// Convert quaternion to a direction vector
1470-
glm::quat rotation(
1471-
static_cast<float>(node.rotation[3]), // w
1472-
static_cast<float>(node.rotation[0]), // x
1473-
static_cast<float>(node.rotation[1]), // y
1474-
static_cast<float>(node.rotation[2]) // z
1475-
);
1476-
// Default forward direction in glTF is -Z
1477-
lights[lightIndex].direction = rotation * glm::vec3(0.0f, 0.0f, -1.0f);
1547+
const glm::mat4& W = nodeWorldTransforms[nodeIndex];
1548+
// Position from world transform origin
1549+
glm::vec3 pos = glm::vec3(W * glm::vec4(0, 0, 0, 1));
1550+
lights[lightIndex].position = pos;
1551+
1552+
// Direction for directional/spot: transform -Z
1553+
if (lights[lightIndex].type == ExtractedLight::Type::Directional ||
1554+
lights[lightIndex].type == ExtractedLight::Type::Spot) {
1555+
glm::mat3 rot = glm::mat3(W);
1556+
glm::vec3 dir = glm::normalize(rot * glm::vec3(0.0f, 0.0f, -1.0f));
1557+
lights[lightIndex].direction = dir;
14781558
}
14791559

14801560
std::cout << " Light " << lightIndex << " positioned at ("

attachments/simple_engine/renderer.h

Lines changed: 19 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <optional>
99
#include <unordered_map>
1010
#include <mutex>
11+
#include <algorithm>
1112

1213
#include "platform.h"
1314
#include "entity.h"
@@ -67,13 +68,13 @@ struct UniformBufferObject {
6768
alignas(4) float prefilteredCubeMipLevels;
6869
alignas(4) float scaleIBLAmbient;
6970
alignas(4) int lightCount; // Number of active lights (dynamic)
70-
alignas(4) int shadowMapCount; // Number of active shadow maps (dynamic)
71-
alignas(4) float shadowBias; // Shadow bias to prevent shadow acne
71+
alignas(4) int padding0; // Padding for alignment (shadows removed)
7272
alignas(4) float padding1; // Padding for alignment
73+
alignas(4) float padding2; // Padding for alignment
7374

7475
// Additional padding to ensure the structure size is aligned to 64 bytes (device nonCoherentAtomSize)
75-
// Current size: 3*64 + 16 + 8*4 = 240 bytes, pad to 256 bytes (multiple of 64)
76-
alignas(4) float padding2[4]; // Add 16 more bytes to reach 256 bytes total
76+
// Adjusted padding to maintain 256 bytes total size
77+
alignas(4) float padding3[2]; // Add remaining bytes to reach 256 bytes total
7778
};
7879

7980

@@ -162,6 +163,16 @@ class Renderer {
162163
*/
163164
bool IsInitialized() const { return initialized; }
164165

166+
/**
167+
* @brief Set sun position slider value in [0,1]. 0 and 1 = night, 0.5 = noon.
168+
*/
169+
void SetSunPosition(float s) { sunPosition = std::clamp(s, 0.0f, 1.0f); }
170+
171+
/**
172+
* @brief Get sun position slider value.
173+
*/
174+
float GetSunPosition() const { return sunPosition; }
175+
165176

166177
/**
167178
* @brief Get the Vulkan device.
@@ -347,21 +358,6 @@ class Renderer {
347358
exposure = _exposure;
348359
}
349360

350-
/**
351-
* @brief Enable or disable shadow rendering.
352-
* @param enabled True to enable shadows, false to disable.
353-
* @note Shadows should be pre-computed and cached during model loading for optimal performance.
354-
* Toggling this flag should only affect shader uniform values, not trigger recomputation.
355-
*/
356-
void SetShadowsEnabled(bool enabled) {
357-
// Only update if the value actually changed to avoid unnecessary uniform buffer updates
358-
if (this->shadowsEnabled != enabled) {
359-
this->shadowsEnabled = enabled;
360-
// TODO: Update uniform buffer with shadow enable/disable flag
361-
// Shadow maps should remain cached and not be recomputed
362-
}
363-
}
364-
365361
/**
366362
* @brief Create or resize light storage buffers to accommodate the given number of lights.
367363
* @param lightCount The number of lights to accommodate.
@@ -417,7 +413,9 @@ class Renderer {
417413
// PBR rendering parameters
418414
float gamma = 2.2f; // Gamma correction value
419415
float exposure = 3.0f; // HDR exposure value (higher for emissive lighting)
420-
bool shadowsEnabled = true; // Shadow rendering enabled by default
416+
417+
// Sun control (UI-driven)
418+
float sunPosition = 0.5f; // 0..1, extremes are night, 0.5 is noon
421419

422420
// Vulkan RAII context
423421
vk::raii::Context context;
@@ -519,25 +517,8 @@ class Renderer {
519517
// Default texture resources (used when no texture is provided)
520518
TextureResources defaultTextureResources;
521519

522-
// Shadow mapping resources
523-
struct ShadowMapResources {
524-
vk::raii::Image shadowMapImage = nullptr;
525-
std::unique_ptr<MemoryPool::Allocation> shadowMapImageAllocation = nullptr;
526-
vk::raii::ImageView shadowMapImageView = nullptr;
527-
vk::raii::Sampler shadowMapSampler = nullptr;
528-
vk::raii::Framebuffer shadowMapFramebuffer = nullptr;
529-
vk::raii::RenderPass shadowMapRenderPass = nullptr;
530-
uint32_t shadowMapSize = 2048; // Default shadow map resolution
531-
};
532-
std::vector<ShadowMapResources> shadowMaps; // One shadow map per light
533-
534-
// Shadow mapping constants
535-
static constexpr uint32_t MAX_SHADOW_MAPS = 16; // Descriptors/array size remains 16
536-
static constexpr uint32_t DEFAULT_SHADOW_MAP_SIZE = 2048;
537-
538520
// Performance clamps (to reduce per-frame cost)
539-
static constexpr uint32_t MAX_ACTIVE_LIGHTS = 32; // Limit the number of lights processed per frame
540-
static constexpr uint32_t MAX_SHADOW_MAPS_USED = 4; // Limit the number of shadows sampled per frame
521+
static constexpr uint32_t MAX_ACTIVE_LIGHTS = 1024; // Limit the number of lights processed per frame
541522

542523
// Static lights loaded during model initialization
543524
std::vector<ExtractedLight> staticLights;
@@ -627,12 +608,6 @@ class Renderer {
627608
bool createCommandPool();
628609

629610
// Shadow mapping methods
630-
bool createShadowMaps();
631-
bool createShadowMapRenderPass();
632-
bool createShadowMapFramebuffers();
633-
bool createShadowMapDescriptorSetLayout();
634-
void renderShadowMaps(const std::vector<Entity*>& entities, const std::vector<ExtractedLight>& lights);
635-
void updateShadowMapUniforms(uint32_t lightIndex, const ExtractedLight& light);
636611
bool createComputeCommandPool();
637612
bool createDepthResources();
638613
bool createTextureImage(const std::string& texturePath, TextureResources& resources);

attachments/simple_engine/renderer_core.cpp

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -162,29 +162,6 @@ bool Renderer::Initialize(const std::string& appName, bool enableValidationLayer
162162
return false;
163163
}
164164

165-
// Create shadow maps for shadow mapping
166-
if (!createShadowMaps()) {
167-
std::cerr << "Failed to create shadow maps" << std::endl;
168-
return false;
169-
}
170-
171-
// Create a shadow map render pass
172-
if (!createShadowMapRenderPass()) {
173-
std::cerr << "Failed to create shadow map render pass" << std::endl;
174-
return false;
175-
}
176-
177-
// Create shadow map framebuffers
178-
if (!createShadowMapFramebuffers()) {
179-
std::cerr << "Failed to create shadow map framebuffers" << std::endl;
180-
return false;
181-
}
182-
183-
// Create a shadow map descriptor set layout
184-
if (!createShadowMapDescriptorSetLayout()) {
185-
std::cerr << "Failed to create shadow map descriptor set layout" << std::endl;
186-
return false;
187-
}
188165

189166
// Create command buffers
190167
if (!createCommandBuffers()) {

attachments/simple_engine/renderer_pipelines.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,17 +95,9 @@ bool Renderer::createPBRDescriptorSetLayout() {
9595
.stageFlags = vk::ShaderStageFlagBits::eFragment,
9696
.pImmutableSamplers = nullptr
9797
},
98-
// Binding 6: Shadow map array
98+
// Binding 6: Light storage buffer (shadows removed)
9999
vk::DescriptorSetLayoutBinding{
100100
.binding = 6,
101-
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
102-
.descriptorCount = MAX_SHADOW_MAPS, // Array of shadow maps (dynamic count)
103-
.stageFlags = vk::ShaderStageFlagBits::eFragment,
104-
.pImmutableSamplers = nullptr
105-
},
106-
// Binding 7: Light storage buffer
107-
vk::DescriptorSetLayoutBinding{
108-
.binding = 7,
109101
.descriptorType = vk::DescriptorType::eStorageBuffer,
110102
.descriptorCount = 1,
111103
.stageFlags = vk::ShaderStageFlagBits::eFragment,

0 commit comments

Comments
 (0)