diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 671c99925536d63e1ef87c0d069e1929e1a592b9..248a5471d73aa66f36496f17c8a3ae5e9588e77f 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(CubeMapping) add_subdirectory(InstancingDemo) add_subdirectory(NormalMapping) diff --git a/demos/CubeMapping/.gitignore b/demos/CubeMapping/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..347cd8b2ccef2c1abb8b363d0c08fde0a2dd5f9d --- /dev/null +++ b/demos/CubeMapping/.gitignore @@ -0,0 +1 @@ +CubeMapping \ No newline at end of file diff --git a/demos/CubeMapping/CMakeLists.txt b/demos/CubeMapping/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..9087dda7f348bb80b88fe711f5e4fd2604a0b1fa --- /dev/null +++ b/demos/CubeMapping/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.16) +project(CubeMapping) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# adding source files to the project +add_project(CubeMapping src/main.cpp) + +# including headers of dependencies and the VkCV framework +target_include_directories(CubeMapping SYSTEM BEFORE PRIVATE ${vkcv_includes}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(CubeMapping ${vkcv_libraries}) diff --git a/demos/CubeMapping/shaders/CubeMapReflection.frag b/demos/CubeMapping/shaders/CubeMapReflection.frag new file mode 100644 index 0000000000000000000000000000000000000000..11f5d1c1f5c996f7a17d4ce7c619b67d7e7afc46 --- /dev/null +++ b/demos/CubeMapping/shaders/CubeMapReflection.frag @@ -0,0 +1,90 @@ +#version 450 + +//incoming data +layout(location = 0) in vec3 passPosition; +layout(location = 1) in vec3 passNormal; +layout(location = 2) in vec2 passUVCoord; + +layout(location = 3) in vec3 passReflectionNormal; + +layout(set=0, binding=0) uniform matrixBuffer { + mat4 viewMatrix; + mat4 projectionMatrix; +}; + +struct Material { + vec3 diffuse; + float reflectionStrength; + vec3 specular; + float shininess; +}; + +layout(set=0, binding=1) uniform materialBuffer { + Material mat; +}; + +struct Light { + vec4 pos; // pos.w = 0 (dir light), pos.w = 1 (point light) + vec3 col; + float spot_exponent; + vec3 spot_direction; + float spot_cutoff; // no spotlight if cutoff = 0 +}; + +layout(set=0, binding=2) uniform lightBuffer { + Light light; + vec3 lightAmbient; +}; + +layout(set=0, binding=3) uniform textureCube cubeMapTexture; +layout(set=0, binding=4) uniform sampler cubeMapSampler; + +layout(location = 0) out vec4 fragmentColor; + +void main() { + /////////////////////////////////////////////////////// + ///////////////// Cube Map Reflection ///////////////// + /////////////////////////////////////////////////////// + vec3 pos = normalize(passPosition); + vec3 normal = normalize(passReflectionNormal); + vec3 reflected = reflect(pos, normal); + reflected = vec3(inverse(viewMatrix) * vec4(reflected, 0.0)); + + vec3 inNormal = normalize(passNormal); + + //Diffuse + vec3 lightVector; + vec3 light_camcoord = (viewMatrix * light.pos).xyz; + if (light.pos.w > 0.001f) + lightVector = normalize(light_camcoord - passPosition); + else + lightVector = normalize(light_camcoord); + float cos_phi = max(dot(inNormal, lightVector), 0.0f); + + // Specular + vec3 eye = normalize(-passPosition); + vec3 reflection = normalize(reflect(-lightVector, inNormal)); + float cos_psi_n = pow(max(dot(reflection, eye), 0.0f), mat.shininess); + + //Spotlight + float spot = 1.0; + if (light.spot_cutoff >= 0.001f) { + float cos_phi_spot = max(dot(-lightVector, mat3(viewMatrix) * light.spot_direction), 0.0f); + if (cos_phi_spot >= cos(light.spot_cutoff)) { + spot = pow(cos_phi_spot, light.spot_exponent); + } else { + spot = 0.0f; + } + } + + //Color + vec3 diffuse_color = mat.diffuse; + + //All together + fragmentColor.rgb = diffuse_color * lightAmbient; + fragmentColor.rgb += spot * diffuse_color * cos_phi * light.col; + fragmentColor.rgb += spot * mat.specular * cos_psi_n * light.col; + fragmentColor *= (1.0 - mat.reflectionStrength); + fragmentColor += texture(samplerCube(cubeMapTexture, cubeMapSampler), reflected) * mat.reflectionStrength; + fragmentColor.a = 1.0; +} diff --git a/demos/CubeMapping/shaders/CubeMapReflection.vert b/demos/CubeMapping/shaders/CubeMapReflection.vert new file mode 100644 index 0000000000000000000000000000000000000000..e3f5d47e7040d9fba7af79c515bb2153b067f173 --- /dev/null +++ b/demos/CubeMapping/shaders/CubeMapReflection.vert @@ -0,0 +1,30 @@ +#version 450 + +layout(location = 0) in vec3 position; +layout(location = 1) in vec3 normal; +layout(location = 2) in vec2 uv; + +layout(set=0, binding=0) uniform matrixBuffer { + mat4 viewMatrix; + mat4 projectionMatrix; +}; + +layout( push_constant ) uniform constants { + mat4 modelMatrix; +}; + +layout(location = 0) out vec3 passPosition; +layout(location = 1) out vec3 passNormal; +layout(location = 2) out vec2 passUVCoord; + +layout(location = 3) out vec3 passReflectionNormal; + +void main() { + passPosition = (viewMatrix * modelMatrix * vec4(position, 1)).xyz; + passNormal = vec3(transpose(inverse(viewMatrix * modelMatrix)) * vec4(normal, 0)); + passUVCoord = uv; + + passReflectionNormal = vec3(viewMatrix * modelMatrix * vec4(normal, 0)); + + gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1); +} diff --git a/demos/CubeMapping/shaders/SkyBox.frag b/demos/CubeMapping/shaders/SkyBox.frag new file mode 100644 index 0000000000000000000000000000000000000000..ea357e5288dd3231b31eaa072fcc6baa1f2e5f6f --- /dev/null +++ b/demos/CubeMapping/shaders/SkyBox.frag @@ -0,0 +1,13 @@ +#version 450 + +//incoming data +layout(location = 0) in vec3 passTexCoord; + +layout(set=0, binding=1) uniform textureCube cubeMapTexture; +layout(set=0, binding=2) uniform sampler cubeMapSampler; + +layout(location = 0) out vec4 fragmentColor; + +void main() { + fragmentColor = texture(samplerCube(cubeMapTexture, cubeMapSampler), passTexCoord); +} diff --git a/demos/CubeMapping/shaders/SkyBox.vert b/demos/CubeMapping/shaders/SkyBox.vert new file mode 100644 index 0000000000000000000000000000000000000000..361f8da1fc98ff60f020ea3932c6711b0308732f --- /dev/null +++ b/demos/CubeMapping/shaders/SkyBox.vert @@ -0,0 +1,19 @@ +#version 450 + +layout(location = 0) in vec3 position; + +layout(set=0, binding=0) uniform matrixBuffer { + mat4 viewMatrix; + mat4 projectionMatrix; +}; + +layout(location = 0) out vec3 passTexCoord; + +void main() { + passTexCoord = position; + + mat4 vM = mat4(mat3(viewMatrix)); + + // Set Pos to xyww instead of xyzw, so that z will always be 1 (furthest from camera) + gl_Position = (projectionMatrix * vM * vec4(position, 1)).xyww; +} diff --git a/demos/CubeMapping/src/main.cpp b/demos/CubeMapping/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cfef5810850f71b756e5b17ad323b9ce016795d2 --- /dev/null +++ b/demos/CubeMapping/src/main.cpp @@ -0,0 +1,378 @@ + +#include <iostream> +#include <vkcv/Buffer.hpp> +#include <vkcv/Core.hpp> +#include <vkcv/DescriptorWrites.hpp> +#include <vkcv/Image.hpp> +#include <vkcv/Pass.hpp> +#include <vkcv/Sampler.hpp> +#include <vkcv/Window.hpp> +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/camera/CameraManager.hpp> +#include <vkcv/geometry/Cuboid.hpp> +#include <vkcv/geometry/Sphere.hpp> +#include <vkcv/geometry/Teapot.hpp> +#include <vkcv/gui/GUI.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> + +struct Material { + glm::vec3 diffuse; + float reflectionStrength; + glm::vec3 specular; + float shininess; +}; + +struct Light { + glm::vec4 pos; // pos.w = 0 (dir light), pos.w = 1 (point light) + glm::vec3 col; + float spot_exponent; + glm::vec3 spot_direction; + float spot_cutoff; // no spotlight if cutoff = 0 +}; + +struct LightProps { + Light light; + glm::vec3 lightAmbient; +}; + +struct FogParams { + glm::vec3 col; // Fog color + float density; // For exp and exp2 equation + float start; // This is only for linear fog + float end; // This is only for linear fog + int mode; // 1 = linear, 2 = exp, 3 = exp2 +}; + +struct TextureProps { + int useColorTexture; +}; + +int main(int argc, const char** argv) { + const std::string applicationName = "Cube Mapping"; + + vkcv::Core core = vkcv::Core::create( + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eTransfer }, + { VK_KHR_SWAPCHAIN_EXTENSION_NAME } + ); + + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 800, 800, true); + vkcv::Window& window = core.getWindow(windowHandle); + + vkcv::camera::CameraManager cameraManager (window); + auto camHandle = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camHandle).setNearFar(0.1f, 10.0f); + + vkcv::shader::GLSLCompiler compiler; + vkcv::ShaderProgram cubeMappingShaderProgram, skyBoxShaderProgram; + + compiler.compileProgram( + cubeMappingShaderProgram, + { + { vkcv::ShaderStage::VERTEX, "shaders/CubeMapReflection.vert" }, + { vkcv::ShaderStage::FRAGMENT, "shaders/CubeMapReflection.frag" } + }, + nullptr + ); + + compiler.compileProgram( + skyBoxShaderProgram, + { + { vkcv::ShaderStage::VERTEX, "shaders/SkyBox.vert" }, + { vkcv::ShaderStage::FRAGMENT, "shaders/SkyBox.frag" } + }, + nullptr + ); + + vkcv::PassHandle renderPass = core.createPass(vkcv::PassConfig( + { + vkcv::AttachmentDescription( + core.getSwapchainFormat(window.getSwapchain()), + vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::STORE, + vk::ClearValue(vk::ClearColorValue(std::array<float, 4>{ + 1.0f, 1.0f, 1.0f, 1.0f + })) + ), + vkcv::AttachmentDescription( + vk::Format::eD32Sfloat, + vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::STORE + ) + } + )); + + vkcv::PassHandle skyRenderPass = vkcv::passSwapchain(core, window.getSwapchain(), { + vk::Format::eUndefined, vk::Format::eD32Sfloat + }, false); + + const vkcv::VertexLayout vertexLayoutCubeMapping { + vkcv::createVertexBindings(cubeMappingShaderProgram.getVertexAttachments()) + }; + + const vkcv::VertexLayout vertexLayoutSykBox { + vkcv::createVertexBindings(skyBoxShaderProgram.getVertexAttachments()) + }; + + const vkcv::DescriptorBindings descriptorBindings = ( + cubeMappingShaderProgram.getReflectedDescriptors().at(0) + ); + + auto descriptorSetLayout = core.createDescriptorSetLayout(descriptorBindings); + + auto descriptorSetSphere = core.createDescriptorSet(descriptorSetLayout); + auto descriptorSetTeapot = core.createDescriptorSet(descriptorSetLayout); + + const vkcv::DescriptorBindings& descriptorBindingsSkyBox = ( + skyBoxShaderProgram.getReflectedDescriptors().at(0) + ); + + auto descriptorSetLayoutSkyBox = core.createDescriptorSetLayout(descriptorBindingsSkyBox); + auto descriptorSetSkyBox = core.createDescriptorSet(descriptorSetLayoutSkyBox); + + vkcv::GraphicsPipelineHandle cubeMappingPipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + cubeMappingShaderProgram, + renderPass, + vertexLayoutCubeMapping, + { descriptorSetLayout } + ) + ); + + vkcv::GraphicsPipelineHandle skyBoxPipeline = core.createGraphicsPipeline( + vkcv::GraphicsPipelineConfig( + skyBoxShaderProgram, + skyRenderPass, + vertexLayoutSykBox, + { descriptorSetLayoutSkyBox } + ) + ); + + auto matrixBuffer = vkcv::buffer<glm::mat4>( + core, + vkcv::BufferType::UNIFORM, + 2, + vkcv::BufferMemoryType::HOST_VISIBLE + ); + + auto matBlueBuffer = vkcv::buffer<Material>( + core, + vkcv::BufferType::UNIFORM, + 1 + ); + + Material mat_blue; + mat_blue.diffuse = glm::vec3(0.0f, 0.0f, 1.0f); + mat_blue.reflectionStrength = 0.7f; + mat_blue.specular = glm::vec3(1.0f); + mat_blue.shininess = 100.0f; + matBlueBuffer.fill(&mat_blue, 1); + + auto matRedBuffer = vkcv::buffer<Material>( + core, + vkcv::BufferType::UNIFORM, + 1 + ); + + Material mat_red; + mat_red.diffuse = glm::vec3(1.0f, 0.0f, 0.0f); + mat_red.reflectionStrength = 0.7f; + mat_red.specular = glm::vec3(1.0f); + mat_red.shininess = 100.0f; + matRedBuffer.fill(&mat_red, 1); + + auto lightBuffer = vkcv::buffer<LightProps>( + core, + vkcv::BufferType::UNIFORM, + 1 + ); + + LightProps lightProps; + lightProps.light.pos = glm::vec4(0.0f, 1.0f, -10.0f, 1.0f); + lightProps.light.col = glm::vec3(0.75f); + lightProps.light.spot_exponent = 1.0f; + lightProps.light.spot_direction = glm::vec3(0.0f); + lightProps.light.spot_cutoff = 0.0f; + lightProps.lightAmbient = glm::vec3(0.2f); + lightBuffer.fill(&lightProps, 1); + + vkcv::asset::Texture negx = vkcv::asset::loadTexture("../../resources/cubeMap/negx.jpg"); + vkcv::asset::Texture negy = vkcv::asset::loadTexture("../../resources/cubeMap/negy.jpg"); + vkcv::asset::Texture negz = vkcv::asset::loadTexture("../../resources/cubeMap/negz.jpg"); + vkcv::asset::Texture posx = vkcv::asset::loadTexture("../../resources/cubeMap/posx.jpg"); + vkcv::asset::Texture posy = vkcv::asset::loadTexture("../../resources/cubeMap/posy.jpg"); + vkcv::asset::Texture posz = vkcv::asset::loadTexture("../../resources/cubeMap/posz.jpg"); + + vkcv::ImageConfig cubemapConfig (negx.w, negx.h); + cubemapConfig.setCubeMapImage(true); + + vkcv::Image cubemapImage = vkcv::image(core, vk::Format::eR8G8B8A8Srgb, cubemapConfig); + cubemapImage.fillLayer(0, posx.data.data()); + cubemapImage.fillLayer(1, negx.data.data()); + cubemapImage.fillLayer(2, posy.data.data()); + cubemapImage.fillLayer(3, negy.data.data()); + cubemapImage.fillLayer(4, posz.data.data()); + cubemapImage.fillLayer(5, negz.data.data()); + + vkcv::SamplerHandle sampler = vkcv::samplerLinear(core); + + { + vkcv::DescriptorWrites writes; + writes.writeUniformBuffer(0, matrixBuffer.getHandle()); + writes.writeUniformBuffer(1, matRedBuffer.getHandle()); + writes.writeUniformBuffer(2, lightBuffer.getHandle()); + writes.writeSampledImage(3, cubemapImage.getHandle()); + writes.writeSampler(4, sampler); + core.writeDescriptorSet(descriptorSetSphere, writes); + } + + { + vkcv::DescriptorWrites writes; + writes.writeUniformBuffer(0, matrixBuffer.getHandle()); + writes.writeUniformBuffer(1, matBlueBuffer.getHandle()); + writes.writeUniformBuffer(2, lightBuffer.getHandle()); + writes.writeSampledImage(3, cubemapImage.getHandle()); + writes.writeSampler(4, sampler); + core.writeDescriptorSet(descriptorSetTeapot, writes); + } + + { + vkcv::DescriptorWrites writes; + writes.writeUniformBuffer(0, matrixBuffer.getHandle()); + writes.writeSampledImage(1, cubemapImage.getHandle()); + writes.writeSampler(2, sampler); + core.writeDescriptorSet(descriptorSetSkyBox, writes); + } + + vkcv::gui::GUI gui (core, windowHandle); + + bool adjustedReflectionStrength = false; + bool renderSkyBox = true; + + vkcv::geometry::Cuboid cube (glm::vec3(0.0f), 1.0f); + vkcv::geometry::Sphere sphere (glm::vec3(0.0f), 0.3f); + vkcv::geometry::Teapot teapot (glm::vec3(0.0f), 1.0f); + + sphere.setResolution(20); + + vkcv::InstanceDrawcall drawcallSphere (sphere.generateVertexData(core)); + drawcallSphere.useDescriptorSet(0, descriptorSetSphere); + + vkcv::InstanceDrawcall drawcallTeapot (teapot.generateVertexData(core)); + drawcallTeapot.useDescriptorSet(0, descriptorSetTeapot); + + vkcv::InstanceDrawcall drawcallSkyBox (cube.generateVertexData(core)); + drawcallSkyBox.useDescriptorSet(0, descriptorSetSkyBox); + + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + vkcv::ImageHandle depthBuffer; + + glm::mat4* mvp = matrixBuffer.map(); + + core.run([&](const vkcv::WindowHandle &windowHandle, + double t, + double dt, + uint32_t swapchainWidth, + uint32_t swapchainHeight + ) { + if ((!depthBuffer) || + (swapchainWidth != core.getImageWidth(depthBuffer)) || + (swapchainHeight != core.getImageHeight(depthBuffer))) { + depthBuffer = core.createImage( + vk::Format::eD32Sfloat, + vkcv::ImageConfig( + swapchainWidth, + swapchainHeight + ) + ); + } + + if (adjustedReflectionStrength) { + matBlueBuffer.fill(&mat_blue, 1); + matRedBuffer.fill(&mat_red, 1); + + adjustedReflectionStrength = false; + } + + cameraManager.update(dt); + + const glm::mat4 teapotMat = glm::rotate( + glm::identity<glm::mat4>(), + glm::radians(30.0f) * static_cast<float>(t), + glm::vec3(0, 1, 0) + ); + + const glm::mat4 sphereMat = teapotMat * glm::rotate( + glm::translate(glm::mat4(1.0f), glm::vec3(3, 0, 0)), + glm::radians(90.0f) * static_cast<float>(t), + glm::vec3(1, 1, 1) + ); + + mvp[0] = cameraManager.getActiveCamera().getView(); + mvp[1] = cameraManager.getActiveCamera().getProjection(); + + auto pushConstants = vkcv::pushConstants<glm::mat4>(); + pushConstants.appendDrawcall(teapotMat); + pushConstants.appendDrawcall(sphereMat); + + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + core.prepareImageForSampling(cmdStream, cubemapImage.getHandle()); + + core.recordDrawcallsToCmdStream( + cmdStream, + cubeMappingPipeline, + pushConstants, + { + drawcallTeapot, + drawcallSphere + }, + { + swapchainInput, + depthBuffer + }, + windowHandle + ); + + if (renderSkyBox) { + core.recordDrawcallsToCmdStream( + cmdStream, + skyBoxPipeline, + vkcv::PushConstants(0), + { drawcallSkyBox }, + { + swapchainInput, + depthBuffer + }, + windowHandle + ); + } + + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + + gui.beginGUI(); + + float reflectionStrength = mat_red.reflectionStrength; + + ImGui::Begin("Settings"); + ImGui::SliderFloat("Reflection strength", &reflectionStrength, 0.0f, 1.0f); + ImGui::Checkbox("Render sky box", &renderSkyBox); + ImGui::End(); + + if (reflectionStrength != mat_red.reflectionStrength) { + mat_blue.reflectionStrength = reflectionStrength; + mat_red.reflectionStrength = reflectionStrength; + + adjustedReflectionStrength = true; + } + + gui.endGUI(); + }); + + matrixBuffer.unmap(); + return 0; +} diff --git a/demos/InstancingDemo/src/main.cpp b/demos/InstancingDemo/src/main.cpp index a0dc75e4acec92f3f855415ea47d638c91b6489d..0f17c5aa75f311ff88e01be69e3e2404a0e84624 100644 --- a/demos/InstancingDemo/src/main.cpp +++ b/demos/InstancingDemo/src/main.cpp @@ -152,8 +152,10 @@ int main(int argc, const char** argv) { (swapchainHeight != core.getImageHeight(depthBuffer))) { depthBuffer = core.createImage( vk::Format::eD32Sfloat, - swapchainWidth, - swapchainHeight + vkcv::ImageConfig( + swapchainWidth, + swapchainHeight + ) ); } diff --git a/demos/NormalMapping/src/main.cpp b/demos/NormalMapping/src/main.cpp index da6fe0c2c309f373d80cb4d41f65ba88a53c3fbb..c3483cfc3517b56f9d34aa501b438897bcfca10e 100644 --- a/demos/NormalMapping/src/main.cpp +++ b/demos/NormalMapping/src/main.cpp @@ -261,8 +261,10 @@ int main(int argc, const char** argv) { (swapchainHeight != core.getImageHeight(depthBuffer))) { depthBuffer = core.createImage( vk::Format::eD32Sfloat, - swapchainWidth, - swapchainHeight + vkcv::ImageConfig( + swapchainWidth, + swapchainHeight + ) ); } diff --git a/framework b/framework index 21562cea94ff11677477431f8d958c0d6577a415..68955e55e1406d28006fa5696f11d10c987b8530 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 21562cea94ff11677477431f8d958c0d6577a415 +Subproject commit 68955e55e1406d28006fa5696f11d10c987b8530