diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 3ff2d925bff188a585f6bd3047ba0e7b2ca594c3..ab0d2aca0eccbd3c6adfea191cefa2c63623b0b9 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -186,9 +186,9 @@ namespace vkcv /** * @brief render a beautiful triangle */ - void renderTriangle(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, + void renderMesh(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, const int width, const int height, const size_t pushConstantSize, const void* pushConstantData, - const BufferHandle vertexBuffer); + const BufferHandle vertexBuffer, const BufferHandle indexBuffer, const size_t indexCount); /** * @brief end recording and present image diff --git a/projects/first_mesh/CMakeLists.txt b/projects/first_mesh/CMakeLists.txt index ae9c5604cb83c6f3a16773e896521117460839f7..eb0f028db38707272f9fbcf61662633f2868eedc 100644 --- a/projects/first_mesh/CMakeLists.txt +++ b/projects/first_mesh/CMakeLists.txt @@ -22,7 +22,7 @@ if(MSVC) endif() # including headers of dependencies and the VkCV framework -target_include_directories(first_mesh SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include}) +target_include_directories(first_mesh SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include}) # linking with libraries from all dependencies and the VkCV framework -target_link_libraries(first_mesh vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries}) +target_link_libraries(first_mesh vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera) diff --git a/projects/first_mesh/resources/shaders/compile.bat b/projects/first_mesh/resources/shaders/compile.bat new file mode 100644 index 0000000000000000000000000000000000000000..b4521235c40fe5fb163bab874560c2f219b7517f --- /dev/null +++ b/projects/first_mesh/resources/shaders/compile.bat @@ -0,0 +1,3 @@ +%VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv +%VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv +pause \ No newline at end of file diff --git a/projects/first_mesh/resources/shaders/frag.spv b/projects/first_mesh/resources/shaders/frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..cb13e606fc0041e24ff6a63c0ec7dcca466732aa Binary files /dev/null and b/projects/first_mesh/resources/shaders/frag.spv differ diff --git a/projects/first_mesh/resources/shaders/shader.frag b/projects/first_mesh/resources/shaders/shader.frag new file mode 100644 index 0000000000000000000000000000000000000000..d26446a73020111695aa2c86166205796dfa5e44 --- /dev/null +++ b/projects/first_mesh/resources/shaders/shader.frag @@ -0,0 +1,9 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 fragColor; +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} \ No newline at end of file diff --git a/projects/first_mesh/resources/shaders/shader.vert b/projects/first_mesh/resources/shaders/shader.vert new file mode 100644 index 0000000000000000000000000000000000000000..e6c0e3d6bafda35e90a6bfd849a211e2b6de0f9c --- /dev/null +++ b/projects/first_mesh/resources/shaders/shader.vert @@ -0,0 +1,27 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 position; + +layout(location = 0) out vec3 fragColor; + +layout( push_constant ) uniform constants{ + mat4 mvp; +}; + +void main() { + vec3 positions[3] = { + vec3(-0.5, 0.5, -1), + vec3( 0.5, 0.5, -1), + vec3(0, -0.5, -1) + }; + + vec3 colors[3] = { + vec3(1, 0, 0), + vec3(0, 1, 0), + vec3(0, 0, 1) + }; + + gl_Position = mvp * vec4(position, 1.0); + fragColor = colors[gl_VertexIndex % 3]; +} \ No newline at end of file diff --git a/projects/first_mesh/resources/shaders/vert.spv b/projects/first_mesh/resources/shaders/vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..74722f38ff0584d51d4a966c748b69a4d3f1d3cb Binary files /dev/null and b/projects/first_mesh/resources/shaders/vert.spv differ diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index b37429e1f7080b70aaab514125f86fbe03f329b5..2b5c783b48abbda4d7c3d7e94e1194b87ce1a304 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -1,76 +1,103 @@ #include <iostream> -#include <stdio.h> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <chrono> #include <vkcv/asset/asset_loader.hpp> int main(int argc, const char** argv) { + const char* applicationName = "First Mesh"; + + const int windowWidth = 800; + const int windowHeight = 600; + vkcv::Window window = vkcv::Window::create( + applicationName, + windowWidth, + windowHeight, + false + ); + + vkcv::CameraManager cameraManager(window, windowWidth, windowHeight); + + window.initEvents(); + + vkcv::Core core = vkcv::Core::create( + window, + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, + {}, + { "VK_KHR_swapchain" } + ); + vkcv::asset::Mesh mesh; - - const char *path = argc > 1 ? argv[1] : "resources/cube/cube.gltf"; + + const char* path = argc > 1 ? argv[1] : "resources/cube/cube.gltf"; int result = vkcv::asset::loadMesh(path, mesh); - + if (result == 1) { std::cout << "Mesh loading successful!" << std::endl; - } else { + } + else { std::cout << "Mesh loading failed: " << result << std::endl; return 1; } - /* Demonstration of how to use the vkcv::asset::Mesh struct. */ - const char *primitive_modes[] = { - "points", "lines", "line loop", "line strip", "triangles", - "triangle strip", "triangle fan" - }; - const char *primitive_types[] = { - "unknown", "position", "normal", "texcoord0" - }; - printf("Mesh %s (%s) has %lu vertex group(s) and %lu material(s):\n", - mesh.name.c_str(), path, mesh.vertexGroups.size(), - mesh.materials.size()); - for (size_t i = 0; i < mesh.vertexGroups.size(); i++) { - printf("--- vertex group %lu ---\n", i); - const auto &vg = mesh.vertexGroups[i]; - printf("primitive mode: %d (%s)\n", vg.mode, - primitive_modes[vg.mode]); - printf("index buffer: %lu bytes for %lu indices ", - vg.indexBuffer.data.size(), vg.numIndices); - const auto itype = vg.indexBuffer.type; - printf("(%s @ %p)\n", - itype == vkcv::asset::UINT32 ? "UINT32" : - itype == vkcv::asset::UINT16 ? "UINT16" : - "UINT8", vg.indexBuffer.data.data()); - printf("\tindices: "); - const size_t n = vg.numIndices; - if (vg.indexBuffer.type == vkcv::asset::UINT32) { - uint32_t *idx = (uint32_t*)vg.indexBuffer.data.data(); - for (size_t j = 0; j < n; j++) printf("%u ", idx[j]); - } else - if (vg.indexBuffer.type == vkcv::asset::UINT16) { - uint16_t *idx = (uint16_t*)vg.indexBuffer.data.data(); - for (size_t j = 0; j < n; j++) printf("%u ", idx[j]); - } else - if (vg.indexBuffer.type == vkcv::asset::UINT8) { - uint8_t *idx = (uint8_t*)vg.indexBuffer.data.data(); - for (size_t j = 0; j < n; j++) printf("%u ", idx[j]); - } else { - fprintf(stderr, "ERROR Invalid IndexType: %d\n", - vg.indexBuffer.type); - return 0; - } - printf("\n"); - printf("vertex buffer: %lu bytes for %lu vertices with %lu " - "attributes (starting at %p)\n", - vg.vertexBuffer.data.size(), vg.numVertices, - vg.vertexBuffer.attributes.size(), - vg.vertexBuffer.data.data()); - printf("attributes:\toffset\tlength\tstride\tcomponents\n"); - for (const auto att : vg.vertexBuffer.attributes) { - printf("%11s\t%u\t%u\t%u\t%hhux%hu\n", - primitive_types[att.type], - att.offset, att.length, att.stride, - att.componentCount, att.componentType); - } + assert(mesh.vertexGroups.size() > 0); + const size_t vertexBufferSize = mesh.vertexGroups[0].vertexBuffer.data.size(); + auto vertexBuffer = core.createBuffer<uint8_t>(vkcv::BufferType::VERTEX, vertexBufferSize, vkcv::BufferMemoryType::DEVICE_LOCAL); + vertexBuffer.fill(mesh.vertexGroups[0].vertexBuffer.data.data(), vertexBufferSize); + + const size_t indexBufferSize = mesh.vertexGroups[0].indexBuffer.data.size(); + auto indexBuffer = core.createBuffer<uint8_t>(vkcv::BufferType::INDEX, indexBufferSize, vkcv::BufferMemoryType::DEVICE_LOCAL); + indexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data.data(), indexBufferSize); + + // an example attachment for passes that output to the window + const vkcv::AttachmentDescription present_color_attachment( + vkcv::AttachmentLayout::UNDEFINED, + vkcv::AttachmentLayout::COLOR_ATTACHMENT, + vkcv::AttachmentLayout::PRESENTATION, + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + core.getSwapchainImageFormat()); + + vkcv::PassConfig trianglePassDefinition({ present_color_attachment }); + vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition); + + if (trianglePass.id == 0) + { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; + } + + vkcv::ShaderProgram triangleShaderProgram{}; + triangleShaderProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv")); + triangleShaderProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv")); + triangleShaderProgram.reflectShader(vkcv::ShaderStage::VERTEX); + triangleShaderProgram.reflectShader(vkcv::ShaderStage::FRAGMENT); + + const vkcv::PipelineConfig trianglePipelineDefinition(triangleShaderProgram, windowWidth, windowHeight, trianglePass); + vkcv::PipelineHandle trianglePipeline = core.createGraphicsPipeline(trianglePipelineDefinition); + if (trianglePipeline.id == 0) + { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + auto start = std::chrono::system_clock::now(); + while (window.isWindowOpen()) + { + core.beginFrame(); + window.pollEvents(); + auto end = std::chrono::system_clock::now(); + auto deltatime = end - start; + start = end; + cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count()); + const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView(); + + core.renderMesh(trianglePass, trianglePipeline, windowWidth, windowHeight, sizeof(mvp), &mvp, vertexBuffer.getHandle(), indexBuffer.getHandle(), mesh.vertexGroups[0].numIndices); + core.endFrame(); } - return 0; } diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index 6261b4d8871e0ac6c2581eb97126a94adf100f5a..0e21f4728bab2044c3910a48d9a23c0ad921607a 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -40,16 +40,19 @@ int main(int argc, const char** argv) { const size_t n = 5027; - auto vertexBuffer = core.createBuffer<vec3>(vkcv::BufferType::VERTEX, n, vkcv::BufferMemoryType::DEVICE_LOCAL); + auto testBuffer = core.createBuffer<vec3>(vkcv::BufferType::VERTEX, n, vkcv::BufferMemoryType::DEVICE_LOCAL); vec3 vec_data[n]; for (size_t i = 0; i < n; i++) { vec_data[i] = { 42, static_cast<float>(i), 7 }; } - vertexBuffer.fill(vec_data); + testBuffer.fill(vec_data); + + auto triangleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, n, vkcv::BufferMemoryType::DEVICE_LOCAL); + uint16_t indices[3] = { 0, 1, 2 }; + triangleIndexBuffer.fill(&indices[0], sizeof(indices)); - /*vec3* m = buffer.map(); m[0] = { 0, 0, 0 }; m[1] = { 0, 0, 0 }; @@ -143,7 +146,7 @@ int main(int argc, const char** argv) { cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count()); const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView(); - core.renderTriangle(trianglePass, trianglePipeline, windowWidth, windowHeight, sizeof(mvp), &mvp, vertexBuffer.getHandle()); + core.renderMesh(trianglePass, trianglePipeline, windowWidth, windowHeight, sizeof(mvp), &mvp, testBuffer.getHandle(), triangleIndexBuffer.getHandle(), 3); core.endFrame(); } return 0; diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index e9b5112888782ae5be373f8a63777b7fc3503713..bb3cf0699cc59d22832a0563f1b95bf942b02265 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -69,6 +69,9 @@ namespace vkcv { case BufferType::STAGING: usageFlags = vk::BufferUsageFlagBits::eTransferSrc; break; + case BufferType::INDEX: + usageFlags = vk::BufferUsageFlagBits::eIndexBuffer; + break; default: // TODO: maybe an issue break; diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index bac12602871a7605cba1d808fde1b21d03ade9bc..13800254d78cb679c81d58a003089aa961986937 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -162,9 +162,9 @@ namespace vkcv destroyTemporaryFramebuffers(); } - void Core::renderTriangle(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, + void Core::renderMesh(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, const int width, const int height, const size_t pushConstantSize, const void *pushConstantData, - const BufferHandle vertexBuffer) { + const BufferHandle vertexBuffer, const BufferHandle indexBuffer, const size_t indexCount) { if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { return; @@ -175,7 +175,8 @@ namespace vkcv const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle); const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle); const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); - const vk::Buffer vulkanVertexBuffer = m_BufferManager->getBuffer(vertexBuffer); + const vk::Buffer vulkanVertexBuffer = m_BufferManager->getBuffer(vertexBuffer); + const vk::Buffer vulkanIndexBuffer = m_BufferManager->getBuffer(indexBuffer); const vk::Framebuffer framebuffer = createFramebuffer(m_Context.getDevice(), renderpass, width, height, imageView); m_TemporaryFramebuffers.push_back(framebuffer); @@ -184,7 +185,7 @@ namespace vkcv submitInfo.queueType = QueueType::Graphics; submitInfo.signalSemaphores = { m_SyncResources.renderFinished }; submitCommands(submitInfo, [renderpass, renderArea, imageView, framebuffer, pipeline, pipelineLayout, - pushConstantSize, pushConstantData, vulkanVertexBuffer](const vk::CommandBuffer& cmdBuffer) { + pushConstantSize, pushConstantData, vulkanVertexBuffer, indexCount, vulkanIndexBuffer](const vk::CommandBuffer& cmdBuffer) { const std::array<float, 4> clearColor = { 0.f, 0.f, 0.f, 1.f }; const vk::ClearValue clearValues(clearColor); @@ -196,8 +197,9 @@ namespace vkcv cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); cmdBuffer.bindVertexBuffers(0, (vulkanVertexBuffer), { 0 }); + cmdBuffer.bindIndexBuffer(vulkanIndexBuffer, 0, vk::IndexType::eUint16); //FIXME: choose proper size cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData); - cmdBuffer.draw(3, 1, 0, 0, {}); + cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {}); cmdBuffer.endRenderPass(); }, nullptr); }