diff --git a/CMakeLists.txt b/CMakeLists.txt index 3365c18..92a4439 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,5 +87,7 @@ add_executable(vulkanologi target_link_libraries(vulkanologi glfw glm tinyobjloader VulkanMemoryAllocator Vulkan::Vulkan) add_shader(vulkanologi shader.frag) add_shader(vulkanologi shader.vert) +add_shader(vulkanologi shader_unlit.frag) +add_shader(vulkanologi shader_unlit.vert) add_dependencies(vulkanologi copy-runtime-files) \ No newline at end of file diff --git a/src/Application.cpp b/src/Application.cpp index cdaa76a..fb78e15 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -84,6 +84,12 @@ void App::keyCallback(GLFWwindow* window, int key, int scancode, int action, int if(key == GLFW_KEY_F11 && action == GLFW_PRESS) { app->window->fullscreenWindow(); } + if(key == GLFW_KEY_F1 && action == GLFW_PRESS) { + app->renderer->rendererMode = NORMAL; + } + if(key == GLFW_KEY_F2 && action == GLFW_PRESS) { + app->renderer->rendererMode = WIREFRAME; + } if(key == GLFW_KEY_E && action == GLFW_PRESS) { app->showImguizmo = !app->showImguizmo; } diff --git a/src/AssetManager.h b/src/AssetManager.h index b70f4e5..b52723c 100644 --- a/src/AssetManager.h +++ b/src/AssetManager.h @@ -9,7 +9,7 @@ #include "Deletionqueue.h" #include "VkInit.h" #include "VkTypes.h" -#include "Vulkandevice.h" +#include "VulkanDevice.h" class AssetManager { public: diff --git a/src/Renderer.cpp b/src/Renderer.cpp index 39b8b83..8433932 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -52,6 +52,7 @@ Renderer::Renderer(std::shared_ptr window, std::shared_ptrdevice().destroyShaderModule(fragShaderModule); } +void Renderer::createWireframePipeline() { + auto vertShaderCode = readFile("shaders/shader_unlit.vert.spv"); + auto fragShaderCode = readFile("shaders/shader_unlit.frag.spv"); + + auto vertShaderModule = createShaderModule(vertShaderCode); + auto fragShaderModule = createShaderModule(fragShaderCode); + + vk::PipelineShaderStageCreateInfo vertShaderStageInfo { + .stage = vk::ShaderStageFlagBits::eVertex, + .module = vertShaderModule, + .pName = "main" + }; + vk::PipelineShaderStageCreateInfo fragShaderStageInfo { + .stage = vk::ShaderStageFlagBits::eFragment, + .module = fragShaderModule, + .pName = "main" + }; + vk::PipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo }; + + auto bindingDescriptions = Vertex::getBindingDescription(); + auto attributeDescriptions = Vertex::getAttributeDescriptions(); + + vk::PipelineVertexInputStateCreateInfo vertexInputInfo { + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = &bindingDescriptions, + .vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()), + .pVertexAttributeDescriptions = attributeDescriptions.data(), + }; + + vk::PipelineInputAssemblyStateCreateInfo inputAssembly { + .topology = vk::PrimitiveTopology::eTriangleList, + .primitiveRestartEnable = VK_FALSE + }; + + vk::Viewport viewport { + .x = 0.0f, + .y = 0.0f, + .width = static_cast(swapChainExtent.width), + .height = static_cast(swapChainExtent.height), + .minDepth = 0.0f, + .maxDepth = 1.0f + }; + + vk::Rect2D scissor { + .offset = {0, 0}, + .extent = swapChainExtent + }; + + vk::PipelineViewportStateCreateInfo viewportState { + .viewportCount = 1, + .pViewports = &viewport, + .scissorCount = 1, + .pScissors = &scissor, + }; + + + vk::PipelineRasterizationStateCreateInfo rasterizer { + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = vk::PolygonMode::eLine, + .cullMode = vk::CullModeFlagBits::eBack, + .frontFace = vk::FrontFace::eCounterClockwise, + .depthBiasEnable = VK_FALSE, + .depthBiasConstantFactor = 0.0f, + .depthBiasClamp = 0.0f, + .depthBiasSlopeFactor = 0.0f, + .lineWidth = 1.0f, + }; + + + vk::PipelineMultisampleStateCreateInfo multisampling { + .rasterizationSamples = device->msaaSamples(), + .sampleShadingEnable = VK_TRUE, + .minSampleShading = 0.2f, + .pSampleMask = nullptr, + .alphaToCoverageEnable = VK_FALSE, + .alphaToOneEnable = VK_FALSE, + }; + + + vk::PipelineColorBlendAttachmentState colorBlendAttachment { + .blendEnable = VK_FALSE, + .colorWriteMask = vk::ColorComponentFlagBits::eR + | vk::ColorComponentFlagBits::eG + | vk::ColorComponentFlagBits::eB + | vk::ColorComponentFlagBits::eA, + }; + + + + vk::PipelineColorBlendStateCreateInfo colorBlending { + .logicOpEnable = VK_FALSE, + .logicOp = vk::LogicOp::eCopy, + .attachmentCount = 1, + .pAttachments = &colorBlendAttachment, + .blendConstants = std::array{0.0f, 0.0f, 0.0f, 0.0f} + }; + + vk::PipelineDepthStencilStateCreateInfo depthStencil { + .depthTestEnable = VK_TRUE, + .depthWriteEnable = VK_TRUE, + .depthCompareOp = vk::CompareOp::eLess, + .depthBoundsTestEnable = VK_FALSE, + .stencilTestEnable = VK_FALSE + }; + + vk::GraphicsPipelineCreateInfo pipelineInfo { + // Reference programmable stages + .stageCount = 2, + + // Fixed Function stages + .pStages = shaderStages, + .pVertexInputState = &vertexInputInfo, + .pInputAssemblyState = &inputAssembly, + .pViewportState = &viewportState, + .pRasterizationState = &rasterizer, + .pMultisampleState = &multisampling, + .pDepthStencilState = &depthStencil, + .pColorBlendState = &colorBlending, + + // A vulkan handle, not a struct pointer + .layout = pipelineLayout, + + .renderPass = renderPass, + .subpass = 0, + .basePipelineHandle = nullptr, + .basePipelineIndex = -1, + }; + + auto result = device->device().createGraphicsPipeline(nullptr, pipelineInfo); + if (result.result != vk::Result::eSuccess) { + throw std::runtime_error("failed to create graphics pipeline!"); + } + wireframePipeline = result.value; + swapChainDeletionQueue.push_function([&]() { + device->device().destroyPipeline(wireframePipeline); + }); + + device->device().destroyShaderModule(vertShaderModule); + device->device().destroyShaderModule(fragShaderModule); +} + vk::ShaderModule Renderer::createShaderModule(const std::vector& code) { const vk::ShaderModuleCreateInfo createInfo { .codeSize = code.size(), @@ -946,7 +1090,14 @@ void Renderer::recordCommandBuffer(int index) { commandBuffers[index].beginRenderPass(renderPassInfo, vk::SubpassContents::eInline); { //Add commands to buffer - commandBuffers[index].bindPipeline(vk::PipelineBindPoint::eGraphics, graphicsPipeline); + vk::Pipeline pipeLineToBind{nullptr}; + if(rendererMode == NORMAL) { + pipeLineToBind = graphicsPipeline; + } + else if(rendererMode == WIREFRAME) { + pipeLineToBind = wireframePipeline; + } + commandBuffers[index].bindPipeline(vk::PipelineBindPoint::eGraphics, pipeLineToBind); commandBuffers[index].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, 1, &descriptorSets[index], 0, nullptr); for (auto model : renderData->getModels()) { diff --git a/src/Renderer.h b/src/Renderer.h index 11cf9b4..ba9d776 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -24,6 +24,11 @@ const int MAX_FRAMES_IN_FLIGHT = 2; std::vector readFile(const std::string& filename); +enum RendererMode { + NORMAL, + WIREFRAME +}; + class Renderer { public: Renderer(std::shared_ptr window, std::shared_ptr device, AssetManager &assetManager, @@ -35,8 +40,9 @@ class Renderer { void drawFrame(); void frameBufferResized(); Material createMaterial(std::vector& texturePaths); + RendererMode rendererMode = RendererMode::NORMAL; - private: +private: std::shared_ptr window; std::shared_ptr device; AssetManager& assetManager; @@ -66,6 +72,7 @@ class Renderer { vk::PipelineLayout pipelineLayout; vk::Pipeline graphicsPipeline; + vk::Pipeline wireframePipeline; vk::CommandPool commandPool; vk::CommandPool transferCommandPool; @@ -110,8 +117,9 @@ class Renderer { void createGraphicsPipelineLayout(); void createGraphicsPipeline(); + void createWireframePipeline(); - vk::ShaderModule createShaderModule(const std::vector& code); + vk::ShaderModule createShaderModule(const std::vector& code); void createFramebuffers(); diff --git a/src/VulkanDevice.cpp b/src/VulkanDevice.cpp index 2345bfe..c757afa 100644 --- a/src/VulkanDevice.cpp +++ b/src/VulkanDevice.cpp @@ -152,7 +152,8 @@ void VulkanDevice::createLogicalDevice() { vk::PhysicalDeviceFeatures deviceFeatures { .sampleRateShading = VK_TRUE, - .samplerAnisotropy = VK_TRUE + .fillModeNonSolid = VK_TRUE, + .samplerAnisotropy = VK_TRUE, }; vk::PhysicalDeviceDescriptorIndexingFeatures descriptorIndexFeatures { @@ -248,6 +249,7 @@ std::vector VulkanDevice::getRequiredExtensions() { extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } + return extensions; } diff --git a/src/shaders/shader_unlit.frag b/src/shaders/shader_unlit.frag new file mode 100644 index 0000000..7836eb9 --- /dev/null +++ b/src/shaders/shader_unlit.frag @@ -0,0 +1,25 @@ +#version 450 +#extension GL_EXT_nonuniform_qualifier : enable + +layout(set = 0, binding = 0) uniform UniformBufferObject { + mat4 view; + mat4 proj; + mat4 projView; + vec4 ambientLightColor; // w is intensity + vec4 lightPosition; // w is ignored + vec4 lightColor; // w is intensity +} ubo; + +layout(set = 1, binding = 0) uniform sampler2D texSampler[]; + +layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec2 fragTexCoord; +layout(location = 2) in flat uint materialIndex; +layout(location = 3) in vec3 fragPosWorld; +layout(location = 4) in vec3 fragNormalWorld; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} \ No newline at end of file diff --git a/src/shaders/shader_unlit.vert b/src/shaders/shader_unlit.vert new file mode 100644 index 0000000..dc3106a --- /dev/null +++ b/src/shaders/shader_unlit.vert @@ -0,0 +1,42 @@ +#version 450 + +layout(set = 0, binding = 0) uniform UniformBufferObject { + mat4 view; + mat4 proj; + mat4 projView; + vec4 ambientLightColor; // w is intensity + vec4 lightPosition; // w is ignored + vec4 lightColor; // w is intensity +} ubo; + +layout (push_constant) uniform constants { + mat4 modelMatrix; +} pushConstants; + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inColor; +layout(location = 2) in vec3 inNormal; +layout(location = 3) in vec2 inTexCoord; +layout(location = 4) in uint inMaterialIndex; + + +layout(location = 0) out vec3 fragColor; +layout(location = 1) out vec2 fragTexCoord; +layout(location = 2) out uint materialIndex; +layout(location = 3) out vec3 fragPosWorld; +layout(location = 4) out vec3 fragNormalWorld; + +void main() { + vec4 positionWorld = pushConstants.modelMatrix * vec4(inPosition, 1.0); + + gl_Position = ubo.projView * positionWorld; + fragColor = inColor; + fragTexCoord = inTexCoord; + materialIndex = inMaterialIndex; + fragPosWorld = positionWorld.xyz; + // Diffuse shading does not work correctly if model is scaled non Uniformly + // https://paroj.github.io/gltut/Illumination/Tut09%20Normal%20Transformation.html + // TODO: Fix this if it becomes necessary + // Can be done by computing the value on the CPU and sending it as a Push Constant + fragNormalWorld = normalize((pushConstants.modelMatrix * vec4(inNormal, 0.0)).xyz); +}