Skip to content

Commit

Permalink
add multiple light support
Browse files Browse the repository at this point in the history
  • Loading branch information
vertoker committed Nov 4, 2024
1 parent af782f9 commit b208484
Show file tree
Hide file tree
Showing 13 changed files with 188 additions and 73 deletions.
6 changes: 2 additions & 4 deletions include/app.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@ class VulkanApp {

void run();

using render_system = std::shared_ptr<VulkanRenderSystem>;
using render_systems = std::vector<render_system>;

private:

void createDescriptors();
Expand All @@ -63,7 +60,8 @@ class VulkanApp {
std::unique_ptr<VulkanDescriptorPool> globalPool;
std::unique_ptr<VulkanDescriptorSetLayout> globalSetLayout;

std::unique_ptr<render_systems> renderSystems;
std::unique_ptr<WorldRenderSystem> worldRenderSystem;
std::unique_ptr<PointLightSystem> pointLightSystem;
std::unique_ptr<InputKeyboardController> keyboardInput;

GameObject::map gameObjects;
Expand Down
16 changes: 13 additions & 3 deletions include/gameobject.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include <format>
#include <unordered_map>

struct Transform {
struct TransformComponent {
glm::vec3 position{ 0.0f, 0.0f, 0.0f };
glm::vec3 rotation{ 0.0f, 0.0f, 0.0f };
//glm::quat rotation{ 1.0f, 0.0f, 0.0f, 0.0f };
Expand All @@ -25,6 +25,10 @@ struct Transform {
glm::mat3 normalMatrix();
};

struct PointLightComponent {
float lightIntensity = 1.0f;
};

// Unity like
class GameObject {
public:
Expand All @@ -35,12 +39,18 @@ class GameObject {
static id_t currentId = 0;
return GameObject{ currentId++ };
}
static GameObject createPointLight(float intensity, float radius, glm::vec3 color);

const id_t getId() { return id; }

std::shared_ptr<VulkanModel> model{};
// TODO convert all of this into ECS

glm::vec3 color{};
Transform transform{};
TransformComponent transform{};

// Optional
std::shared_ptr<VulkanModel> model{};
std::unique_ptr<PointLightComponent> pointLight = nullptr;

private:
GameObject(id_t objId) : id{ objId } {}
Expand Down
4 changes: 2 additions & 2 deletions include/input.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ class InputKeyboardController {
void move(GLFWwindow* window, float dt, GameObject& controller);

KeyMappings keys{};
float moveSpeed{ 0.3f };
float lookSpeed{ 0.8f };
float moveSpeed{ 0.8f };
float lookSpeed{ 1.3f };
};
19 changes: 18 additions & 1 deletion include/render/frameInfo.hpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
#pragma once

#include "camera.hpp"
#include "gameobject.hpp"

#include <vulkan/vulkan.h>

#define MAX_LIGHTS 10

struct VulkanFrameInfo {
int frameIndex;
float deltaTime;
VkCommandBuffer commandBuffer;
VulkanCamera& camera;
VkDescriptorSet globalDescriptorSet;
GameObject::map& gameObjects;
};
};

struct PointLight {
glm::vec4 position{};
glm::vec4 color{};
};

struct UniformBufferObject {
glm::mat4 projection{1.0f};
glm::mat4 view{1.0f};

glm::vec4 ambientLightColor{1.0f, 1.0f, 1.0f, 0.02f}; // w is intensity
PointLight pointLights[MAX_LIGHTS];
int numLights;
};
1 change: 1 addition & 0 deletions include/systems/point_light_system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class PointLightSystem : public VulkanRenderSystem {
const std::string& vertFilePath, const std::string& fragFilePath);
~PointLightSystem() override;

void updateLights(VulkanFrameInfo& frameInfo, UniformBufferObject& ubo);
void render(VulkanFrameInfo& frameInfo) override;

private:
Expand Down
51 changes: 27 additions & 24 deletions src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,6 @@ VulkanApp::~VulkanApp()

}

struct UniformBufferObject {
// alignas is same as PushConstants
glm::mat4 projection{1.0f};
glm::mat4 view{1.0f};

//glm::vec3 lightDirection = glm::normalize(glm::vec3 {1.0f, -3.0f, -1.0f});

glm::vec4 ambientLightColor{1.0f, 1.0f, 1.0f, 0.02f}; // w is intensity
glm::vec3 lightPosition{-1.0f}; alignas(16)
glm::vec4 lightColor{0.0f, 1.0f, 0.0f, 1.0f}; // w is lightIntensity
};

const float MAX_FRAME_TIME = 0.25f;

void VulkanApp::run()
Expand Down Expand Up @@ -69,6 +57,8 @@ void VulkanApp::run()

auto currentTime = std::chrono::high_resolution_clock::now();
auto cameraObject = GameObject::createGameObject();

cameraObject.transform.position = glm::vec3{0.0f, -1.5f, 0.0f};

while (!window->shouldClose()) {
glfwPollEvents();
Expand Down Expand Up @@ -111,14 +101,14 @@ void VulkanApp::run()
UniformBufferObject ubo{};
ubo.projection = camera->getProjection();
ubo.view = camera->getView();
pointLightSystem->updateLights(frameInfo, ubo);
uboBuffers[frameIndex]->writeToBuffer(&ubo);
uboBuffers[frameIndex]->flush();

// rendering
renderer->beginSwapChainRenderPass(commandBuffer);
for (size_t i = 0; i < renderSystems->size(); i++) {
renderSystems->at(i)->render(frameInfo);
}
worldRenderSystem->render(frameInfo);
pointLightSystem->render(frameInfo);
renderer->endSwapChainRenderPass(commandBuffer);
renderer->endFrame();
}
Expand All @@ -143,21 +133,16 @@ void VulkanApp::createDescriptors()

void VulkanApp::createRenderSystems(VulkanAppSettings& settings)
{
auto worldRenderSystem = std::make_shared<WorldRenderSystem>(*device,
worldRenderSystem = std::make_unique<WorldRenderSystem>(*device,
renderer->getSwapChainRenderPass(),
globalSetLayout->getDescriptorSetLayout(),
settings.world_vertShaderPath,
settings.world_fragShaderPath);
auto pointLightSystem = std::make_shared<PointLightSystem>(*device,
pointLightSystem = std::make_unique<PointLightSystem>(*device,
renderer->getSwapChainRenderPass(),
globalSetLayout->getDescriptorSetLayout(),
settings.pointLight_vertShaderPath,
settings.pointLight_fragShaderPath);

renderSystems = std::make_unique<render_systems>();
renderSystems->reserve(2);
renderSystems->emplace_back(std::static_pointer_cast<VulkanRenderSystem>(worldRenderSystem));
renderSystems->emplace_back(std::static_pointer_cast<VulkanRenderSystem>(pointLightSystem));
}

void VulkanApp::loadGameObjects(const std::string &modelPath)
Expand All @@ -166,12 +151,30 @@ void VulkanApp::loadGameObjects(const std::string &modelPath)

auto gameObj = GameObject::createGameObject();
gameObj.model = testModel;
gameObj.transform.position = { 0.0f, 0.0f, 1.0f };
gameObj.transform.position = { -1.0f, 1.5f, 1.0f };
gameObj.transform.rotation = { 0.0f, 0.0f, 0.0f };
//gameObj.transform.rotation = { 1.0f, 1.0f, 0.5f, 0.0f };

//gameObj.transform.scale = { 1.5f, 1.5f, 1.5f };
gameObj.transform.scale = { 0.5f, 0.5f, 0.5f };
gameObj.transform.scale = { 1.0f, 1.0f, 1.0f };
//gameObj.transform.scale = { 0.5f, 0.5f, 0.5f };

gameObjects.emplace(gameObj.getId(), std::move(gameObj));

// Lights
std::vector<glm::vec3> lightColors {
{1.0f, 0.1f, 0.1f},
{0.1f, 0.1f, 1.0f},
{0.1f, 1.0f, 0.1f},
{1.0f, 1.0f, 0.1f},
{0.1f, 1.0f, 1.0f},
{1.0f, 1.0f, 1.0f}
};

for (size_t i = 0; i < lightColors.size(); i++) {
auto pointLight = GameObject::createPointLight(0.8f, 0.1f, lightColors[i]);
auto rotateLight = glm::rotate(glm::mat4(1.0f), (i * glm::two_pi<float>()) / lightColors.size(), {0.0f, -1.0f, 0.0f});
pointLight.transform.position = glm::vec3(rotateLight * glm::vec4(-1.0f, -1.0f, -1.0f, 1.0f));
gameObjects.emplace(pointLight.getId(), std::move(pointLight));
}
}
18 changes: 14 additions & 4 deletions src/gameobject.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "gameobject.hpp"
#include <glm/gtc/quaternion.hpp>

/*glm::mat4 Transform::rotation_matrix() const
/*glm::mat4 TransformComponent::rotation_matrix() const
{
float x = rotation.x * 2.0f;
float y = rotation.y * 2.0f;
Expand Down Expand Up @@ -49,7 +49,7 @@
return matrix;
}*/

/*glm::mat4 Transform::matrix2()
/*glm::mat4 TransformComponent::matrix2()
{
auto matrix = glm::translate(glm::mat4{ 1.0f }, position);
matrix = matrix * rotation_matrix();
Expand All @@ -58,7 +58,7 @@
}*/

// position * rotation.y * rotation.x * rotation.z * scale
glm::mat4 Transform::matrix()
glm::mat4 TransformComponent::matrix()
{
const float s1 = glm::sin(rotation.y);
const float c1 = glm::cos(rotation.y);
Expand Down Expand Up @@ -98,7 +98,7 @@ glm::mat4 Transform::matrix()
};
}

glm::mat3 Transform::normalMatrix()
glm::mat3 TransformComponent::normalMatrix()
{
const float s1 = glm::sin(rotation.y);
const float c1 = glm::cos(rotation.y);
Expand Down Expand Up @@ -127,3 +127,13 @@ glm::mat3 Transform::normalMatrix()
},
};
}

GameObject GameObject::createPointLight(float intensity, float radius, glm::vec3 color)
{
GameObject obj = GameObject::createGameObject();
obj.color = color;
obj.transform.scale = glm::vec3{radius};
obj.pointLight = std::make_unique<PointLightComponent>();
obj.pointLight->lightIntensity = intensity;
return obj;
}
17 changes: 13 additions & 4 deletions src/shaders/point_light.frag
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,28 @@
layout(location = 0) in vec2 fragOffset;
layout(location = 0) out vec4 outColor;

struct PointLight {
vec4 position; // ignore w
vec4 color; // w is intensity
};
layout(set = 0, binding = 0) uniform UniformBufferObject {
mat4 projectionMatrix;
mat4 viewMatrix;

vec4 ambientLightColor; // w is for intensity
vec3 lightPosition;
vec4 lightColor; // w is for intensity
PointLight pointLights[10];
int numLights;
} ubo;

layout(push_constant) uniform Push {
vec4 position;
vec4 color;
float radius;
} push;

void main() {
float dis = sqrt(dot(fragOffset, fragOffset));
if (dis >= 1.0) {
discard;
}
outColor = ubo.lightColor;
outColor = push.color;
}
21 changes: 14 additions & 7 deletions src/shaders/point_light.vert
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,32 @@ const vec2 OFFSETS[6] = vec2[](

layout(location = 0) out vec2 fragOffset;

struct PointLight {
vec4 position; // ignore w
vec4 color; // w is intensity
};
layout(set = 0, binding = 0) uniform UniformBufferObject {
mat4 projectionMatrix;
mat4 viewMatrix;

vec4 ambientLightColor; // w is for intensity
vec3 lightPosition;
vec4 lightColor; // w is for intensity
PointLight pointLights[10];
int numLights;
} ubo;

const float LIGHT_RADIUS = 0.1;
layout(push_constant) uniform Push {
vec4 position;
vec4 color;
float radius;
} push;

void main() {
fragOffset = OFFSETS[gl_VertexIndex];
vec3 cameraRightWorld = {ubo.viewMatrix[0][0], ubo.viewMatrix[1][0], ubo.viewMatrix[2][0]};
vec3 cameraUpWorld = {ubo.viewMatrix[0][1], ubo.viewMatrix[1][1], ubo.viewMatrix[2][1]};

vec3 positionWorld = ubo.lightPosition.xyz
+ LIGHT_RADIUS * fragOffset.x * cameraRightWorld
+ LIGHT_RADIUS * fragOffset.y * cameraUpWorld;
vec3 positionWorld = push.position.xyz
+ push.radius * fragOffset.x * cameraRightWorld
+ push.radius * fragOffset.y * cameraUpWorld;

gl_Position = ubo.projectionMatrix * ubo.viewMatrix * vec4(positionWorld, 1.0);
}
32 changes: 20 additions & 12 deletions src/shaders/world.frag
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ layout(location = 2) in vec3 fragNormalWorld;
// Output
layout(location = 0) out vec4 outColor;

struct PointLight {
vec4 position; // ignore w
vec4 color; // w is intensity
};
layout(set = 0, binding = 0) uniform UniformBufferObject {
mat4 projectionMatrix;
mat4 viewMatrix;

vec4 ambientLightColor; // w is for intensity
vec3 lightPosition;
vec4 lightColor; // w is for intensity
PointLight pointLights[10];
int numLights;
} ubo;

layout(push_constant) uniform Push {
Expand All @@ -26,15 +29,20 @@ layout(push_constant) uniform Push {
// Input location and Output location is different buffers

void main() {
vec3 distanceToLight = ubo.lightPosition - fragPosWorld;
vec3 directionToLight = normalize(distanceToLight);

vec3 ambientLightColor = ubo.ambientLightColor.xyz * ubo.ambientLightColor.w;
vec3 diffuseLight = ubo.ambientLightColor.xyz * ubo.ambientLightColor.w;
vec3 surfaceNormal = normalize(fragNormalWorld);

// dot product of vec3 itself is easy squared distance
float attenuation = 1.0 / dot(distanceToLight, distanceToLight);
vec3 lightColor = ubo.lightColor.xyz * ubo.lightColor.w * attenuation;
vec3 diffuseLight = lightColor * max(dot(normalize(fragNormalWorld), directionToLight), 0);
for (int i = 0; i < ubo.numLights; i++) {
PointLight light = ubo.pointLights[i];
vec3 vectorToLight = light.position.xyz - fragPosWorld;
vec3 directionToLight = normalize(vectorToLight);

outColor = vec4((diffuseLight + ambientLightColor) * fragColor, 1.0);
float distanceAttenuation = 1.0 / dot(vectorToLight, vectorToLight); // distance squared
float cosRefraction = max(dot(surfaceNormal, directionToLight), 0);

vec3 lightIntensity = light.color.xyz * light.color.w * distanceAttenuation;
diffuseLight += lightIntensity * cosRefraction;
}

outColor = vec4(diffuseLight * fragColor, 1.0);
}
Loading

0 comments on commit b208484

Please sign in to comment.