1
Fork 0
mirror of https://github.com/redstrate/Novus.git synced 2025-05-14 12:37:46 +00:00

Begin adding support for drawing additional objects in the renderer

This will be used in the map editor to draw where objects are. It
doesn't draw anything yet, and can't until we get LGB support in
libphysis.
This commit is contained in:
Joshua Goins 2025-05-13 15:19:11 -04:00
parent 442a13a612
commit 93bb7fec43
28 changed files with 304 additions and 5 deletions

View file

@ -7,11 +7,13 @@ target_sources(novus-mapeditor
include/mainwindow.h include/mainwindow.h
include/maplistwidget.h include/maplistwidget.h
include/mapview.h include/mapview.h
include/objectpass.h
src/main.cpp src/main.cpp
src/mainwindow.cpp src/mainwindow.cpp
src/maplistwidget.cpp src/maplistwidget.cpp
src/mapview.cpp) src/mapview.cpp
src/objectpass.cpp)
target_include_directories(novus-mapeditor target_include_directories(novus-mapeditor
PUBLIC PUBLIC
include) include)

View file

@ -0,0 +1,26 @@
#pragma once
#include "pass.h"
#include <glm/glm.hpp>
#include <vulkan/vulkan.h>
class RenderManager;
class Device;
class ObjectPass : public RendererPass
{
public:
ObjectPass(RenderManager *renderer);
void render(VkCommandBuffer commandBuffer, Camera &camera) override;
private:
void createPipeline();
VkPipeline pipeline_ = nullptr;
VkPipelineLayout pipelineLayout_ = nullptr;
RenderManager *m_renderer;
Device &m_device;
};

View file

@ -7,6 +7,7 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include "filecache.h" #include "filecache.h"
#include "objectpass.h"
MapView::MapView(GameData *data, FileCache &cache, QWidget *parent) MapView::MapView(GameData *data, FileCache &cache, QWidget *parent)
: QWidget(parent) : QWidget(parent)
@ -15,6 +16,9 @@ MapView::MapView(GameData *data, FileCache &cache, QWidget *parent)
{ {
mdlPart = new MDLPart(data, cache); mdlPart = new MDLPart(data, cache);
mdlPart->enableFreemode(); mdlPart->enableFreemode();
connect(mdlPart, &MDLPart::initializeRender, this, [this] {
mdlPart->manager()->addPass(new ObjectPass(mdlPart->manager()));
});
auto layout = new QVBoxLayout(); auto layout = new QVBoxLayout();
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);

View file

@ -0,0 +1,162 @@
#include "objectpass.h"
#include "device.h"
#include "rendermanager.h"
#include "simplerenderer.h"
#include "swapchain.h"
#include <glm/gtc/matrix_transform.hpp>
ObjectPass::ObjectPass(RenderManager *renderer)
: m_renderer(renderer)
, m_device(m_renderer->device())
{
createPipeline();
}
void ObjectPass::render(VkCommandBuffer commandBuffer, Camera &camera)
{
if (auto renderer = dynamic_cast<SimpleRenderer *>(m_renderer->renderer())) {
} else {
qWarning() << "Can't render object pass in non-simple renderer for now!!";
}
/*VkClearValue clearValue = {};
clearValue.color = {0.0f, 0.0f, 0.0f, 0.0f};
VkRenderPassBeginInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = m_renderPass;
renderPassInfo.framebuffer = target->sobelFramebuffers[target->currentResource];
renderPassInfo.renderArea.extent = target->extent;
renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &clearValue;
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_);
if(extraInfo != nullptr) {
for (auto mesh: collection.meshes) {
bool shouldRender = false;
for (int i = 0; i < extraInfo->numSelectedEntities; i++) {
if (extraInfo->selectedEntities[i] == mesh.entity)
shouldRender = true;
}
if (shouldRender) {
glm::mat4 mvp;
mvp = glm::perspective(glm::radians(collection.camera.camera->fov),
(float) target->extent.width / target->extent.height,
collection.camera.camera->near, collection.camera.camera->far);
mvp *= glm::lookAt(collection.camera.transform->position, collection.camera.camera->target,
glm::vec3(0, -1, 0));
mvp = glm::translate(mvp, mesh.transform->position);
vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4),
&mvp);
const VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &mesh.mesh->mesh->vertexBuffer, offsets);
vkCmdBindIndexBuffer(commandBuffer, mesh.mesh->mesh->indexBuffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(commandBuffer, mesh.mesh->mesh->indices.size(), 1, 0, 0, 0);
}
}
}
vkCmdEndRenderPass(commandBuffer);*/
}
void ObjectPass::createPipeline()
{
VkPipelineShaderStageCreateInfo vertexShaderStageInfo = {};
vertexShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertexShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertexShaderStageInfo.module = m_device.loadShaderFromDisk(":/shaders/debug.vert.spv");
vertexShaderStageInfo.pName = "main";
VkPipelineShaderStageCreateInfo fragmentShaderStageInfo = {};
fragmentShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragmentShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
fragmentShaderStageInfo.module = m_device.loadShaderFromDisk(":/shaders/debug.vert.spv");
fragmentShaderStageInfo.pName = "main";
const std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = {vertexShaderStageInfo, fragmentShaderStageInfo};
VkVertexInputBindingDescription vertexBindingDescription = {};
vertexBindingDescription.stride = sizeof(Vertex);
VkVertexInputAttributeDescription positionAttributeDescription = {};
positionAttributeDescription.format = VK_FORMAT_R32G32B32_SFLOAT;
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDescription;
vertexInputInfo.vertexAttributeDescriptionCount = 1;
vertexInputInfo.pVertexAttributeDescriptions = &positionAttributeDescription;
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkPipelineViewportStateCreateInfo viewportState = {};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.scissorCount = 1;
VkPipelineRasterizationStateCreateInfo rasterizer = {};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer.cullMode = VK_CULL_MODE_NONE;
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizer.lineWidth = 1.0f;
VkPipelineMultisampleStateCreateInfo multisampling = {};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
VkPipelineColorBlendStateCreateInfo colorBlending = {};
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.attachmentCount = 1;
colorBlending.pAttachments = &colorBlendAttachment;
const std::array<VkDynamicState, 2> dynamicStates = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
VkPipelineDynamicStateCreateInfo dynamicState = {};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.dynamicStateCount = dynamicStates.size();
dynamicState.pDynamicStates = dynamicStates.data();
VkPushConstantRange pushConstant = {};
pushConstant.size = sizeof(glm::mat4);
pushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.pushConstantRangeCount = 1;
pipelineLayoutInfo.pPushConstantRanges = &pushConstant;
vkCreatePipelineLayout(m_device.device, &pipelineLayoutInfo, nullptr, &pipelineLayout_);
auto renderer = dynamic_cast<SimpleRenderer *>(m_renderer->renderer());
VkGraphicsPipelineCreateInfo pipelineInfo = {};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = shaderStages.size();
pipelineInfo.pStages = shaderStages.data();
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &inputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = &dynamicState;
pipelineInfo.layout = pipelineLayout_;
pipelineInfo.renderPass = renderer->renderPass();
vkCreateGraphicsPipelines(m_device.device, nullptr, 1, &pipelineInfo, nullptr, &pipeline_);
}

View file

@ -423,4 +423,9 @@ int MDLPart::numModels() const
return models.size(); return models.size();
} }
RenderManager *MDLPart::manager() const
{
return renderer;
}
#include "moc_mdlpart.cpp" #include "moc_mdlpart.cpp"

View file

@ -49,6 +49,8 @@ public:
int numModels() const; int numModels() const;
RenderManager *manager() const;
physis_PBD pbd{}; physis_PBD pbd{};
bool enableRacialDeform = true; bool enableRacialDeform = true;
@ -56,6 +58,8 @@ public:
Q_SIGNALS: Q_SIGNALS:
void modelChanged(); void modelChanged();
void skeletonChanged(); void skeletonChanged();
// Called when a Vulkan context is available, and you can safely access RenderManager
void initializeRender();
public Q_SLOTS: public Q_SLOTS:
/// Clears all stored MDLs. /// Clears all stored MDLs.

View file

@ -25,6 +25,7 @@ void VulkanWindow::exposeEvent(QExposeEvent *)
auto surface = m_instance->surfaceForWindow(this); auto surface = m_instance->surfaceForWindow(this);
if (!m_renderer->initSwapchain(surface, width() * screen()->devicePixelRatio(), height() * screen()->devicePixelRatio())) { if (!m_renderer->initSwapchain(surface, width() * screen()->devicePixelRatio(), height() * screen()->devicePixelRatio())) {
Q_EMIT part->initializeRender();
m_initialized = false; m_initialized = false;
} else { } else {
render(); render();

View file

@ -22,6 +22,7 @@ target_sources(renderer
include/simplerenderer.h include/simplerenderer.h
include/swapchain.h include/swapchain.h
include/texture.h include/texture.h
include/pass.h
src/device.cpp src/device.cpp
src/gamerenderer.cpp src/gamerenderer.cpp
@ -42,7 +43,9 @@ qt_add_resources(renderer
shaders/mesh.vert.spv shaders/mesh.vert.spv
shaders/skinned.vert.spv shaders/skinned.vert.spv
shaders/blit.vert.spv shaders/blit.vert.spv
shaders/blit.frag.spv) shaders/blit.frag.spv
shaders/debug.vert.spv
shaders/debug.frag.spv)
target_include_directories(renderer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(renderer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(renderer target_link_libraries(renderer
PUBLIC PUBLIC

View file

@ -18,6 +18,8 @@ struct DrawObject;
struct Camera; struct Camera;
struct Texture; struct Texture;
struct Scene; struct Scene;
class Pass;
class Device;
/// Base class for all rendering implementations /// Base class for all rendering implementations
class BaseRenderer class BaseRenderer
@ -33,4 +35,6 @@ public:
/// The final composite texture that is drawn into with render() /// The final composite texture that is drawn into with render()
virtual Texture &getCompositeTexture() = 0; virtual Texture &getCompositeTexture() = 0;
virtual Device &device() = 0;
}; };

View file

@ -35,6 +35,8 @@ public:
Texture &getCompositeTexture() override; Texture &getCompositeTexture() override;
Device &device() override;
private: private:
struct RequestedBinding { struct RequestedBinding {
VkDescriptorType type; VkDescriptorType type;

11
renderer/include/pass.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include <vulkan/vulkan.h>
class Camera;
class RendererPass
{
public:
virtual void render(VkCommandBuffer commandBuffer, Camera &camera) = 0;
};

View file

@ -20,6 +20,7 @@
class ImGuiPass; class ImGuiPass;
struct ImGuiContext; struct ImGuiContext;
class BaseRenderer; class BaseRenderer;
class RendererPass;
/// Render 3D scenes made up of FFXIV game objects /// Render 3D scenes made up of FFXIV game objects
class RenderManager class RenderManager
@ -49,6 +50,10 @@ public:
VkSampler defaultSampler(); VkSampler defaultSampler();
void addPass(RendererPass *pass);
BaseRenderer *renderer();
private: private:
void updateCamera(Camera &camera); void updateCamera(Camera &camera);
void initBlitPipeline(); void initBlitPipeline();
@ -68,4 +73,5 @@ private:
Device *m_device = nullptr; Device *m_device = nullptr;
BaseRenderer *m_renderer = nullptr; BaseRenderer *m_renderer = nullptr;
GameData *m_data = nullptr; GameData *m_data = nullptr;
std::vector<RendererPass *> m_passes;
}; };

View file

@ -34,6 +34,11 @@ public:
Texture &getCompositeTexture() override; Texture &getCompositeTexture() override;
Device &device() override;
VkFramebuffer framebuffer();
VkRenderPass renderPass();
private: private:
void initRenderPass(); void initRenderPass();
void initPipeline(); void initPipeline();

Binary file not shown.

Binary file not shown.

View file

@ -9,4 +9,6 @@ glslc imgui.vert -o imgui.vert.spv &&
glslc imgui.frag -o imgui.frag.spv && glslc imgui.frag -o imgui.frag.spv &&
glslc dummy.frag -o dummy.frag.spv && glslc dummy.frag -o dummy.frag.spv &&
glslc blit.vert -o blit.vert.spv && glslc blit.vert -o blit.vert.spv &&
glslc blit.frag -o blit.frag.spv glslc blit.frag -o blit.frag.spv &&
glslc debug.vert -o debug.vert.spv &&
glslc debug.frag -o debug.frag.spv

View file

@ -0,0 +1,10 @@
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: CC0-1.0
#version 450
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(1, 0, 0, 1);
}

Binary file not shown.

View file

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: CC0-1.0
#version 450
layout(location = 0) in vec3 inPosition;
layout(std430, push_constant) uniform PushConstant {
mat4 vp, model;
};
void main() {
vec4 bPos = model * vec4(inPosition, 1.0);
gl_Position = vp * bPos;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1498,3 +1498,8 @@ void GameRenderer::bindDescriptorSets(VkCommandBuffer commandBuffer,
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipelineLayout, i, 1, &pipeline.cachedDescriptors[i], 0, nullptr); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipelineLayout, i, 1, &pipeline.cachedDescriptors[i], 0, nullptr);
} }
} }
Device &GameRenderer::device()
{
return m_device;
}

View file

@ -15,6 +15,7 @@
#include "gamerenderer.h" #include "gamerenderer.h"
#include "imgui.h" #include "imgui.h"
#include "imguipass.h" #include "imguipass.h"
#include "pass.h"
#include "simplerenderer.h" #include "simplerenderer.h"
#include "swapchain.h" #include "swapchain.h"
@ -423,6 +424,13 @@ void RenderManager::render(const std::vector<DrawObject> &models)
m_renderer->render(commandBuffer, camera, scene, models); m_renderer->render(commandBuffer, camera, scene, models);
// render extra passes
for (const auto &pass : m_passes) {
pass->render(commandBuffer, camera);
}
vkCmdEndRenderPass(commandBuffer);
VkRenderPassBeginInfo renderPassInfo = {}; VkRenderPassBeginInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = m_renderPass; renderPassInfo.renderPass = m_renderPass;
@ -708,3 +716,13 @@ void RenderManager::initBlitPipeline()
vkUpdateDescriptorSets(m_device->device, 1, &multiDescriptorWrite2, 0, nullptr); vkUpdateDescriptorSets(m_device->device, 1, &multiDescriptorWrite2, 0, nullptr);
} }
void RenderManager::addPass(RendererPass *pass)
{
m_passes.push_back(pass);
}
BaseRenderer *RenderManager::renderer()
{
return m_renderer;
}

View file

@ -161,8 +161,6 @@ void SimpleRenderer::render(VkCommandBuffer commandBuffer, Camera &camera, Scene
vkCmdDrawIndexed(commandBuffer, part.numIndices, 1, 0, 0, 0); vkCmdDrawIndexed(commandBuffer, part.numIndices, 1, 0, 0, 0);
} }
} }
vkCmdEndRenderPass(commandBuffer);
} }
void SimpleRenderer::initRenderPass() void SimpleRenderer::initRenderPass()
@ -569,3 +567,18 @@ Texture &SimpleRenderer::getCompositeTexture()
{ {
return m_compositeTexture; return m_compositeTexture;
} }
Device &SimpleRenderer::device()
{
return m_device;
}
VkFramebuffer SimpleRenderer::framebuffer()
{
return m_framebuffer;
}
VkRenderPass SimpleRenderer::renderPass()
{
return m_renderPass;
}