Interaction.. Yay?
This commit is contained in:
parent
3c8e214f6d
commit
cc7678aec6
|
@ -1,4 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
<component name="CidrRootsConfiguration">
|
||||
<excludeRoots>
|
||||
<file path="$PROJECT_DIR$/build" />
|
||||
</excludeRoots>
|
||||
</component>
|
||||
</project>
|
|
@ -6,6 +6,5 @@ set(CMAKE_CXX_STANDARD 20)
|
|||
find_package(Vulkan REQUIRED)
|
||||
find_package(Qt5 COMPONENTS Gui REQUIRED)
|
||||
|
||||
add_executable(VulkanCppSetup src/main.cpp src/VulkanWindow.cpp src/VulkanRenderer.cpp src/ShaderLoader.cpp)
|
||||
#include_directories(VulkanCppSetup ${Vulkan_INCLUDE_DIRS} ${Qt5_INCLUDE_DIRS})
|
||||
add_executable(VulkanCppSetup src/main.cpp src/VulkanWindow.cpp src/VulkanRenderer.cpp src/ShaderLoader.cpp src/WorldView.cpp src/UniformBuffers.cpp src/camera.cpp)
|
||||
target_link_libraries(VulkanCppSetup ${Vulkan_LIBRARIES} Qt5::Gui)
|
||||
|
|
|
@ -1,20 +1,44 @@
|
|||
#version 450
|
||||
|
||||
layout(push_constant) uniform VertexUniformBufferObject {
|
||||
mat4 model;
|
||||
mat4 view;
|
||||
mat4 proj;
|
||||
} ubo;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
|
||||
vec2 positions[3] = vec2[](
|
||||
vec2(0.0, -0.5),
|
||||
vec2(0.5, 0.5),
|
||||
vec2(-0.5, 0.5)
|
||||
vec3 positions[12] = vec3[](
|
||||
vec3(0.0, -1.0, 1.0), // 1
|
||||
vec3(1.0, 1.0, 1.0), // 2
|
||||
vec3(-1.0, 1.0, 1.0), // 3
|
||||
vec3(-1.0, 1.0, 1.0), // 3
|
||||
vec3(0.0, 0.0, -1.0), // 4
|
||||
vec3(0.0, -1.0, 1.0), // 1
|
||||
vec3(0.0, -1.0, 1.0), // 1
|
||||
vec3(0.0, 0.0, -1.0), // 4
|
||||
vec3(1.0, 1.0, 1.0), // 2
|
||||
vec3(1.0, 1.0, 1.0), // 2
|
||||
vec3(0.0, 0.0, -1.0), // 4
|
||||
vec3(-1.0, 1.0, 1.0) // 3
|
||||
);
|
||||
|
||||
vec3 colors[3] = vec3[](
|
||||
vec3 colors[12] = vec3[](
|
||||
vec3(1.0, 0.0, 0.0),
|
||||
vec3(0.0, 1.0, 0.0),
|
||||
vec3(0.0, 0.0, 1.0),
|
||||
vec3(0.0, 0.0, 1.0),
|
||||
vec3(1.0, 1.0, 1.0),
|
||||
vec3(1.0, 0.0, 0.0),
|
||||
vec3(1.0, 0.0, 0.0),
|
||||
vec3(1.0, 1.0, 1.0),
|
||||
vec3(0.0, 1.0, 0.0),
|
||||
vec3(0.0, 1.0, 0.0),
|
||||
vec3(1.0, 1.0, 1.0),
|
||||
vec3(0.0, 0.0, 1.0)
|
||||
);
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
|
||||
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(positions[gl_VertexIndex], 1.0);
|
||||
fragColor = colors[gl_VertexIndex];
|
||||
}
|
||||
|
|
BIN
shaders/vert.spv
BIN
shaders/vert.spv
Binary file not shown.
103
src/UniformBuffers.cpp
Normal file
103
src/UniformBuffers.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include "UniformBuffers.h"
|
||||
#include "VertexUniformBufferObject.h"
|
||||
#include <QVulkanDeviceFunctions>
|
||||
|
||||
/// Find a memory in `memoryTypeBitsRequirement` that includes all of
|
||||
/// `requiredProperties` see
|
||||
/// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMemoryProperties.html
|
||||
int32_t
|
||||
findProperties(const VkPhysicalDeviceMemoryProperties *pMemoryProperties,
|
||||
uint32_t memoryTypeBitsRequirement,
|
||||
VkMemoryPropertyFlags requiredProperties) {
|
||||
const uint32_t memoryCount = pMemoryProperties->memoryTypeCount;
|
||||
for (uint32_t memoryIndex = 0; memoryIndex < memoryCount; ++memoryIndex) {
|
||||
const uint32_t memoryTypeBits = (1 << memoryIndex);
|
||||
const bool isRequiredMemoryType =
|
||||
memoryTypeBitsRequirement & memoryTypeBits;
|
||||
|
||||
const VkMemoryPropertyFlags properties =
|
||||
pMemoryProperties->memoryTypes[memoryIndex].propertyFlags;
|
||||
const bool hasRequiredProperties =
|
||||
(properties & requiredProperties) == requiredProperties;
|
||||
|
||||
if (isRequiredMemoryType && hasRequiredProperties)
|
||||
return static_cast<int32_t>(memoryIndex);
|
||||
}
|
||||
|
||||
// failed to find memory type
|
||||
return -1;
|
||||
}
|
||||
|
||||
void UniformBuffers::createBuffers(QVulkanWindow *window,
|
||||
QVulkanDeviceFunctions *devFuncs) {
|
||||
VkResult result;
|
||||
|
||||
VkDeviceSize bufferSize = sizeof(VertexUniformBufferObject);
|
||||
|
||||
int swapChainImageCount = window->swapChainImageCount();
|
||||
if (!m_uniformBuffers.empty() || !m_uniformBuffersMemory.empty()) {
|
||||
qFatal("Uniform buffers are allocated! Old buffers need to be destroyed.");
|
||||
}
|
||||
m_uniformBuffers.resize(swapChainImageCount);
|
||||
m_uniformBuffersMemory.resize(swapChainImageCount);
|
||||
|
||||
VkBufferCreateInfo bufferCreateInfo{};
|
||||
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferCreateInfo.size = bufferSize;
|
||||
bufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
QVulkanFunctions *pFunctions = window->vulkanInstance()->functions();
|
||||
VkPhysicalDeviceMemoryProperties memProperties;
|
||||
pFunctions->vkGetPhysicalDeviceMemoryProperties(window->physicalDevice(),
|
||||
&memProperties);
|
||||
|
||||
for (size_t i = 0; i < swapChainImageCount; i++) {
|
||||
result = devFuncs->vkCreateBuffer(window->device(), &bufferCreateInfo,
|
||||
VK_NULL_HANDLE, &m_uniformBuffers[i]);
|
||||
if (result != VK_SUCCESS) {
|
||||
qFatal("Failed to create buffer, code %d", result);
|
||||
}
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
devFuncs->vkGetBufferMemoryRequirements(
|
||||
window->device(), m_uniformBuffers[i], &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memRequirements.size;
|
||||
uint32_t requiredProperties{VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT};
|
||||
allocInfo.memoryTypeIndex = findProperties(
|
||||
&memProperties, memRequirements.memoryTypeBits, requiredProperties);
|
||||
|
||||
if (allocInfo.memoryTypeIndex == -1) {
|
||||
qFatal("Unable to find memory type with props %d", requiredProperties);
|
||||
}
|
||||
|
||||
result =
|
||||
devFuncs->vkAllocateMemory(window->device(), &allocInfo, VK_NULL_HANDLE,
|
||||
&m_uniformBuffersMemory[i]);
|
||||
if (result != VK_SUCCESS) {
|
||||
qFatal("Failed to allocate buffer memory, code %d", result);
|
||||
}
|
||||
|
||||
result = devFuncs->vkBindBufferMemory(window->device(), m_uniformBuffers[i],
|
||||
m_uniformBuffersMemory[i], 0);
|
||||
if (result != VK_SUCCESS) {
|
||||
qFatal("Failed to bind buffer memory, code %d", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UniformBuffers::destroyBuffers(QVulkanWindow *window,
|
||||
QVulkanDeviceFunctions *devFuncs) {
|
||||
for (VkBuffer &buffer : m_uniformBuffers) {
|
||||
devFuncs->vkDestroyBuffer(window->device(), buffer, VK_NULL_HANDLE);
|
||||
}
|
||||
m_uniformBuffers.clear();
|
||||
for (VkDeviceMemory &memory : m_uniformBuffersMemory) {
|
||||
devFuncs->vkFreeMemory(window->device(), memory, VK_NULL_HANDLE);
|
||||
}
|
||||
m_uniformBuffersMemory.clear();
|
||||
}
|
23
src/UniformBuffers.h
Normal file
23
src/UniformBuffers.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef VULKANCPPSETUP_UNIFORMBUFFERS_H
|
||||
#define VULKANCPPSETUP_UNIFORMBUFFERS_H
|
||||
|
||||
#include <QVulkanDeviceFunctions>
|
||||
#include <QVulkanWindow>
|
||||
#include <vector>
|
||||
|
||||
// Note: Switched to push constants, but kept this work
|
||||
class UniformBuffers {
|
||||
public:
|
||||
explicit UniformBuffers() = default;
|
||||
~UniformBuffers() = default;
|
||||
|
||||
void createBuffers(QVulkanWindow *window, QVulkanDeviceFunctions *devFuncs);
|
||||
void destroyBuffers(QVulkanWindow *window,
|
||||
QVulkanDeviceFunctions *devFuncs);
|
||||
|
||||
private:
|
||||
std::vector<VkBuffer> m_uniformBuffers{};
|
||||
std::vector<VkDeviceMemory> m_uniformBuffersMemory{};
|
||||
};
|
||||
|
||||
#endif // VULKANCPPSETUP_UNIFORMBUFFERS_H
|
12
src/VertexUniformBufferObject.h
Normal file
12
src/VertexUniformBufferObject.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef VULKANCPPSETUP_VERTEXUNIFORMBUFFEROBJECT_H
|
||||
#define VULKANCPPSETUP_VERTEXUNIFORMBUFFEROBJECT_H
|
||||
|
||||
#include <array>
|
||||
|
||||
struct VertexUniformBufferObject {
|
||||
std::array<float, 16> model;
|
||||
std::array<float, 16> view;
|
||||
std::array<float, 16> proj;
|
||||
};
|
||||
|
||||
#endif // VULKANCPPSETUP_VERTEXUNIFORMBUFFEROBJECT_H
|
|
@ -1,32 +1,38 @@
|
|||
#include "VulkanRenderer.h"
|
||||
#include "VertexUniformBufferObject.h"
|
||||
#include <complex>
|
||||
|
||||
VulkanRenderer::VulkanRenderer(QVulkanWindow *w) : m_window(w) {}
|
||||
VulkanRenderer::VulkanRenderer(QVulkanWindow *window, WorldView *worldView)
|
||||
: m_window(window), m_worldView(worldView) {}
|
||||
|
||||
void VulkanRenderer::initResources() {
|
||||
void VulkanRenderer::createPipeline() {
|
||||
VkResult result;
|
||||
m_devFuncs = m_window->vulkanInstance()->deviceFunctions(m_window->device());
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipelineLayoutInfo.setLayoutCount = 0; // Optional
|
||||
pipelineLayoutInfo.pSetLayouts = nullptr; // Optional
|
||||
pipelineLayoutInfo.pushConstantRangeCount = 0; // Optional
|
||||
pipelineLayoutInfo.pPushConstantRanges = nullptr; // Optional
|
||||
// Note: switched to push constants instead
|
||||
// VkDescriptorSetLayoutBinding uboLayoutBinding{};
|
||||
// uboLayoutBinding.binding = 0;
|
||||
// uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
// uboLayoutBinding.descriptorCount = 1;
|
||||
// uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
//
|
||||
// VkDescriptorSetLayoutCreateInfo layoutInfo{};
|
||||
// layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
// layoutInfo.bindingCount = 1;
|
||||
// layoutInfo.pBindings = &uboLayoutBinding;
|
||||
//
|
||||
// result = m_devFuncs->vkCreateDescriptorSetLayout(
|
||||
// m_window->device(), &layoutInfo, VK_NULL_HANDLE,
|
||||
// &m_descriptorSetLayout);
|
||||
// if (result != VK_SUCCESS) {
|
||||
// qFatal("Failed to create descriptor set layout, code %d", result);
|
||||
// }
|
||||
|
||||
result = m_devFuncs->vkCreatePipelineLayout(
|
||||
m_window->device(), &pipelineLayoutInfo, nullptr, &m_pipelineLayout);
|
||||
if (result != VK_SUCCESS) {
|
||||
qFatal("Failed to create pipeline layout, code: %d", result);
|
||||
}
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
|
||||
vertexInputInfo.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertexInputInfo.vertexBindingDescriptionCount = 0;
|
||||
vertexInputInfo.pVertexBindingDescriptions = nullptr; // Optional
|
||||
vertexInputInfo.vertexAttributeDescriptionCount = 0;
|
||||
vertexInputInfo.pVertexAttributeDescriptions = nullptr; // Optional
|
||||
VkPushConstantRange pushConstant{};
|
||||
pushConstant.offset = 0;
|
||||
// might be too big for some graphics cards, spec requires min 128 bytes (the
|
||||
// validation layer will tell us)
|
||||
pushConstant.size = sizeof(VertexUniformBufferObject);
|
||||
pushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
|
||||
auto shaders =
|
||||
std::array<std::string, 2>{"shaders/vert.spv", "shaders/frag.spv"};
|
||||
|
@ -46,6 +52,30 @@ void VulkanRenderer::initResources() {
|
|||
fragShaderStageInfo.pName = "main";
|
||||
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages{
|
||||
vertShaderStageInfo, fragShaderStageInfo};
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
// Note: switched to push constants instead
|
||||
// pipelineLayoutInfo.setLayoutCount = 1;
|
||||
// pipelineLayoutInfo.pSetLayouts = &m_descriptorSetLayout;
|
||||
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
||||
pipelineLayoutInfo.pPushConstantRanges = &pushConstant;
|
||||
|
||||
result = m_devFuncs->vkCreatePipelineLayout(
|
||||
m_window->device(), &pipelineLayoutInfo, VK_NULL_HANDLE,
|
||||
&m_pipelineLayout);
|
||||
if (result != VK_SUCCESS) {
|
||||
qFatal("Failed to create pipeline layout, code: %d", result);
|
||||
}
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
|
||||
vertexInputInfo.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertexInputInfo.vertexBindingDescriptionCount = 0;
|
||||
vertexInputInfo.pVertexBindingDescriptions = VK_NULL_HANDLE; // Optional
|
||||
vertexInputInfo.vertexAttributeDescriptionCount = 0;
|
||||
vertexInputInfo.pVertexAttributeDescriptions = VK_NULL_HANDLE; // Optional
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo{};
|
||||
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipelineInfo.stageCount = shaderStages.size();
|
||||
|
@ -114,34 +144,55 @@ void VulkanRenderer::initResources() {
|
|||
pipelineInfo.basePipelineIndex = -1; // Optional
|
||||
|
||||
result = m_devFuncs->vkCreateGraphicsPipelines(
|
||||
m_window->device(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr,
|
||||
m_window->device(), VK_NULL_HANDLE, 1, &pipelineInfo, VK_NULL_HANDLE,
|
||||
&m_graphicsPipeline);
|
||||
if (result != VK_SUCCESS) {
|
||||
qFatal("Failed to create graphics pipeline: code %d", result);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderer::initResources() {
|
||||
QVulkanWindowRenderer::initResources();
|
||||
m_devFuncs = m_window->vulkanInstance()->deviceFunctions(m_window->device());
|
||||
createPipeline();
|
||||
}
|
||||
|
||||
void VulkanRenderer::releaseResources() {
|
||||
QVulkanWindowRenderer::releaseResources();
|
||||
m_devFuncs->vkDestroyPipeline(m_window->device(), m_graphicsPipeline,
|
||||
nullptr);
|
||||
VK_NULL_HANDLE);
|
||||
m_devFuncs->vkDestroyPipelineLayout(m_window->device(), m_pipelineLayout,
|
||||
nullptr);
|
||||
VK_NULL_HANDLE);
|
||||
// m_devFuncs->vkDestroyDescriptorSetLayout(
|
||||
// m_window->device(), m_descriptorSetLayout, VK_NULL_HANDLE);
|
||||
m_shaderLoader.destroyShaders(m_window->device(), m_devFuncs);
|
||||
}
|
||||
|
||||
void VulkanRenderer::initSwapChainResources() {
|
||||
QVulkanWindowRenderer::initSwapChainResources();
|
||||
// m_uniformBuffers.createBuffers(m_window, m_devFuncs);
|
||||
m_worldView->initializeProjectionMatrix(m_window);
|
||||
}
|
||||
|
||||
void VulkanRenderer::releaseSwapChainResources() {
|
||||
QVulkanWindowRenderer::releaseSwapChainResources();
|
||||
// m_uniformBuffers.destroyBuffers(m_window, m_devFuncs);
|
||||
}
|
||||
|
||||
void VulkanRenderer::startNextFrame() {
|
||||
VkCommandBuffer cmdBuf = m_window->currentCommandBuffer();
|
||||
|
||||
VkClearDepthStencilValue clearDS = {1, 0};
|
||||
std::array<VkClearValue, 3> clearValue{};
|
||||
float flash = std::abs(std::sin(static_cast<float>(m_frameNumber) / 120.f));
|
||||
float flash =
|
||||
std::abs(std::sin(static_cast<float>(m_frameNumber) / 80.f)) / 2.f;
|
||||
clearValue[0].color = {{0.0f, 0.0f, flash, 1.0f}};
|
||||
clearValue[1].depthStencil = clearDS;
|
||||
clearValue[2].color = clearValue[0].color;
|
||||
|
||||
VkRenderPassBeginInfo rpInfo{};
|
||||
rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
rpInfo.pNext = nullptr;
|
||||
rpInfo.pNext = VK_NULL_HANDLE;
|
||||
|
||||
rpInfo.renderPass = m_window->defaultRenderPass();
|
||||
rpInfo.renderArea.offset.x = 0;
|
||||
|
@ -169,7 +220,12 @@ void VulkanRenderer::startNextFrame() {
|
|||
m_devFuncs->vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
m_graphicsPipeline);
|
||||
|
||||
m_devFuncs->vkCmdDraw(cmdBuf, 3, 1, 0, 0);
|
||||
const VertexUniformBufferObject &mvp = m_worldView->getBufferObject();
|
||||
m_devFuncs->vkCmdPushConstants(cmdBuf, m_pipelineLayout,
|
||||
VK_SHADER_STAGE_VERTEX_BIT, 0,
|
||||
sizeof(VertexUniformBufferObject), &mvp);
|
||||
|
||||
m_devFuncs->vkCmdDraw(cmdBuf, 12, 1, 0, 0);
|
||||
|
||||
m_devFuncs->vkCmdEndRenderPass(cmdBuf);
|
||||
m_window->frameReady();
|
||||
|
|
|
@ -1,26 +1,35 @@
|
|||
#ifndef VULKANCPPSETUP_VULKANRENDERER_H
|
||||
#define VULKANCPPSETUP_VULKANRENDERER_H
|
||||
|
||||
#include "WorldView.h"
|
||||
#include "ShaderLoader.h"
|
||||
#include "UniformBuffers.h"
|
||||
#include <QVulkanWindowRenderer>
|
||||
#include <qvulkanfunctions.h>
|
||||
|
||||
class VulkanRenderer : public QVulkanWindowRenderer {
|
||||
public:
|
||||
explicit VulkanRenderer(QVulkanWindow *w);
|
||||
explicit VulkanRenderer(QVulkanWindow *window, WorldView *worldView);
|
||||
|
||||
void initResources() override;
|
||||
void releaseResources() override;
|
||||
void initSwapChainResources() override;
|
||||
void releaseSwapChainResources() override;
|
||||
|
||||
void startNextFrame() override;
|
||||
|
||||
private:
|
||||
QVulkanWindow *m_window;
|
||||
WorldView *m_worldView;
|
||||
QVulkanDeviceFunctions *m_devFuncs{};
|
||||
unsigned long m_frameNumber{0UL};
|
||||
ShaderLoader m_shaderLoader{};
|
||||
// UniformBuffers m_uniformBuffers{};
|
||||
// VkDescriptorSetLayout m_descriptorSetLayout{};
|
||||
VkPipelineLayout m_pipelineLayout{};
|
||||
VkPipeline m_graphicsPipeline{};
|
||||
|
||||
void createPipeline();
|
||||
};
|
||||
|
||||
#endif // VULKANCPPSETUP_VULKANRENDERER_H
|
||||
|
|
|
@ -3,16 +3,57 @@
|
|||
#include <qevent.h>
|
||||
|
||||
static const int KEY_ESCAPE = 16777216;
|
||||
static const int KEY_W = 87;
|
||||
static const int KEY_A = 65;
|
||||
static const int KEY_S = 83;
|
||||
static const int KEY_D = 68;
|
||||
|
||||
void VulkanWindow::keyPressEvent(QKeyEvent *event) {
|
||||
QWindow::keyPressEvent(event);
|
||||
qDebug() << "text" << event->text() << "key" << event->key() << "modifiers"
|
||||
<< event->modifiers();
|
||||
if (event->matches(QKeySequence::Quit) || event->key() == KEY_ESCAPE) {
|
||||
if (event->key() == KEY_W) {
|
||||
m_worldView.moveCamera(1.f);
|
||||
} else if (event->key() == KEY_S) {
|
||||
m_worldView.moveCamera(-1.f);
|
||||
} else if (event->key() == KEY_A) {
|
||||
m_worldView.strafeCamera(-1.f);
|
||||
} else if (event->key() == KEY_D) {
|
||||
m_worldView.strafeCamera(1.f);
|
||||
} else if (event->matches(QKeySequence::Quit) || event->key() == KEY_ESCAPE) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
QVulkanWindowRenderer *VulkanWindow::createRenderer() {
|
||||
return new VulkanRenderer(this);
|
||||
void VulkanWindow::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
m_mousePressed = true;
|
||||
m_lastMousePos = e->localPos().toPoint();
|
||||
}
|
||||
|
||||
void VulkanWindow::mouseReleaseEvent(QMouseEvent *)
|
||||
{ m_mousePressed = false;
|
||||
}
|
||||
|
||||
void VulkanWindow::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
if (!m_mousePressed)
|
||||
return;
|
||||
|
||||
int dx = e->localPos().toPoint().x() - m_lastMousePos.x();
|
||||
int dy = e->localPos().toPoint().y() - m_lastMousePos.y();
|
||||
|
||||
if (dy) {
|
||||
m_worldView.pitchCamera(static_cast<float>(dy) / 10.0f);
|
||||
}
|
||||
|
||||
if (dx) {
|
||||
m_worldView.yawCamera(static_cast<float>(dx) / 10.0f);
|
||||
}
|
||||
|
||||
m_lastMousePos = e->localPos().toPoint();
|
||||
}
|
||||
|
||||
QVulkanWindowRenderer *VulkanWindow::createRenderer() {
|
||||
return new VulkanRenderer(this, &m_worldView);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
//
|
||||
// Created by ben on 13.01.22.
|
||||
//
|
||||
|
||||
#ifndef VULKANCPPSETUP_VULKANWINDOW_H
|
||||
#define VULKANCPPSETUP_VULKANWINDOW_H
|
||||
|
||||
#include <QVulkanWindow>
|
||||
#include <iostream>
|
||||
#include <qevent.h>
|
||||
#include "WorldView.h"
|
||||
|
||||
class VulkanWindow : public QVulkanWindow {
|
||||
public:
|
||||
|
@ -15,6 +12,14 @@ public:
|
|||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
WorldView m_worldView{};
|
||||
bool m_mousePressed{false};
|
||||
QPoint m_lastMousePos;
|
||||
};
|
||||
|
||||
#endif // VULKANCPPSETUP_VULKANWINDOW_H
|
||||
|
|
43
src/WorldView.cpp
Normal file
43
src/WorldView.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include "WorldView.h"
|
||||
|
||||
WorldView::WorldView() {
|
||||
// m_modelMat.translate(0, 0, -5);
|
||||
// m_modelMat.rotate(-90, 1, 0, 0);
|
||||
// m_modelMat.scale(1.f, 1.f, 1.5f);
|
||||
}
|
||||
|
||||
void WorldView::initializeProjectionMatrix(QVulkanWindow *window) {
|
||||
// m_projectionMat = window->clipCorrectionMatrix();
|
||||
// const QSize sz = window->swapChainImageSize();
|
||||
// m_projectionMat.perspective(
|
||||
// 90.0f, static_cast<float>(sz.width()) / static_cast<float>(sz.height()),
|
||||
// 0.01f, 1000.0f);
|
||||
}
|
||||
|
||||
VertexUniformBufferObject WorldView::getBufferObject() {
|
||||
VertexUniformBufferObject obj{};
|
||||
m_modelMat.copyDataTo(obj.model.data());
|
||||
m_camera.viewMatrix().copyDataTo(obj.view.data());
|
||||
m_projectionMat.copyDataTo(obj.proj.data());
|
||||
return obj;
|
||||
}
|
||||
|
||||
QVector4D WorldView::multiply(const QVector4D &vector) {
|
||||
return m_projectionMat * m_camera.viewMatrix() * m_modelMat * vector;
|
||||
}
|
||||
|
||||
void WorldView::pitchCamera(float degrees) {
|
||||
m_camera.pitch(degrees);
|
||||
}
|
||||
|
||||
void WorldView::yawCamera(float degrees) {
|
||||
m_camera.yaw(degrees);
|
||||
}
|
||||
|
||||
void WorldView::strafeCamera(float amount) {
|
||||
m_camera.strafe(amount);
|
||||
}
|
||||
|
||||
void WorldView::moveCamera(float amount) {
|
||||
m_camera.walk(amount);
|
||||
}
|
26
src/WorldView.h
Normal file
26
src/WorldView.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef VULKANCPPSETUP_WORLDVIEW_H
|
||||
#define VULKANCPPSETUP_WORLDVIEW_H
|
||||
|
||||
#include "camera.h"
|
||||
#include "VertexUniformBufferObject.h"
|
||||
#include <QMatrix4x4>
|
||||
#include <QVulkanWindow>
|
||||
|
||||
class WorldView {
|
||||
public:
|
||||
explicit WorldView();
|
||||
void initializeProjectionMatrix(QVulkanWindow *window);
|
||||
QVector4D multiply(const QVector4D &vector);
|
||||
VertexUniformBufferObject getBufferObject();
|
||||
void pitchCamera(float degrees);
|
||||
void yawCamera(float degrees);
|
||||
void moveCamera(float amount);
|
||||
void strafeCamera(float amount);
|
||||
|
||||
private:
|
||||
QMatrix4x4 m_modelMat{};
|
||||
QMatrix4x4 m_projectionMat{};
|
||||
Camera m_camera{QVector3D{0.f, 0.f, -1.f}};
|
||||
};
|
||||
|
||||
#endif // VULKANCPPSETUP_WORLDVIEW_H
|
112
src/camera.cpp
Normal file
112
src/camera.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** BSD License Usage
|
||||
** Alternatively, you may use this file under the terms of the BSD license
|
||||
** as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "camera.h"
|
||||
|
||||
Camera::Camera(const QVector3D &pos)
|
||||
: m_forward(0.0f, 0.0f, -1.0f),
|
||||
m_right(1.0f, 0.0f, 0.0f),
|
||||
m_up(0.0f, 1.0f, 0.0f),
|
||||
m_pos(pos),
|
||||
m_yaw(0.0f),
|
||||
m_pitch(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void clamp360(float *v)
|
||||
{
|
||||
if (*v > 360.0f)
|
||||
*v -= 360.0f;
|
||||
if (*v < -360.0f)
|
||||
*v += 360.0f;
|
||||
}
|
||||
|
||||
void Camera::yaw(float degrees)
|
||||
{
|
||||
m_yaw += degrees;
|
||||
clamp360(&m_yaw);
|
||||
m_yawMatrix.setToIdentity();
|
||||
m_yawMatrix.rotate(m_yaw, 0, 1, 0);
|
||||
|
||||
QMatrix4x4 rotMat = m_pitchMatrix * m_yawMatrix;
|
||||
m_forward = (QVector4D(0.0f, 0.0f, -1.0f, 0.0f) * rotMat).toVector3D();
|
||||
m_right = (QVector4D(1.0f, 0.0f, 0.0f, 0.0f) * rotMat).toVector3D();
|
||||
}
|
||||
|
||||
void Camera::pitch(float degrees)
|
||||
{
|
||||
m_pitch += degrees;
|
||||
clamp360(&m_pitch);
|
||||
m_pitchMatrix.setToIdentity();
|
||||
m_pitchMatrix.rotate(m_pitch, 1, 0, 0);
|
||||
|
||||
QMatrix4x4 rotMat = m_pitchMatrix * m_yawMatrix;
|
||||
m_forward = (QVector4D(0.0f, 0.0f, -1.0f, 0.0f) * rotMat).toVector3D();
|
||||
m_up = (QVector4D(0.0f, 1.0f, 0.0f, 0.0f) * rotMat).toVector3D();
|
||||
}
|
||||
|
||||
void Camera::walk(float amount)
|
||||
{
|
||||
m_pos[0] += amount * m_forward.x();
|
||||
m_pos[2] += amount * m_forward.z();
|
||||
}
|
||||
|
||||
void Camera::strafe(float amount)
|
||||
{
|
||||
m_pos[0] += amount * m_right.x();
|
||||
m_pos[2] += amount * m_right.z();
|
||||
}
|
||||
|
||||
QMatrix4x4 Camera::viewMatrix() const
|
||||
{
|
||||
QMatrix4x4 m = m_pitchMatrix * m_yawMatrix;
|
||||
m.translate(-m_pos);
|
||||
return m;
|
||||
}
|
80
src/camera.h
Normal file
80
src/camera.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** BSD License Usage
|
||||
** Alternatively, you may use this file under the terms of the BSD license
|
||||
** as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CAMERA_H
|
||||
#define CAMERA_H
|
||||
|
||||
#include <QVector3D>
|
||||
#include <QMatrix4x4>
|
||||
|
||||
class Camera
|
||||
{
|
||||
public:
|
||||
explicit Camera(const QVector3D &pos);
|
||||
|
||||
void yaw(float degrees);
|
||||
void pitch(float degrees);
|
||||
void walk(float amount);
|
||||
void strafe(float amount);
|
||||
|
||||
[[nodiscard]] QMatrix4x4 viewMatrix() const;
|
||||
|
||||
private:
|
||||
QVector3D m_forward;
|
||||
QVector3D m_right;
|
||||
QVector3D m_up;
|
||||
QVector3D m_pos;
|
||||
float m_yaw;
|
||||
float m_pitch;
|
||||
QMatrix4x4 m_yawMatrix;
|
||||
QMatrix4x4 m_pitchMatrix;
|
||||
};
|
||||
|
||||
#endif
|
10
src/main.cpp
10
src/main.cpp
|
@ -6,11 +6,15 @@ int main(int argc, char **argv) {
|
|||
QGuiApplication app(argc, argv);
|
||||
|
||||
QVulkanInstance inst;
|
||||
QByteArrayList layers{"VK_LAYER_LUNARG_standard_validation"};
|
||||
QByteArrayList layers{"VK_LAYER_KHRONOS_validation"};
|
||||
inst.setLayers(layers);
|
||||
if (!inst.create()) {
|
||||
qFatal("Could not create Vulkan instance %d", inst.errorCode());
|
||||
return EXIT_FAILURE;
|
||||
qFatal("Could not create Vulkan instance, code %d", inst.errorCode());
|
||||
}
|
||||
for (const auto& layer : layers) {
|
||||
if (!inst.layers().contains(layer)) {
|
||||
qFatal("Layer not available: %s", layer.toStdString().c_str());
|
||||
}
|
||||
}
|
||||
VulkanWindow window{};
|
||||
window.setVulkanInstance(&inst);
|
||||
|
|
Loading…
Reference in a new issue