Skip to content

Commit

Permalink
Added spot light direction settings. Added light space transformations.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismile committed Sep 6, 2024
1 parent f45ab5c commit c2ed44d
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 1 deletion.
3 changes: 3 additions & 0 deletions Data/Shaders/VPT/VptHeader.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,9 @@ struct Light {
// Point light & spotlight.
vec3 position; ///< POINT & SPOT; distance for DIRECTIONAL.
uint useDistance; ///< POINT & SPOT

vec3 spotDirection;
float padding;
};
layout (binding = 31) uniform LightsBuffer {
Light lights[NUM_LIGHTS];
Expand Down
6 changes: 5 additions & 1 deletion Data/Shaders/VPT/VptUtils.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,11 @@ vec3 sampleHeadlight(vec3 pos, uint lightIdx) {
const float falloffStart =
light.spotTotalWidth > light.spotFalloffStart ? cos(light.spotFalloffStart) : totalWidth;
vec3 p = pos - lightPosition;
vec3 z = light.lightSpace == LIGHT_SPACE_VIEW ? parameters.camForward : normalize(-lightPosition);
//vec3 z = light.lightSpace == LIGHT_SPACE_VIEW ? parameters.camForward : normalize(-lightPosition);
vec3 z = normalize(light.spotDirection);
if (light.lightSpace == LIGHT_SPACE_VIEW || light.lightSpace == LIGHT_SPACE_VIEW_ORIENTATION) {
z = (parameters.inverseViewMatrix * vec4(z, 0.0)).xyz;
}
float cosTheta = dot(z, p) / (length(z) * length(p));
float coneFactor = smoothstep(totalWidth, falloffStart, cosTheta);
lightFactor *= coneFactor;
Expand Down
1 change: 1 addition & 0 deletions src/MainApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ MainApp::MainApp()
checkpointWindow.setStandardWindowPosition(841, 53);

lightEditorWidget = new LightEditorWidget(rendererVk);
lightEditorWidget->setCamera(camera);
lightEditorWidget->setShowWindow(false);

propertyEditor.setInitWidthValues(sgl::ImGuiWrapper::get()->getScaleDependentSize(280.0f));
Expand Down
55 changes: 55 additions & 0 deletions src/PathTracer/LightEditorWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <Utils/AppSettings.hpp>
#include <Utils/File/FileUtils.hpp>
#include <Utils/File/Logfile.hpp>
#include <Graphics/Scene/Camera.hpp>
#include <Graphics/Vulkan/Utils/Device.hpp>
#include <Graphics/Vulkan/Buffers/Buffer.hpp>
#include <Graphics/Vulkan/Render/Renderer.hpp>
Expand Down Expand Up @@ -231,6 +232,7 @@ bool LightEditorWidget::renderGui() {
addLight(light);
reRender = true;
}
ImGui::SameLine();
if (ImGui::Button("Save to File...")) {
fileDialogModeSave = true;
openSelectLightFileDialog();
Expand All @@ -240,6 +242,7 @@ bool LightEditorWidget::renderGui() {
fileDialogModeSave = false;
openSelectLightFileDialog();
}
ImGui::Checkbox("Transform on Space Change", &shallTransformOnSpaceChange);
}
propertyEditor->end();

Expand Down Expand Up @@ -295,6 +298,8 @@ void LightEditorWidget::setLightProperty(uint32_t lightIdx, const std::string& k
light.spotTotalWidth = sgl::fromString<float>(value);
} else if (key == "spot_falloff_start") {
light.spotFalloffStart = sgl::fromString<float>(value);
} else if (key == "spot_direction") {
light.spotDirection = stringToVec3(value);
}
}

Expand Down Expand Up @@ -386,6 +391,12 @@ bool LightEditorWidget::loadFromFile(const std::string& filePath) {
light.spotFalloffStart = lightNode["spot_falloff_start"].asFloat();
}

if (lightNode.isMember("spot_direction")) {
auto spotDirectionNode = lightNode["spot_direction"];
light.spotDirection = glm::vec3(
spotDirectionNode["x"].asFloat(), spotDirectionNode["y"].asFloat(), spotDirectionNode["z"].asFloat());
}

newLights.push_back(light);
newLightCreationIndices.push_back(newCurrentLightIdx++);
}
Expand Down Expand Up @@ -417,6 +428,11 @@ bool LightEditorWidget::saveToFile(const std::string& filePath) {
positionNode["y"] = light.position.y;
positionNode["z"] = light.position.z;

Json::Value spotDirectionNode;
spotDirectionNode["x"] = light.spotDirection.x;
spotDirectionNode["y"] = light.spotDirection.y;
spotDirectionNode["z"] = light.spotDirection.z;

Json::Value lightNode;
lightNode["type"] = LIGHT_TYPE_NAMES[int(light.lightType)];
lightNode["color"] = colorNode;
Expand All @@ -426,6 +442,7 @@ bool LightEditorWidget::saveToFile(const std::string& filePath) {
lightNode["space"] = LIGHT_SPACE_NAMES[int(light.lightSpace)];
lightNode["spot_total_width"] = light.spotTotalWidth;
lightNode["spot_falloff_start"] = light.spotFalloffStart;
lightNode["spot_direction"] = spotDirectionNode;
lightsNode.append(lightNode);
}
root["lights"] = lightsNode;
Expand Down Expand Up @@ -473,9 +490,14 @@ bool LightEditorWidget::renderGuiLight(size_t lightIdx) {
light.lightType == LightType::DIRECTIONAL ? "Direction" : "Position", &light.position.x, -2.0f, 2.0f)) {
reRender = true;
}

auto lightSpaceOld = light.lightSpace;
if (propertyEditor->addCombo(
"Light Space", reinterpret_cast<int*>(&light.lightSpace), LIGHT_SPACE_NAMES, IM_ARRAYSIZE(LIGHT_SPACE_NAMES))) {
reRender = true;
if (shallTransformOnSpaceChange) {
transformLightSpace(light, lightSpaceOld);
}
}

if (light.lightType == LightType::SPOT) {
Expand All @@ -485,7 +507,40 @@ bool LightEditorWidget::renderGuiLight(size_t lightIdx) {
if (propertyEditor->addSliderFloat("Falloff Start Angle", (float*)&light.spotFalloffStart, 0.0, sgl::HALF_PI)) {
reRender = true;
}
if (propertyEditor->addSliderFloat3("Spot Direction", &light.spotDirection.x, -1.0f, 1.0f)) {
reRender = true;
}
}

return reRender;
}

void LightEditorWidget::transformLightSpace(Light& light, LightSpace lightSpaceOld) {
LightSpace lightSpaceNew = light.lightSpace;
const auto& viewMatrix = camera->getViewMatrix();
auto inverseViewMatrix = glm::inverse(viewMatrix);

// Transform old position (or direction) from old to new world space.
glm::vec3 lightPosition = light.position;
if (lightSpaceOld == LightSpace::VIEW || lightSpaceOld == LightSpace::VIEW_ORIENTATION) {
const float homComp =
light.lightType == LightType::DIRECTIONAL || lightSpaceOld == LightSpace::VIEW_ORIENTATION ? 0.0f : 1.0f;
lightPosition = (inverseViewMatrix * glm::vec4(lightPosition, homComp));
}
if (lightSpaceNew == LightSpace::VIEW || lightSpaceNew == LightSpace::VIEW_ORIENTATION) {
const float homComp =
light.lightType == LightType::DIRECTIONAL || lightSpaceNew == LightSpace::VIEW_ORIENTATION ? 0.0f : 1.0f;
lightPosition = (viewMatrix * glm::vec4(lightPosition, homComp));
}
light.position = lightPosition;

// Transform old spot direction from old to new world space.
glm::vec3 spotDirection = light.spotDirection;
if (lightSpaceOld == LightSpace::VIEW || lightSpaceOld == LightSpace::VIEW_ORIENTATION) {
spotDirection = (inverseViewMatrix * glm::vec4(spotDirection, 0.0f));
}
if (lightSpaceNew == LightSpace::VIEW || lightSpaceNew == LightSpace::VIEW_ORIENTATION) {
spotDirection = (viewMatrix * glm::vec4(spotDirection, 0.0f));
}
light.spotDirection = spotDirection;
}
11 changes: 11 additions & 0 deletions src/PathTracer/LightEditorWidget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ typedef std::shared_ptr<Buffer> BufferPtr;
}}
namespace sgl {
class PropertyEditor;
class Camera;
typedef std::shared_ptr<Camera> CameraPtr;
}

namespace IGFD {
Expand Down Expand Up @@ -77,6 +79,9 @@ struct Light {
// Point light & spotlight.
glm::vec3 position{}; ///< POINT & SPOT; distance for DIRECTIONAL.
uint32_t useDistance = true; ///< POINT & SPOT

glm::vec3 spotDirection = glm::vec3(0.0f, 0.0f, -1.0f); ///< SPOT
float padding{}; ///< SPOT
};

class LightEditorWidget {
Expand All @@ -96,6 +101,7 @@ class LightEditorWidget {
inline void setStandardWindowSize(int width, int height) { standardWidth = width; standardHeight = height; }
inline void setStandardWindowPosition(int x, int y) { standardPositionX = x; standardPositionY = y; }
void setFileDialogInstance(ImGuiFileDialog* _fileDialogInstance);
inline void setCamera(const sgl::CameraPtr& _camera) { camera = _camera; }

/// Property interface.
void setLightProperty(uint32_t lightIdx, const std::string& key, const std::string& value);
Expand All @@ -107,12 +113,17 @@ class LightEditorWidget {

private:
sgl::vk::Renderer* renderer;
sgl::CameraPtr camera;

void recreateLightBuffer();
void updateLightBuffer();
std::vector<Light> lights;
sgl::vk::BufferPtr lightsBuffer;

// Whether to transform positions and directions on changing light spaces.
bool shallTransformOnSpaceChange = false;
void transformLightSpace(Light& light, LightSpace lightSpaceOld);

// Counts lights by their creation so that ImGui can keep track when lights are removed.
ptrdiff_t currentLightIdx = 0;
std::vector<ptrdiff_t> lightCreationIndices;
Expand Down

0 comments on commit c2ed44d

Please sign in to comment.