1
Fork 0
mirror of https://github.com/redstrate/Novus.git synced 2025-05-14 04:27: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/maplistwidget.h
include/mapview.h
include/objectpass.h
src/main.cpp
src/mainwindow.cpp
src/maplistwidget.cpp
src/mapview.cpp)
src/mapview.cpp
src/objectpass.cpp)
target_include_directories(novus-mapeditor
PUBLIC
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 "filecache.h"
#include "objectpass.h"
MapView::MapView(GameData *data, FileCache &cache, QWidget *parent)
: QWidget(parent)
@ -15,6 +16,9 @@ MapView::MapView(GameData *data, FileCache &cache, QWidget *parent)
{
mdlPart = new MDLPart(data, cache);
mdlPart->enableFreemode();
connect(mdlPart, &MDLPart::initializeRender, this, [this] {
mdlPart->manager()->addPass(new ObjectPass(mdlPart->manager()));
});
auto layout = new QVBoxLayout();
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();
}
RenderManager *MDLPart::manager() const
{
return renderer;
}
#include "moc_mdlpart.cpp"

View file

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

View file

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

View file

@ -22,6 +22,7 @@ target_sources(renderer
include/simplerenderer.h
include/swapchain.h
include/texture.h
include/pass.h
src/device.cpp
src/gamerenderer.cpp
@ -42,7 +43,9 @@ qt_add_resources(renderer
shaders/mesh.vert.spv
shaders/skinned.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_link_libraries(renderer
PUBLIC

View file

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

View file

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

View file

@ -34,6 +34,11 @@ public:
Texture &getCompositeTexture() override;
Device &device() override;
VkFramebuffer framebuffer();
VkRenderPass renderPass();
private:
void initRenderPass();
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 dummy.frag -o dummy.frag.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);
}
}
Device &GameRenderer::device()
{
return m_device;
}

View file

@ -15,6 +15,7 @@
#include "gamerenderer.h"
#include "imgui.h"
#include "imguipass.h"
#include "pass.h"
#include "simplerenderer.h"
#include "swapchain.h"
@ -423,6 +424,13 @@ void RenderManager::render(const std::vector<DrawObject> &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 = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = m_renderPass;
@ -708,3 +716,13 @@ void RenderManager::initBlitPipeline()
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);
}
}
vkCmdEndRenderPass(commandBuffer);
}
void SimpleRenderer::initRenderPass()
@ -569,3 +567,18 @@ Texture &SimpleRenderer::getCompositeTexture()
{
return m_compositeTexture;
}
Device &SimpleRenderer::device()
{
return m_device;
}
VkFramebuffer SimpleRenderer::framebuffer()
{
return m_framebuffer;
}
VkRenderPass SimpleRenderer::renderPass()
{
return m_renderPass;
}