diff --git a/CMakeLists.txt b/CMakeLists.txt index fd55ad7..a71fecc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ add_subdirectory(3rdparty) include(cmake/BuildShaders.cmake) include(cmake/CopyData.cmake) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) find_package(SDL2 REQUIRED) find_package(Vulkan REQUIRED) @@ -56,7 +56,8 @@ set(GRAPH_SRC src/stringutils.cpp src/animationsystem.cpp src/worldmanager.cpp - src/assetmanager.cpp) + src/assetmanager.cpp + src/entityparser.cpp) if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(GRAPH_SRC @@ -69,8 +70,7 @@ add_executable(Graph target_compile_options(Graph PUBLIC - -fno-exceptions - -fno-rtti) + -fno-exceptions) target_link_libraries(Graph PUBLIC SDL2::SDL2 diff --git a/data/empty.world b/data/empty.world index 8a8f144..249eaaf 100644 --- a/data/empty.world +++ b/data/empty.world @@ -1,11 +1,21 @@ { - "meshes": [ - - ], - "lights": [ + "entities": [ { - "position": "66,56,25", - "type": 1 + "name": "sun", + "components": [ + { + "type": "Transform", + "position": "66,56,25" + }, + { + "type": "Light", + "kind": 1, + "color": "1,1,1" + } + ] } - ] + ], + "environment": { + "color": "0.9,0.9,0.9" + } } diff --git a/data/test.cim b/data/test.cim index bc845b2..d3b45c8 100644 --- a/data/test.cim +++ b/data/test.cim @@ -4,57 +4,96 @@ "world": "test.world", "start": 0, "end": 5, - "meshes": [ + "entities": [ { "name": "suzanne", - "path": "suzanne.obj", - "material": "test.material" + "components": [ + { + "type": "Mesh", + "path": "suzanne.obj", + "material": "test.material" + }, + { + "type": "Transform", + "position": "0,0,0" + } + ] }, { "name": "suzanne2", - "path": "suzanne.obj", - "material": "test.material" + "components": [ + { + "type": "Mesh", + "path": "suzanne.obj", + "material": "test.material" + }, + { + "type": "Transform", + "position": "0,0,0" + }, + { + "type": "Light", + "color": "1,0,0", + "kind": 0 + } + ] + }, + { + "name": "camera", + "components": [ + { + "type": "Transform", + "position": "0,0,0" + }, + { + "type": "Camera", + "fov": 75 + } + ] } ], "animations": [ { "target": "suzanne", + "targetComponent": "Transform", "property": "position", "keyframes": [ { "time": 0, - "value": "0,0,0" + "value": "0,2,0" }, { "time": 1, - "value": "0,2,-3.5" + "value": "0,4,-3.5" }, { "time": 3, - "value": "0,0.5,-4" + "value": "0,2.5,-4" }, { "time": 5, - "value": "0,0,-6" + "value": "0,2,-6" } ] }, { "target": "suzanne2", + "targetComponent": "Transform", "property": "position", "keyframes": [ { "time": 0, - "value": "5,0,-2" + "value": "5,2,-2" }, { "time": 2, - "value": "-5,0,-2" + "value": "-5,2,-2" } ] }, { "target": "camera", + "targetComponent": "Transform", "property": "position", "keyframes": [ { @@ -73,30 +112,39 @@ "world": "empty.world", "start": 5, "end": 10, - "meshes": [ - { + "entities": [ + { "name": "suzanne", - "path": "suzanne.obj", - "material": "test.material" - } - ], - "animations": [ - { - "target": "suzanne", - "property": "position", - "keyframes": [ + "components": [ { - "time": 5, - "value": "0,5,0" + "type": "Mesh", + "path": "suzanne.obj", + "material": "test.material" }, { - "time": 10, - "value": "0,5,0" + "type": "Transform", + "position": "0,5,0" } ] }, + { + "name": "camera", + "components": [ + { + "type": "Transform", + "position": "0,0,0" + }, + { + "type": "Camera", + "fov": 75 + } + ] + } + ], + "animations": [ { "target": "camera", + "targetComponent": "Transform", "property": "position", "keyframes": [ { @@ -111,6 +159,7 @@ }, { "target": "camera", + "targetComponent": "Camera", "property": "fov", "keyframes": [ { @@ -125,6 +174,7 @@ }, { "target": "camera", + "targetComponent": "Camera", "property": "target", "keyframes": [ { diff --git a/data/test.world b/data/test.world index deb5d60..b13a1c2 100644 --- a/data/test.world +++ b/data/test.world @@ -1,15 +1,35 @@ { - "meshes": [ + "entities": [ { - "position": "0,0,0", - "path": "scene.obj", - "material": "test.material" + "name": "suzanne", + "components": [ + { + "type": "Transform", + "position": "0,0,0" + }, + { + "type": "Mesh", + "path": "scene.obj", + "material": "test.material" + } + ] + }, + { + "name": "sun", + "components": [ + { + "type": "Transform", + "position": "66,56,25" + }, + { + "type": "Light", + "kind": 1, + "color": "1,1,1" + } + ] } ], - "lights": [ - { - "position": "66,56,25", - "type": 1 - } - ] + "environment": { + "color": "0.1,0.1,0.8" + } } diff --git a/include/assetmanager.h b/include/assetmanager.h index fa57a20..23d3670 100644 --- a/include/assetmanager.h +++ b/include/assetmanager.h @@ -2,8 +2,8 @@ #include -struct Mesh; -struct Material; +struct MeshAsset; +struct MaterialAsset; class Renderer; class AssetManager { @@ -12,8 +12,8 @@ public: renderer = r; } - Mesh* loadMesh(const std::string& path); - Material* loadMaterial(const std::string& path); + MeshAsset* loadMesh(const std::string& path); + MaterialAsset* loadMaterial(const std::string& path); private: Renderer* renderer = nullptr; diff --git a/include/camera.h b/include/camera.h deleted file mode 100644 index 7f1ec95..0000000 --- a/include/camera.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -class Camera { -public: - glm::vec3 position = glm::vec3(0), target = glm::vec3(0); - float fov = 75.0f; - float focusDistance = 0.0f; - float aperture = 0.0f; - float near = 0.1f, far = 100.0f; -}; diff --git a/include/cinematic.h b/include/cinematic.h index b4f19f4..bc46a07 100644 --- a/include/cinematic.h +++ b/include/cinematic.h @@ -2,8 +2,9 @@ #include #include +#include -class Mesh; +#include "ecs.h" struct Keyframe { int time = 0; @@ -18,25 +19,25 @@ enum class AnimationProperty { }; struct Animation { - Mesh* target = nullptr; - std::string targetName; + EntityID target; + std::string targetName, targetComponent; AnimationProperty property = AnimationProperty::Position; std::vector keyframes; }; -struct CinematicMesh { - std::string name, modelPath, materialPath; +struct CinematicEntity { + nlohmann::json data; }; struct Shot { int start = 0, end = 0; bool loaded = false; - + std::string world; - std::vector meshes; - std::vector loadedMeshes; + std::vector entities; + std::vector loadedEntities; std::vector animations; }; diff --git a/include/dofpass.h b/include/dofpass.h index 84051e4..62e6742 100644 --- a/include/dofpass.h +++ b/include/dofpass.h @@ -4,14 +4,14 @@ class Renderer; struct RenderTarget; -class Camera; +struct CameraComponent; class DoFPass { public: DoFPass(Renderer& renderer); ~DoFPass(); - void render(VkCommandBuffer commandBuffer, Camera& camera, RenderTarget* target); + void render(VkCommandBuffer commandBuffer, CameraComponent& camera, RenderTarget* target); void createDescriptorSet(RenderTarget* target); diff --git a/include/ecs.h b/include/ecs.h new file mode 100644 index 0000000..fb92a93 --- /dev/null +++ b/include/ecs.h @@ -0,0 +1,136 @@ +#pragma once + +#include +#include +#include +#include +#include + +struct InfoComponent { + std::string name, tag; +}; + +struct TransformComponent { + glm::vec3 position = glm::vec3(0); +}; + +struct MeshAsset; +struct MaterialAsset; + +struct MeshComponent { + MeshAsset* mesh = nullptr; + MaterialAsset* material = nullptr; +}; + +enum class LightType { + Point, + Directional +}; + +struct LightComponent { + LightType type = LightType::Point; + glm::vec3 color = glm::vec3(1); + + glm::mat4 matrix = glm::mat4(1.0f); +}; + +struct CameraComponent { + float fov = 75.0f, near = 0.1f, far = 100.0f; + float focusDistance = 0.0f; + float aperture = 0.0f; + glm::vec3 target = glm::vec3(0); +}; + +using EntityID = uint64_t; + +struct World; + +namespace ECS { + // components + inline std::map infos; + inline std::map transforms; + inline std::map meshes; + inline std::map lights; + inline std::map cameras; + + inline std::map worlds; + inline EntityID lastID = 1; + + static inline EntityID createEntity(World* world) { + EntityID newID = lastID++; + worlds[newID] = world; + + return newID; + } + + static inline void destroyEntity(const EntityID id) { + + } + + template + static inline T* addComponent(const EntityID id) { + T* t = new T(); + if constexpr(std::is_same::value) { + infos[id] = t; + } else if constexpr(std::is_same::value) { + transforms[id] = t; + } else if constexpr(std::is_same::value) { + meshes[id] = t; + } else if constexpr(std::is_same::value) { + lights[id] = t; + } else if constexpr(std::is_same::value) { + cameras[id] = t; + } + + return t; + } + + template + static inline T* getComponent(const EntityID id) { + if constexpr(std::is_same::value) { + return infos[id]; + } else if constexpr(std::is_same::value) { + return transforms[id]; + } else if constexpr(std::is_same::value) { + return meshes[id]; + } else if constexpr(std::is_same::value) { + return lights[id]; + } else if constexpr(std::is_same::value) { + return cameras[id]; + } + } + + template + static inline auto getWorldComponents(World* world) { + std::vector entities; + for (auto it = worlds.begin(); it != worlds.end(); ++it) { + if(it->second == world) { + entities.push_back(it->first); + } + } + + std::vector> components; + for(auto ent : entities) { + T* t = getComponent(ent); + if(t != nullptr) + components.push_back(std::tuple(ent, t)); + } + + return components; + } + + static inline std::vector getWorldEntities(World* world) { + std::vector entities; + for (auto it = worlds.begin(); it != worlds.end(); ++it) { + if(it->second == world) + entities.push_back(it->first); + } + + return entities; + } + + template + static inline void removeComponent(const EntityID id) { + delete transforms[id]; + } +}; diff --git a/include/entityparser.h b/include/entityparser.h new file mode 100644 index 0000000..d24ae9d --- /dev/null +++ b/include/entityparser.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +#include "ecs.h" + +struct World; + +EntityID parseEntity(const nlohmann::json& json, World* world); diff --git a/include/light.h b/include/light.h deleted file mode 100644 index 1da39c0..0000000 --- a/include/light.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -enum class LightType { - Point, - Directional -}; - -class Light { -public: - LightType type = LightType::Point; - glm::vec3 position = glm::vec3(0); - glm::vec3 color = glm::vec3(1); - - glm::mat4 matrix = glm::mat4(1.0f); -}; diff --git a/include/material.h b/include/material.h index 9d406eb..6a40c3f 100644 --- a/include/material.h +++ b/include/material.h @@ -3,8 +3,7 @@ #include #include -class Material { -public: +struct MaterialAsset { std::string albedoTexturePath; VkImage albedoImage = nullptr; diff --git a/include/mesh.h b/include/mesh.h index b864a09..1e30fe9 100644 --- a/include/mesh.h +++ b/include/mesh.h @@ -6,20 +6,12 @@ #include #include -class Material; - struct Vertex { glm::vec3 position, normal; glm::vec2 uv; }; -class Mesh { -public: - std::string name, tag; - glm::vec3 position; - - Material* material = nullptr; - +struct MeshAsset { std::vector vertices; std::vector indices; diff --git a/include/rendercollection.h b/include/rendercollection.h new file mode 100644 index 0000000..a664e59 --- /dev/null +++ b/include/rendercollection.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +struct TransformComponent; +struct MeshComponent; +struct LightComponent; +struct CameraComponent; + +struct RenderLight { + TransformComponent* transform = nullptr; + LightComponent* light = nullptr; +}; + +struct RenderMesh { + TransformComponent* transform = nullptr; + MeshComponent* mesh = nullptr; +}; + +struct RenderCamera { + TransformComponent* transform = nullptr; + CameraComponent* camera = nullptr; +}; + +struct RenderCollection { + std::vector lights; + std::vector meshes; + + RenderCamera camera; +}; diff --git a/include/renderer.h b/include/renderer.h index 3134a3a..aedc454 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -74,16 +74,16 @@ struct GraphicsConfig { }; class World; -class Mesh; +class MeshAsset; class Camera; -class Material; +class MaterialAsset; class Renderer { public: Renderer(GraphicsConfig config); ~Renderer(); - void render(World& world, Camera& camera, RenderTarget* target); + void render(World& world, RenderTarget* target); RenderTarget* createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTarget* oldTarget = nullptr); void destroyRenderTarget(RenderTarget* target); @@ -96,11 +96,11 @@ public: uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); - void fillMeshBuffers(Mesh* mesh); - void destroyMeshBuffers(Mesh* mesh); + void fillMeshBuffers(MeshAsset* mesh); + void destroyMeshBuffers(MeshAsset* mesh); - void fillMaterialBuffers(Material* material); - void destroyMaterialBuffers(Material* material); + void fillMaterialBuffers(MaterialAsset* material); + void destroyMaterialBuffers(MaterialAsset* material); GraphicsConfig getConfig() const { return config_; diff --git a/include/shadowpass.h b/include/shadowpass.h index 870bbb9..ebe6d8d 100644 --- a/include/shadowpass.h +++ b/include/shadowpass.h @@ -4,13 +4,14 @@ class Renderer; class World; +struct RenderCollection; class ShadowPass { public: ShadowPass(Renderer& renderer); ~ShadowPass(); - void render(VkCommandBuffer commandBuffer, World& world); + void render(VkCommandBuffer commandBuffer, RenderCollection& collection); VkImageView getImageView() const { return shadowImageView_; diff --git a/include/skypass.h b/include/skypass.h index fa353a2..3c9eb36 100644 --- a/include/skypass.h +++ b/include/skypass.h @@ -1,6 +1,7 @@ #pragma once #include +#include class Renderer; @@ -9,7 +10,7 @@ public: SkyPass(Renderer& renderer); ~SkyPass(); - void render(VkCommandBuffer commandBuffer); + void render(glm::vec3 color, VkCommandBuffer commandBuffer); private: void createPipeline(); diff --git a/include/world.h b/include/world.h index ccbe316..c1c0a89 100644 --- a/include/world.h +++ b/include/world.h @@ -1,16 +1,7 @@ #pragma once -#include +#include -#include "camera.h" - -class Mesh; -class Light; - -class World { -public: - std::vector meshes; - std::vector lights; - - Camera camera; +struct World { + glm::vec3 color; }; diff --git a/include/worldmanager.h b/include/worldmanager.h index 47c3112..8407c90 100644 --- a/include/worldmanager.h +++ b/include/worldmanager.h @@ -15,6 +15,10 @@ public: return currentWorld; } + World* getWorld(const std::string& path) { + return loadedWorlds[path]; + } + private: std::map loadedWorlds; World* currentWorld = nullptr; diff --git a/include/worldpass.h b/include/worldpass.h index d7ee281..6ac2f5f 100644 --- a/include/worldpass.h +++ b/include/worldpass.h @@ -2,6 +2,8 @@ #include +#include "rendercollection.h" + class Renderer; class World; struct RenderTarget; @@ -12,7 +14,7 @@ public: WorldPass(Renderer& renderer); ~WorldPass(); - void render(VkCommandBuffer commandBuffer, World& world, Camera& camera, RenderTarget* target); + void render(VkCommandBuffer commandBuffer, RenderCollection& collection, RenderTarget* target); VkRenderPass getRenderPass() const { return renderPass_; @@ -22,7 +24,7 @@ private: void createRenderPass(); void createDescriptorSetLayout(); void createPipeline(); - void createUniformBuffer(); + void createUniformBuffers(); void createDescriptorSet(); VkRenderPass renderPass_ = nullptr; @@ -31,6 +33,9 @@ private: VkPipelineLayout pipelineLayout_ = nullptr; VkPipeline pipeline_ = nullptr; + + VkDeviceMemory sceneMemory_ = nullptr; + VkBuffer sceneBuffer_ = nullptr; VkDeviceMemory lightMemory_ = nullptr; VkBuffer lightBuffer_ = nullptr; diff --git a/shaders/mesh.frag b/shaders/mesh.frag index 29d914f..0efe766 100644 --- a/shaders/mesh.frag +++ b/shaders/mesh.frag @@ -8,15 +8,14 @@ layout(location = 3) in vec2 inUV; layout(location = 0) out vec4 outColor; struct Light { - vec4 position; - vec3 color; + vec4 position, color; }; -layout(set = 0, binding = 0) uniform Lights { +layout(set = 0, binding = 1) uniform Lights { Light lights[32]; }; -layout(set = 0, binding = 1) uniform sampler2D shadowSampler; +layout(set = 0, binding = 2) uniform sampler2D shadowSampler; layout(set = 1, binding = 0) uniform sampler2D albedoSampler; layout(constant_id = 0) const int shadowFilterPCF = 1; @@ -54,7 +53,7 @@ float filterPCF(vec4 sc) { } void main() { - vec3 diffuse = vec3(0); + vec3 diffuse = vec3(0.0); for(int i = 0; i < 32; i++) { vec3 lightDir = vec3(0); if(lights[i].position.w == 0) @@ -68,7 +67,20 @@ void main() { const float diff = max(dot(norm, lightDir), 0.0); const float shadow = shadowFilterPCF == 1 ? filterPCF(inShadowPos / inShadowPos.w) : textureProj(inShadowPos / inShadowPos.w, vec2(0, 0)); - diffuse += vec3(diff) * lights[i].color * shadow; + + vec3 add = vec3(diff) * lights[i].color.rgb * shadow; + + if(lights[i].position.w == 1) { + const float radius = 15.0; + const float dist = distance(inFragPos, lights[i].position.xyz); + + float att = clamp(1.0 - dist / radius, 0.0, 1.0); + att *= att; + + add *= att; + } + + diffuse += add; } outColor = vec4(vec3(0.1) + diffuse * texture(albedoSampler, inUV).rgb, 1.0); diff --git a/shaders/mesh.vert b/shaders/mesh.vert index 62da307..7c72059 100644 --- a/shaders/mesh.vert +++ b/shaders/mesh.vert @@ -9,8 +9,12 @@ layout(location = 1) out vec4 outShadowPos; layout(location = 2) out vec3 outNormal; layout(location = 3) out vec2 outUV; -layout(push_constant) uniform PushConstants { +layout(set = 0, binding = 0) uniform SceneInfo { mat4 vp, lightSpace; +} sceneInfo; + +layout(push_constant) uniform PushConstants { + mat4 m; } pushConstants; const mat4 biasMat = mat4( @@ -20,9 +24,9 @@ const mat4 biasMat = mat4( 0.5, 0.5, 0.0, 1.0); void main() { - gl_Position = pushConstants.vp * vec4(inPosition, 1.0); - outFragPos = inPosition; - outShadowPos = (biasMat * pushConstants.lightSpace) * vec4(inPosition, 1.0); - outNormal = inNormal; + gl_Position = sceneInfo.vp * pushConstants.m * vec4(inPosition, 1.0); + outFragPos = vec3(pushConstants.m * vec4(inPosition, 1.0)); + outShadowPos = (biasMat * sceneInfo.lightSpace) * vec4(inPosition, 1.0); + outNormal = mat3(transpose(inverse(pushConstants.m))) * inNormal; outUV = inUV; } diff --git a/shaders/sky.frag b/shaders/sky.frag index eace1ef..38a5ec5 100644 --- a/shaders/sky.frag +++ b/shaders/sky.frag @@ -4,7 +4,11 @@ layout(location = 0) in vec2 inUV; layout(location = 0) out vec4 outColor; +layout(push_constant) uniform PushConstants { + vec3 color; +} pushConstants; + void main() { - outColor = vec4(0.1, 0.1, 0.8, 1.0); + outColor = vec4(pushConstants.color, 1.0); } diff --git a/src/animationsystem.cpp b/src/animationsystem.cpp index b31ebba..d057391 100644 --- a/src/animationsystem.cpp +++ b/src/animationsystem.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include "mesh.h" @@ -10,35 +9,35 @@ #include "worldmanager.h" #include "world.h" #include "assetmanager.h" +#include "entityparser.h" Cinematic* AnimationSystem::loadCinematic(const std::string& path) { std::ifstream file("data/" + path); if(!file) return nullptr; - + nlohmann::json json; file >> json; - + auto cinematic = new Cinematic(); for(auto shotObject : json["shots"]) { Shot* shot = new Shot(); shot->start = shotObject["start"]; shot->end = shotObject["end"]; shot->world = shotObject["world"]; - - for(auto meshObject : shotObject["meshes"]) { - CinematicMesh mesh; - mesh.name = meshObject["name"]; - mesh.modelPath = meshObject["path"]; - mesh.materialPath = meshObject["material"]; - - shot->meshes.push_back(mesh); + + for(auto entityObject : shotObject["entities"]) { + CinematicEntity entity; + entity.data = entityObject; + + shot->entities.push_back(entity); } - + for(auto animationObject : shotObject["animations"]) { auto animation = new Animation(); animation->targetName = animationObject["target"]; - + animation->targetComponent = animationObject["targetComponent"]; + const auto property = animationObject["property"]; if(property == "position") animation->property = AnimationProperty::Position; @@ -46,35 +45,35 @@ Cinematic* AnimationSystem::loadCinematic(const std::string& path) { animation->property = AnimationProperty::Target; else if(property == "fov") animation->property = AnimationProperty::FoV; - + for(auto keyframeObject : animationObject["keyframes"]) { Keyframe keyframe; keyframe.time = keyframeObject["time"]; - + if(animation->property == AnimationProperty::Position || animation->property == AnimationProperty::Target) { auto tokens = tokenize(keyframeObject["value"]); - + keyframe.valueVec3[0] = atof(tokens[0].c_str()); keyframe.valueVec3[1] = atof(tokens[1].c_str()); keyframe.valueVec3[2] = atof(tokens[2].c_str()); - + animation->keyframes.push_back(keyframe); } else if(animation->property == AnimationProperty::FoV) { keyframe.valueInt = keyframeObject["value"]; - + animation->keyframes.push_back(keyframe); } } - + shot->animations.push_back(animation); } - + cinematic->shots.push_back(shot); } - + preloadShot(cinematic->shots[0]); loadShot(cinematic->shots[0]); - + return cinematic; } @@ -86,7 +85,7 @@ void AnimationSystem::update(Cinematic* cinematic, float deltaTime) { preloadShot(cinematic->shots[currentShot + 1]); cinematic->shots[currentShot + 1]->loaded = true; } - + if(i > currentShot && animationTime > cinematic->shots[i]->start) { unloadShot(cinematic->shots[currentShot]); currentShot = i; @@ -102,89 +101,71 @@ void AnimationSystem::update(Cinematic* cinematic, float deltaTime) { break; } } - + const auto currentFrame = animation->keyframes[frameIndex]; const auto nextFrame = animation->keyframes[(frameIndex + 1) % animation->keyframes.size()]; - + const float delta = (animationTime - currentFrame.time) / (nextFrame.time - currentFrame.time); - + switch(animation->property) { case AnimationProperty::Position: { auto pos = currentFrame.valueVec3 + delta * (nextFrame.valueVec3 - currentFrame.valueVec3); - - if(animation->target == nullptr) - worldManager.getCurrentWorld()->camera.position = pos; - else { - animation->target->position = pos; + + if(animation->targetComponent == "Transform") { + TransformComponent* transform = ECS::getComponent(animation->target); + transform->position = pos; } } break; case AnimationProperty::Target: { auto pos = currentFrame.valueVec3 + delta * (nextFrame.valueVec3 - currentFrame.valueVec3); - - worldManager.getCurrentWorld()->camera.target = pos; + + if(animation->targetComponent == "Camera") { + CameraComponent* camera = ECS::getComponent(animation->target); + camera->target = pos; + } } break; case AnimationProperty::FoV: { auto pos = currentFrame.valueInt + delta * (nextFrame.valueInt - currentFrame.valueInt); - worldManager.getCurrentWorld()->camera.fov = pos; + + if(animation->targetComponent == "Camera") { + CameraComponent* camera = ECS::getComponent(animation->target); + camera->fov = pos; + } } break; } } - + animationTime += deltaTime; } void AnimationSystem::preloadShot(Shot* shot) { - std::cout << "preloading shot..." << std::endl; - worldManager.loadWorld(shot->world); - - for(auto cimMesh : shot->meshes) { - Mesh* mesh = assetManager.loadMesh(cimMesh.modelPath); - mesh->name = cimMesh.name; - mesh->material = assetManager.loadMaterial(cimMesh.materialPath); - mesh->tag = "cinematic"; - + + for(auto cimEntity : shot->entities) { + EntityID entity = parseEntity(cimEntity.data, worldManager.getWorld(shot->world)); + for(auto animation : shot->animations) { - if(animation->targetName == mesh->name) - animation->target = mesh; + if(animation->targetName == ECS::getComponent(entity)->name) + animation->target = entity; } - - shot->loadedMeshes.push_back(mesh); + + shot->loadedEntities.push_back(entity); } } void AnimationSystem::loadShot(Shot* shot) { - std::cout << "loading shot..." << std::endl; - worldManager.switchWorld(shot->world); - - for(auto mesh : shot->loadedMeshes) - worldManager.getCurrentWorld()->meshes.push_back(mesh); } void AnimationSystem::unloadShot(Shot* shot) { - std::cout << "unloading shot..." << std::endl; - World* world = worldManager.getCurrentWorld(); - - for(auto mesh : world->meshes) { - if(mesh->tag == "cinematic") { - //renderer->destroyMaterialBuffers(mesh->material); - delete mesh->material; - - //renderer->destroyMeshBuffers(mesh); - delete mesh; - } - } - - world->meshes.erase(std::remove_if(world->meshes.begin(), - world->meshes.end(), - [](Mesh* m){return m->tag == "cinematic";}), - world->meshes.end()); + + for(auto entity : shot->loadedEntities) + ECS::destroyEntity(entity); } diff --git a/src/assetmanager.cpp b/src/assetmanager.cpp index 293ecb7..e0b45a0 100644 --- a/src/assetmanager.cpp +++ b/src/assetmanager.cpp @@ -11,51 +11,55 @@ #include "material.h" #include "renderer.h" -Mesh* AssetManager::loadMesh(const std::string& path) { +MeshAsset* AssetManager::loadMesh(const std::string& path) { std::string fixedPath = "data/" + path; - + Assimp::Importer importer; const aiScene* scene = importer.ReadFile(fixedPath.c_str(), aiProcess_Triangulate); - - Mesh* mesh = new Mesh(); - + if(scene == nullptr) + return nullptr; + + MeshAsset* mesh = new MeshAsset(); + unsigned int indexOffset = 0; for(unsigned mi = 0; mi < scene->mNumMeshes; mi++) { aiMesh* m = scene->mMeshes[mi]; - + for(unsigned int i = 0; i < m->mNumVertices; i++) { Vertex vertex; vertex.position = glm::vec3(m->mVertices[i].x, m->mVertices[i].y, m->mVertices[i].z); vertex.normal = glm::vec3(m->mNormals[i].x, m->mNormals[i].y, m->mNormals[i].z); vertex.uv = glm::vec2(m->mTextureCoords[0][i].x, m->mTextureCoords[0][i].y); - + mesh->vertices.push_back(vertex); } - + for(unsigned int i = 0; i < m->mNumFaces; i++) { aiFace face = m->mFaces[i]; for(unsigned int j = 0; j < face.mNumIndices; j++) mesh->indices.push_back(indexOffset + face.mIndices[j]); } - + indexOffset += m->mNumVertices; } - + renderer->fillMeshBuffers(mesh); - + return mesh; } -Material* AssetManager::loadMaterial(const std::string& path) { +MaterialAsset* AssetManager::loadMaterial(const std::string& path) { std::ifstream file("data/" + path); - + if(!file) + return nullptr; + nlohmann::json json; file >> json; - - Material* material = new Material(); + + MaterialAsset* material = new MaterialAsset(); material->albedoTexturePath = "data/" + json["albedoTexture"].get(); - + renderer->fillMaterialBuffers(material); - + return material; } diff --git a/src/dofpass.cpp b/src/dofpass.cpp index 6016a1f..f3b1624 100644 --- a/src/dofpass.cpp +++ b/src/dofpass.cpp @@ -5,7 +5,8 @@ #include #include "renderer.h" -#include "camera.h" +#include "rendercollection.h" +#include "ecs.h" DoFPass::DoFPass(Renderer& renderer) : renderer_(renderer) { createRenderPass(); @@ -28,7 +29,7 @@ DoFPass::~DoFPass() { vkDestroyRenderPass(renderer_.getDevice(), renderPass_, nullptr); } -void DoFPass::render(VkCommandBuffer commandBuffer, Camera& camera, RenderTarget* target) { +void DoFPass::render(VkCommandBuffer commandBuffer, CameraComponent& camera, RenderTarget* target) { VkViewport viewport = {}; viewport.width = target->extent.width / renderer_.getConfig().dofDownscale; viewport.height = target->extent.height / renderer_.getConfig().dofDownscale; diff --git a/src/entityparser.cpp b/src/entityparser.cpp new file mode 100644 index 0000000..4386518 --- /dev/null +++ b/src/entityparser.cpp @@ -0,0 +1,44 @@ +#include "entityparser.h" + +#include "assetmanager.h" +#include "stringutils.h" + +EntityID parseEntity(const nlohmann::json& json, World* world) { + EntityID entity = ECS::createEntity(world); + + InfoComponent* info = ECS::addComponent(entity); + info->name = json["name"]; + + for(auto componentObject : json["components"]) { + const auto& componentType = componentObject["type"]; + + if(componentType == "Transform") { + TransformComponent* transform = ECS::addComponent(entity); + + auto tokens = tokenize(componentObject["position"]); + + transform->position[0] = atof(tokens[0].c_str()); + transform->position[1] = atof(tokens[1].c_str()); + transform->position[2] = atof(tokens[2].c_str()); + } else if(componentType == "Mesh") { + MeshComponent* mesh = ECS::addComponent(entity); + + mesh->mesh = assetManager.loadMesh(componentObject["path"]); + mesh->material = assetManager.loadMaterial(componentObject["material"]); + } else if(componentType == "Light") { + LightComponent* light = ECS::addComponent(entity); + + auto tokens = tokenize(componentObject["color"]); + + light->color[0] = atof(tokens[0].c_str()); + light->color[1] = atof(tokens[1].c_str()); + light->color[2] = atof(tokens[2].c_str()); + + light->type = componentObject["kind"]; + } else if(componentType == "Camera") { + CameraComponent* camera = ECS::addComponent(entity); + } + } + + return entity; +} diff --git a/src/main.cpp b/src/main.cpp index 88bf250..2ab6f22 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,8 +14,6 @@ #include "platform.h" #include "world.h" #include "mesh.h" -#include "light.h" -#include "camera.h" #include "animationsystem.h" #include "material.h" #include "config.h" @@ -110,7 +108,7 @@ int main(int argc, char* argv[]) { bool cinematicMode = false; if(argc > 2 && strcmp(argv[1], "--cinematic") == 0) cinematicMode = true; - + bool record = false; if(argc > 3 && strcmp(argv[2], "--record") == 0) record = true; @@ -135,16 +133,16 @@ int main(int argc, char* argv[]) { ImGui::StyleColorsDark(); #endif - + renderer = new Renderer(graphicsConfig); VkSurfaceKHR surface = nullptr; SDL_Vulkan_CreateSurface(window, renderer->getInstance(), &surface); RenderTarget* target = renderer->createSurfaceRenderTarget(surface); - + assetManager.setRenderer(renderer); - + AnimationSystem* animationSystem = new AnimationSystem(); if(cinematicMode) @@ -152,8 +150,15 @@ int main(int argc, char* argv[]) { else { worldManager.loadWorld("test.world"); worldManager.switchWorld("test.world"); + + EntityID entity = ECS::createEntity(worldManager.getCurrentWorld()); + + TransformComponent* transform = ECS::addComponent(entity); + transform->position = glm::vec3(5, 5, 5); + + ECS::addComponent(entity); } - + float currentTime = 0.0f, lastTime = 0.0f; bool running = true; @@ -168,7 +173,7 @@ int main(int argc, char* argv[]) { #ifdef DEBUG io.DisplaySize = ImVec2(event.window.data1, event.window.data2); #endif - + target = renderer->createSurfaceRenderTarget(surface, target); } } @@ -196,7 +201,7 @@ int main(int argc, char* argv[]) { if(cinematicMode) animationSystem->update(cinematic, deltaTime); - + #ifdef DEBUG ImGui::NewFrame(); @@ -211,40 +216,19 @@ int main(int argc, char* argv[]) { if(SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS) io.MousePos = ImVec2(static_cast(mouseX), static_cast(mouseY)); - ImGui::DragFloat3("Light Position", &worldManager.getCurrentWorld()->lights[0]->position[0]); - ImGui::DragFloat3("Camera Position", &worldManager.getCurrentWorld()->camera.position[0], 0.1f); - ImGui::DragFloat3("Target", &worldManager.getCurrentWorld()->camera.target[0], 0.1f); - ImGui::DragFloat("Aperture", &worldManager.getCurrentWorld()->camera.aperture, 0.01f, 0.0f, 1.0f); - ImGui::DragFloat("Focus Distance", &worldManager.getCurrentWorld()->camera.focusDistance); - ImGui::Text("dpack[2] = %f", (100 - worldManager.getCurrentWorld()->camera.focusDistance) / 100.0f); - ImGui::Render(); #endif - renderer->render(*worldManager.getCurrentWorld(), worldManager.getCurrentWorld()->camera, target); + renderer->render(*worldManager.getCurrentWorld(), target); if(record) { static int frameNum = 0; std::string screenshotName = "frame" + std::to_string(frameNum) + ".ppm"; frameNum++; - + renderer->takeScreenshot(screenshotName.c_str(), target); } } - - /*for(auto mesh : world->meshes) { - renderer->destroyMaterialBuffers(mesh->material); - delete mesh->material; - - renderer->destroyMeshBuffers(mesh); - delete mesh; - } - - for(auto light : world->lights) { - delete light; - } - - delete world;*/ renderer->destroyRenderTarget(target); diff --git a/src/renderer.cpp b/src/renderer.cpp index 6e07f1a..a4b925a 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -11,8 +11,10 @@ #include "platform.h" #include "mesh.h" -#include "camera.h" #include "material.h" +#include "rendercollection.h" +#include "ecs.h" +#include "world.h" Renderer::Renderer(GraphicsConfig config) : config_(config) { createInstance(); @@ -65,7 +67,37 @@ Renderer::~Renderer() { vkDestroyInstance(instance_, nullptr); } -void Renderer::render(World& world, Camera& camera, RenderTarget* target) { +void Renderer::render(World& world, RenderTarget* target) { + RenderCollection collection; + + // generate collection + { + auto meshes = ECS::getWorldComponents(&world); + for(auto [id, mesh] : meshes) { + RenderMesh renderMesh; + renderMesh.mesh = mesh; + renderMesh.transform = ECS::getComponent(id); + + collection.meshes.push_back(renderMesh); + } + + auto lights = ECS::getWorldComponents(&world); + for(auto [id, light] : lights) { + RenderLight renderLight; + renderLight.light = light; + renderLight.transform = ECS::getComponent(id); + + collection.lights.push_back(renderLight); + } + + auto cameras = ECS::getWorldComponents(&world); + + auto [id, camera] = cameras[0]; + + collection.camera.camera = camera; + collection.camera.transform = ECS::getComponent(id); + } + vkAcquireNextImageKHR(device_, target->swapchain, UINT64_MAX, target->imageAvailableSemaphore, nullptr, &target->imageIndex); target->currentResource = (target->imageIndex + 1) % numFrameResources; @@ -80,7 +112,7 @@ void Renderer::render(World& world, Camera& camera, RenderTarget* target) { vkBeginCommandBuffer(commandBuffer, &beginInfo); - shadowPass_->render(commandBuffer, world); + shadowPass_->render(commandBuffer, collection); VkViewport viewport = {}; viewport.width = target->extent.width; @@ -107,12 +139,12 @@ void Renderer::render(World& world, Camera& camera, RenderTarget* target) { vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - worldPass_->render(commandBuffer, world, camera, target); - skyPass_->render(commandBuffer); + worldPass_->render(commandBuffer, collection, target); + skyPass_->render(world.color, commandBuffer); vkCmdEndRenderPass(commandBuffer); - dofPass_->render(commandBuffer, camera, target); + dofPass_->render(commandBuffer, *collection.camera.camera, target); // reset after dof pass vkCmdSetViewport(commandBuffer, 0, 1, &viewport); @@ -994,7 +1026,7 @@ uint32_t Renderer::findMemoryType(const uint32_t typeFilter, const VkMemoryPrope return 0; } -void Renderer::fillMeshBuffers(Mesh* mesh) { +void Renderer::fillMeshBuffers(MeshAsset* mesh) { // vertex { VkBufferCreateInfo bufferInfo = {}; @@ -1050,7 +1082,7 @@ void Renderer::fillMeshBuffers(Mesh* mesh) { } } -void Renderer::fillMaterialBuffers(Material* material) { +void Renderer::fillMaterialBuffers(MaterialAsset* material) { int width = 0, height = 0, channels = 0; stbi_uc* pixels = stbi_load(material->albedoTexturePath.c_str(), &width, &height, &channels, STBI_rgb_alpha); if(pixels == nullptr) @@ -1139,7 +1171,7 @@ void Renderer::fillMaterialBuffers(Material* material) { vkUpdateDescriptorSets(device_, 1, &albedoDescriptorWrite, 0, nullptr); } -void Renderer::destroyMaterialBuffers(Material* material) { +void Renderer::destroyMaterialBuffers(MaterialAsset* material) { vkDeviceWaitIdle(device_); vkFreeDescriptorSets(device_, descriptorPool_, 1, &material->set); @@ -1150,7 +1182,7 @@ void Renderer::destroyMaterialBuffers(Material* material) { vkDestroyImage(device_, material->albedoImage, nullptr); } -void Renderer::destroyMeshBuffers(Mesh* mesh) { +void Renderer::destroyMeshBuffers(MeshAsset* mesh) { vkDeviceWaitIdle(device_); vkFreeMemory(device_, mesh->indexMemory, nullptr); @@ -1173,7 +1205,7 @@ void Renderer::createInstance() { if(strcmp(availableLayers[i].layerName, "VK_LAYER_LUNARG_standard_validation") == 0) enabledLayers.push_back("VK_LAYER_LUNARG_standard_validation"); } - + delete[] availableLayers; #endif diff --git a/src/shadowpass.cpp b/src/shadowpass.cpp index c0e53a6..0c2da97 100644 --- a/src/shadowpass.cpp +++ b/src/shadowpass.cpp @@ -7,7 +7,9 @@ #include "renderer.h" #include "world.h" #include "mesh.h" -#include "light.h" +#include "rendercollection.h" +#include "ecs.h" +#include "mesh.h" ShadowPass::ShadowPass(Renderer& renderer) : renderer_(renderer) { createRenderPass(); @@ -28,20 +30,20 @@ ShadowPass::~ShadowPass() { vkDestroyRenderPass(renderer_.getDevice(), renderPass_, nullptr); } -void ShadowPass::render(VkCommandBuffer commandBuffer, World& world) { +void ShadowPass::render(VkCommandBuffer commandBuffer, RenderCollection& collection) { VkViewport viewport = {}; viewport.width = renderer_.getConfig().shadowResolution; viewport.height = renderer_.getConfig().shadowResolution; viewport.maxDepth = 1.0f; - + vkCmdSetViewport(commandBuffer, 0, 1, &viewport); - + VkRect2D scissor = {}; scissor.extent.width = renderer_.getConfig().shadowResolution; scissor.extent.height = renderer_.getConfig().shadowResolution; - + vkCmdSetScissor(commandBuffer, 0, 1, &scissor); - + VkClearValue clearColor = {}; clearColor.depthStencil.depth = 1.0f; @@ -59,23 +61,22 @@ void ShadowPass::render(VkCommandBuffer commandBuffer, World& world) { vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); glm::mat4 lightSpace = glm::mat4(1.0f); - //lightSpace = glm::perspective(glm::radians(75.0f), 1.0f, 0.1f, 100.0f); lightSpace = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 0.1f, 100.0f); - lightSpace *= glm::lookAt(world.lights[0]->position, glm::vec3(0), glm::vec3(0, -1, 0)); + lightSpace *= glm::lookAt(collection.lights[0].transform->position, glm::vec3(0), glm::vec3(0, -1, 0)); - world.lights[0]->matrix = lightSpace; + collection.lights[0].light->matrix = lightSpace; - for(const auto& mesh : world.meshes) { - glm::mat4 mvp = world.lights[0]->matrix; - mvp = glm::translate(mvp, mesh->position); + for(const auto& mesh : collection.meshes) { + glm::mat4 mvp = collection.lights[0].light->matrix; + mvp = glm::translate(mvp, mesh.transform->position); vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &mvp); VkDeviceSize offsets[] = {0}; - vkCmdBindVertexBuffers(commandBuffer, 0, 1, &mesh->vertexBuffer, offsets); - vkCmdBindIndexBuffer(commandBuffer, mesh->indexBuffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &mesh.mesh->mesh->vertexBuffer, offsets); + vkCmdBindIndexBuffer(commandBuffer, mesh.mesh->mesh->indexBuffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(commandBuffer, mesh->indices.size(), 1, 0, 0, 0); + vkCmdDrawIndexed(commandBuffer, mesh.mesh->mesh->indices.size(), 1, 0, 0, 0); } vkCmdEndRenderPass(commandBuffer); diff --git a/src/skypass.cpp b/src/skypass.cpp index 1b79677..5a47c52 100644 --- a/src/skypass.cpp +++ b/src/skypass.cpp @@ -13,8 +13,11 @@ SkyPass::~SkyPass() { vkDestroyPipelineLayout(renderer_.getDevice(), pipelineLayout_, nullptr); } -void SkyPass::render(VkCommandBuffer commandBuffer) { +void SkyPass::render(glm::vec3 color, VkCommandBuffer commandBuffer) { vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); + + vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(glm::vec3), &color); + vkCmdDraw(commandBuffer, 3, 1, 0, 0); } @@ -83,8 +86,14 @@ void SkyPass::createPipeline() { dynamicState.dynamicStateCount = dynamicStates.size(); dynamicState.pDynamicStates = dynamicStates.data(); + VkPushConstantRange pushConstant = {}; + pushConstant.size = sizeof(glm::vec3); + pushConstant.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pPushConstantRanges = &pushConstant; vkCreatePipelineLayout(renderer_.getDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout_); diff --git a/src/worldmanager.cpp b/src/worldmanager.cpp index dddba09..aa80445 100644 --- a/src/worldmanager.cpp +++ b/src/worldmanager.cpp @@ -9,43 +9,28 @@ #include "world.h" #include "assetmanager.h" #include "mesh.h" -#include "light.h" +#include "entityparser.h" +#include "ecs.h" void WorldManager::loadWorld(const std::string& path) { std::ifstream file("data/" + path); if(!file) - std::cout << "failed to load " << path << std::endl; - + return; + nlohmann::json json; file >> json; - + World* world = new World(); - - for(auto meshObject : json["meshes"]) { - Mesh* mesh = assetManager.loadMesh(meshObject["path"]); - mesh->material = assetManager.loadMaterial(meshObject["material"]); - - auto tokens = tokenize(meshObject["position"]); - - mesh->position[0] = atof(tokens[0].c_str()); - mesh->position[1] = atof(tokens[1].c_str()); - mesh->position[2] = atof(tokens[2].c_str()); - - world->meshes.push_back(mesh); - } - - for(auto lightObject : json["lights"]) { - Light* light = new Light(); - - auto tokens = tokenize(lightObject["position"]); - - light->position[0] = atof(tokens[0].c_str()); - light->position[1] = atof(tokens[1].c_str()); - light->position[2] = atof(tokens[2].c_str()); - - world->lights.push_back(light); - } - + + auto tokens = tokenize(json["environment"]["color"]); + + world->color[0] = atof(tokens[0].c_str()); + world->color[1] = atof(tokens[1].c_str()); + world->color[2] = atof(tokens[2].c_str()); + + for(auto entityObject : json["entities"]) + EntityID entity = parseEntity(entityObject, world); + loadedWorlds[path] = world; } diff --git a/src/worldpass.cpp b/src/worldpass.cpp index d404876..46e4459 100644 --- a/src/worldpass.cpp +++ b/src/worldpass.cpp @@ -1,20 +1,20 @@ #include "worldpass.h" +#include #include #include #include "renderer.h" #include "world.h" #include "mesh.h" -#include "light.h" -#include "camera.h" #include "material.h" +#include "ecs.h" WorldPass::WorldPass(Renderer& renderer) : renderer_(renderer) { createRenderPass(); createDescriptorSetLayout(); createPipeline(); - createUniformBuffer(); + createUniformBuffers(); createDescriptorSet(); } @@ -30,24 +30,40 @@ WorldPass::~WorldPass() { vkDestroyBuffer(renderer_.getDevice(), lightBuffer_, nullptr); } -void WorldPass::render(VkCommandBuffer commandBuffer, World& world, Camera& camera, RenderTarget* target) { +void WorldPass::render(VkCommandBuffer commandBuffer, RenderCollection& collection, RenderTarget* target) { + glm::mat4* sceneData; + vkMapMemory(renderer_.getDevice(), sceneMemory_, 0, sizeof(glm::mat4) * 2, 0, reinterpret_cast(&sceneData)); + + glm::mat4 vp; + vp = glm::perspective(glm::radians(collection.camera.camera->fov), (float)target->extent.width / target->extent.height, collection.camera.camera->near, collection.camera.camera->far); + vp *= glm::lookAt(collection.camera.transform->position, collection.camera.camera->target, glm::vec3(0, -1, 0)); + + memcpy(sceneData, &vp, sizeof(glm::mat4)); + + sceneData++; + + memcpy(sceneData, &collection.lights[0].light->matrix, sizeof(glm::mat4)); + + vkUnmapMemory(renderer_.getDevice(), sceneMemory_); + struct ShaderLight { - glm::vec4 position; - glm::vec3 color; + glm::vec4 position, color; }; ShaderLight* data; - vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 3) * 32, 0, reinterpret_cast(&data)); + vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (8) * 32, 0, reinterpret_cast(&data)); - for(const auto& light : world.lights) { + memset(data, 0, sizeof(float) * (8) * 32); + + for(const auto& light : collection.lights) { glm::vec3 position; - if(light->type == LightType::Point) - position = light->position; + if(light.light->type == LightType::Point) + position = light.transform->position; else - position = glm::normalize(glm::vec3(0) - light->position); + position = glm::normalize(glm::vec3(0) - light.transform->position); - data->position = glm::vec4(position, ((int)light->type) + 1); - data->color = light->color; + data->position = glm::vec4(position, ((int)light.light->type) + 1); + data->color = glm::vec4(light.light->color, 0.0); data++; } @@ -57,23 +73,19 @@ void WorldPass::render(VkCommandBuffer commandBuffer, World& world, Camera& came vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descriptorSet_, 0, nullptr); - for(const auto& mesh : world.meshes) { - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 1, 1, &mesh->material->set, 0, nullptr); + for(const auto& mesh : collection.meshes) { + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 1, 1, &mesh.mesh->material->set, 0, nullptr); - glm::mat4 vp; - vp = glm::perspective(glm::radians(camera.fov), (float)target->extent.width / target->extent.height, camera.near, camera.far); - vp *= glm::lookAt(camera.position, camera.target, glm::vec3(0, -1, 0)); - vp = glm::translate(vp, mesh->position); - - vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &vp); + glm::mat4 m(1.0f); + m = glm::translate(m, mesh.transform->position); - vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::mat4), sizeof(glm::mat4), &world.lights[0]->matrix); + vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &m); VkDeviceSize offsets[] = {0}; - vkCmdBindVertexBuffers(commandBuffer, 0, 1, &mesh->vertexBuffer, offsets); - vkCmdBindIndexBuffer(commandBuffer, mesh->indexBuffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &mesh.mesh->mesh->vertexBuffer, offsets); + vkCmdBindIndexBuffer(commandBuffer, mesh.mesh->mesh->indexBuffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdDrawIndexed(commandBuffer, mesh->indices.size(), 1, 0, 0, 0); + vkCmdDrawIndexed(commandBuffer, mesh.mesh->mesh->indices.size(), 1, 0, 0, 0); } } @@ -146,18 +158,25 @@ void WorldPass::createRenderPass() { } void WorldPass::createDescriptorSetLayout() { + VkDescriptorSetLayoutBinding sceneBufferBinding = {}; + sceneBufferBinding.descriptorCount = 1; + sceneBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + sceneBufferBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + VkDescriptorSetLayoutBinding lightBufferBinding = {}; lightBufferBinding.descriptorCount = 1; + lightBufferBinding.binding = 1; lightBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; lightBufferBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; VkDescriptorSetLayoutBinding shadowBinding = {}; shadowBinding.descriptorCount = 1; - shadowBinding.binding = 1; + shadowBinding.binding = 2; shadowBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; shadowBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - const std::array bindings = { + const std::array bindings = { + sceneBufferBinding, lightBufferBinding, shadowBinding }; @@ -275,7 +294,7 @@ void WorldPass::createPipeline() { dynamicState.pDynamicStates = dynamicStates.data(); VkPushConstantRange mvpPushConstant = {}; - mvpPushConstant.size = sizeof(glm::mat4) * 2; + mvpPushConstant.size = sizeof(glm::mat4); mvpPushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; const std::array setLayouts = { @@ -313,25 +332,50 @@ void WorldPass::createPipeline() { vkDestroyShaderModule(renderer_.getDevice(), vertShaderModule, nullptr); } -void WorldPass::createUniformBuffer() { - VkBufferCreateInfo bufferInfo = {}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = sizeof(float) * (4 + 3) * 32; - bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; +void WorldPass::createUniformBuffers() { + // scene + { + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = sizeof(glm::mat4) * 2; + bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - vkCreateBuffer(renderer_.getDevice(), &bufferInfo, nullptr, &lightBuffer_); + vkCreateBuffer(renderer_.getDevice(), &bufferInfo, nullptr, &sceneBuffer_); - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(renderer_.getDevice(), lightBuffer_, &memRequirements); + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(renderer_.getDevice(), sceneBuffer_, &memRequirements); - VkMemoryAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = renderer_.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = renderer_.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - vkAllocateMemory(renderer_.getDevice(), &allocInfo, nullptr, &lightMemory_); - vkBindBufferMemory(renderer_.getDevice(), lightBuffer_, lightMemory_, 0); + vkAllocateMemory(renderer_.getDevice(), &allocInfo, nullptr, &sceneMemory_); + vkBindBufferMemory(renderer_.getDevice(), sceneBuffer_, sceneMemory_, 0); + } + + // light + { + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = sizeof(float) * (8) * 32; + bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vkCreateBuffer(renderer_.getDevice(), &bufferInfo, nullptr, &lightBuffer_); + + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(renderer_.getDevice(), lightBuffer_, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = renderer_.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + vkAllocateMemory(renderer_.getDevice(), &allocInfo, nullptr, &lightMemory_); + vkBindBufferMemory(renderer_.getDevice(), lightBuffer_, lightMemory_, 0); + } } void WorldPass::createDescriptorSet() { @@ -343,41 +387,54 @@ void WorldPass::createDescriptorSet() { vkAllocateDescriptorSets(renderer_.getDevice(), &allocInfo, &descriptorSet_); - VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = lightBuffer_; - bufferInfo.range = sizeof(float) * (4 + 3) * 32; + VkDescriptorBufferInfo sceneBufferInfo = {}; + sceneBufferInfo.buffer = sceneBuffer_; + sceneBufferInfo .range = sizeof(glm::mat4) * 2; + + VkDescriptorBufferInfo lightBufferInfo = {}; + lightBufferInfo.buffer = lightBuffer_; + lightBufferInfo.range = sizeof(float) * (8) * 32; VkDescriptorImageInfo imageInfo = {}; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo.imageView = renderer_.getShadowPass().getImageView(); imageInfo.sampler = renderer_.getShadowPass().getSampler(); - VkWriteDescriptorSet bufferDescriptorWrite = {}; - bufferDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - bufferDescriptorWrite.descriptorCount = 1; - bufferDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - bufferDescriptorWrite.dstSet = descriptorSet_; - bufferDescriptorWrite.pBufferInfo = &bufferInfo; + VkWriteDescriptorSet sceneBufferDescriptorWrite = {}; + sceneBufferDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + sceneBufferDescriptorWrite.descriptorCount = 1; + sceneBufferDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + sceneBufferDescriptorWrite.dstSet = descriptorSet_; + sceneBufferDescriptorWrite.pBufferInfo = &sceneBufferInfo; + + VkWriteDescriptorSet lightBufferDescriptorWrite = {}; + lightBufferDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + lightBufferDescriptorWrite.descriptorCount = 1; + lightBufferDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + lightBufferDescriptorWrite.dstBinding = 1; + lightBufferDescriptorWrite.dstSet = descriptorSet_; + lightBufferDescriptorWrite.pBufferInfo = &lightBufferInfo; VkWriteDescriptorSet shadowDescriptorWrite = {}; shadowDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; shadowDescriptorWrite.descriptorCount = 1; shadowDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - shadowDescriptorWrite.dstBinding = 1; + shadowDescriptorWrite.dstBinding = 2; shadowDescriptorWrite.dstSet = descriptorSet_; shadowDescriptorWrite.pImageInfo = &imageInfo; - const std::array descriptorWrites = { - bufferDescriptorWrite, + const std::array descriptorWrites = { + sceneBufferDescriptorWrite, + lightBufferDescriptorWrite, shadowDescriptorWrite }; vkUpdateDescriptorSets(renderer_.getDevice(), descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); float* data; - vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 3) * 32, 0, reinterpret_cast(&data)); + vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (8) * 32, 0, reinterpret_cast(&data)); - for(uint32_t i = 0; i < (4 + 3) * 32; i++) + for(uint32_t i = 0; i < (8) * 32; i++) data[i] = 0.0f; vkUnmapMemory(renderer_.getDevice(), lightMemory_);