mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 16:16:16 +03:00
654 lines
26 KiB
C++
654 lines
26 KiB
C++
#include "../renderer_interface.h"
|
|
#include "../render_scene.h"
|
|
#include "../renderer.h"
|
|
#include "../scene_textures.h"
|
|
|
|
namespace engine
|
|
{
|
|
|
|
struct PMXSDSMPushConsts
|
|
{
|
|
math::mat4 modelMatrix;
|
|
uint32_t colorTexId;
|
|
uint32_t cascadeId;
|
|
};
|
|
|
|
|
|
class PMXPass : public PassInterface
|
|
{
|
|
public:
|
|
VkDescriptorSetLayout frameDataSetLayout = VK_NULL_HANDLE;
|
|
std::unique_ptr<GraphicPipeResources> pmxPass;
|
|
std::unique_ptr<GraphicPipeResources> pmxOutlinePass;
|
|
std::unique_ptr<GraphicPipeResources> pmxTranslucencyPass;
|
|
|
|
protected:
|
|
virtual void onInit() override
|
|
{
|
|
{
|
|
getContext()->descriptorFactoryBegin()
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, kCommonShaderStage, 0) // frameData
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, kCommonShaderStage, 1) // frameData
|
|
.bindNoInfo(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, kCommonShaderStage, 2) // frameData
|
|
.buildNoInfoPush(frameDataSetLayout);
|
|
|
|
std::vector<VkDescriptorSetLayout> commonLayouts =
|
|
{
|
|
frameDataSetLayout,
|
|
getContext()->getSamplerCache().getCommonDescriptorSetLayout(),
|
|
getRenderer()->getBlueNoise().spp_1_buffer.setLayouts,
|
|
getContext()->getBindlessTextureSetLayout(),
|
|
getContext()->getBindlessSSBOSetLayout()
|
|
, getContext()->getBindlessSSBOSetLayout(),
|
|
getContext()->getDynamicUniformBuffers().getSetlayout(),
|
|
|
|
};
|
|
|
|
pmxPass = std::make_unique<GraphicPipeResources>(
|
|
"shader/pmx_gbuffer.vert.spv",
|
|
"shader/pmx_gbuffer.frag.spv",
|
|
commonLayouts,
|
|
0,
|
|
std::vector<VkFormat>
|
|
{
|
|
GBufferTextures::hdrSceneColorFormat(),
|
|
GBufferTextures::gbufferAFormat(),
|
|
GBufferTextures::gbufferBFormat(),
|
|
GBufferTextures::gbufferSFormat(),
|
|
GBufferTextures::gbufferVFormat(),
|
|
GBufferTextures::getIdTextureFormat(),
|
|
GBufferTextures::gbufferUpscaleReactiveFormat(),
|
|
GBufferTextures::gbufferUpscaleTranslucencyAndCompositionFormat(),
|
|
},
|
|
std::vector<VkPipelineColorBlendAttachmentState>
|
|
{
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
},
|
|
GBufferTextures::depthTextureFormat());
|
|
|
|
pmxOutlinePass = std::make_unique<GraphicPipeResources>(
|
|
"shader/pmx_outline_depth.vert.spv",
|
|
"shader/pmx_outline_depth.frag.spv",
|
|
commonLayouts,
|
|
0,
|
|
std::vector<VkFormat>
|
|
{
|
|
GBufferTextures::hdrSceneColorFormat(),
|
|
GBufferTextures::gbufferVFormat(),
|
|
},
|
|
std::vector<VkPipelineColorBlendAttachmentState>
|
|
{
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
},
|
|
GBufferTextures::depthTextureFormat(),
|
|
VK_CULL_MODE_BACK_BIT);
|
|
|
|
// Translucency blend.
|
|
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
|
|
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
colorBlendAttachment.blendEnable = VK_TRUE;
|
|
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
|
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
|
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
|
|
pmxTranslucencyPass = std::make_unique<GraphicPipeResources>(
|
|
"shader/pmx_translucency.vert.spv",
|
|
"shader/pmx_translucency.frag.spv",
|
|
commonLayouts,
|
|
0,
|
|
std::vector<VkFormat>
|
|
{
|
|
GBufferTextures::hdrSceneColorFormat(),
|
|
GBufferTextures::gbufferUpscaleReactiveFormat(),
|
|
GBufferTextures::gbufferUpscaleTranslucencyAndCompositionFormat(),
|
|
GBufferTextures::getIdTextureFormat(),
|
|
GBufferTextures::gbufferVFormat(),
|
|
},
|
|
std::vector<VkPipelineColorBlendAttachmentState>
|
|
{
|
|
colorBlendAttachment,
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
RHIColorBlendAttachmentOpauqeState(),
|
|
},
|
|
GBufferTextures::depthTextureFormat(),
|
|
VK_CULL_MODE_NONE,
|
|
VK_COMPARE_OP_GREATER,
|
|
false,
|
|
false,
|
|
std::vector<VkVertexInputAttributeDescription>{},
|
|
0,
|
|
VK_POLYGON_MODE_FILL,
|
|
false);
|
|
}
|
|
}
|
|
|
|
virtual void release() override
|
|
{
|
|
pmxPass.reset();
|
|
pmxTranslucencyPass.reset();
|
|
pmxOutlinePass.reset();
|
|
}
|
|
};
|
|
|
|
void RendererInterface::renderPMXTranslucent(
|
|
VkCommandBuffer cmd,
|
|
GBufferTextures* inGBuffers,
|
|
RenderScene* scene,
|
|
BufferParameterHandle perFrameGPU)
|
|
{
|
|
if (!scene->isPMXExist())
|
|
{
|
|
return;
|
|
}
|
|
auto* pass = m_context->getPasses().get<PMXPass>();
|
|
auto& hdrSceneColor = inGBuffers->hdrSceneColor->getImage();
|
|
auto& sceneDepthZ = inGBuffers->depthTexture->getImage();
|
|
auto& gbufferComposition = inGBuffers->gbufferUpscaleTranslucencyAndComposition->getImage();
|
|
auto& gbufferUpscaleMask = inGBuffers->gbufferUpscaleReactive->getImage();
|
|
auto& idTexture = inGBuffers->idTexture->getImage();
|
|
auto& selectionMask = inGBuffers->selectionOutlineMask->getImage();
|
|
auto& gbufferV = inGBuffers->gbufferV->getImage();
|
|
|
|
selectionMask.transitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
hdrSceneColor.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
sceneDepthZ.transitionLayout(cmd, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT));
|
|
gbufferComposition.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferUpscaleMask.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
idTexture.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferV.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
|
|
std::vector<VkRenderingAttachmentInfo> colorAttachments = ColorAttachmentsBuilder()
|
|
.add(hdrSceneColor, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.add(gbufferUpscaleMask, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.add(gbufferComposition, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.add(idTexture, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.add(gbufferV, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.result;
|
|
|
|
VkRenderingAttachmentInfo depthAttachment = getDepthAttachment(sceneDepthZ, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE);
|
|
{
|
|
ScopeRenderCmdObject renderCmdScope(cmd, "PMX translucent", sceneDepthZ, colorAttachments, depthAttachment);
|
|
pass->pmxTranslucencyPass->bind(cmd);
|
|
|
|
PushSetBuilder(cmd)
|
|
.addBuffer(perFrameGPU)
|
|
.addUAV(selectionMask)
|
|
.addSRV(m_averageLum ? m_averageLum->getImage() : getContext()->getEngineTextureWhite()->getImage())
|
|
.push(pass->pmxTranslucencyPass.get());
|
|
|
|
pass->pmxTranslucencyPass->bindSet(cmd, std::vector<VkDescriptorSet>
|
|
{
|
|
getContext()->getSamplerCache().getCommonDescriptorSet(),
|
|
getRenderer()->getBlueNoise().spp_1_buffer.set,
|
|
getContext()->getBindlessTextureSet(),
|
|
m_context->getBindlessSSBOSet()
|
|
, m_context->getBindlessSSBOSet()
|
|
}, 1);
|
|
|
|
const auto& pmxes = scene->getPMXes();
|
|
for (const auto& pmx : pmxes)
|
|
{
|
|
pmx.lock()->onRenderCollect(this, cmd, pass->pmxTranslucencyPass->pipelineLayout, true);
|
|
}
|
|
|
|
}
|
|
|
|
selectionMask.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
hdrSceneColor.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
sceneDepthZ.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT));
|
|
gbufferComposition.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferUpscaleMask.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
idTexture.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferV.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
|
|
m_gpuTimer.getTimeStamp(cmd, "pmx translucent");
|
|
}
|
|
|
|
void RendererInterface::renderPMXGbuffer(
|
|
VkCommandBuffer cmd,
|
|
GBufferTextures* inGBuffers,
|
|
RenderScene* scene,
|
|
BufferParameterHandle perFrameGPU)
|
|
{
|
|
if (!scene->isPMXExist())
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto* pass = m_context->getPasses().get<PMXPass>();
|
|
|
|
auto& hdrSceneColor = inGBuffers->hdrSceneColor->getImage();
|
|
auto& gbufferA = inGBuffers->gbufferA->getImage();
|
|
auto& gbufferB = inGBuffers->gbufferB->getImage();
|
|
auto& gbufferS = inGBuffers->gbufferS->getImage();
|
|
auto& gbufferV = inGBuffers->gbufferV->getImage();
|
|
auto& sceneDepthZ = inGBuffers->depthTexture->getImage();
|
|
auto& gbufferComposition = inGBuffers->gbufferUpscaleTranslucencyAndComposition->getImage();
|
|
auto& gbufferUpscaleMask = inGBuffers->gbufferUpscaleReactive->getImage();
|
|
auto& idTexture = inGBuffers->idTexture->getImage();
|
|
auto& selectionMask = inGBuffers->selectionOutlineMask->getImage();
|
|
|
|
selectionMask.transitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
hdrSceneColor.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferA.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferB.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferS.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferV.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
sceneDepthZ.transitionLayout(cmd, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT));
|
|
gbufferComposition.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferUpscaleMask.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
idTexture.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
|
|
std::vector<VkRenderingAttachmentInfo> colorAttachments = ColorAttachmentsBuilder()
|
|
.add(hdrSceneColor, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.add(gbufferA, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.add(gbufferB, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.add(gbufferS, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.add(gbufferV, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.add(idTexture, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.add(gbufferUpscaleMask, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.add(gbufferComposition, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.result;
|
|
VkRenderingAttachmentInfo depthAttachment = getDepthAttachment(sceneDepthZ, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE);
|
|
|
|
{
|
|
ScopeRenderCmdObject renderCmdScope(cmd, "PMXGBuffer", sceneDepthZ, colorAttachments, depthAttachment);
|
|
pass->pmxPass->bind(cmd);
|
|
|
|
PushSetBuilder(cmd)
|
|
.addBuffer(perFrameGPU)
|
|
.addUAV(selectionMask)
|
|
.addSRV(m_averageLum ? m_averageLum->getImage() : getContext()->getEngineTextureWhite()->getImage())
|
|
.push(pass->pmxPass.get());
|
|
|
|
pass->pmxPass->bindSet(cmd, std::vector<VkDescriptorSet>
|
|
{
|
|
getContext()->getSamplerCache().getCommonDescriptorSet(),
|
|
getRenderer()->getBlueNoise().spp_1_buffer.set,
|
|
getContext()->getBindlessTextureSet(),
|
|
m_context->getBindlessSSBOSet()
|
|
, m_context->getBindlessSSBOSet()
|
|
}, 1);
|
|
|
|
const auto& pmxes = scene->getPMXes();
|
|
for (const auto& pmx : pmxes)
|
|
{
|
|
pmx.lock()->onRenderCollect(this, cmd, pass->pmxPass->pipelineLayout, false);
|
|
}
|
|
|
|
}
|
|
|
|
selectionMask.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
hdrSceneColor.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferA.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferB.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferS.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferV.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
sceneDepthZ.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT));
|
|
gbufferComposition.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferUpscaleMask.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
idTexture.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
|
|
m_gpuTimer.getTimeStamp(cmd, "pmx gbuffer");
|
|
}
|
|
|
|
void RendererInterface::renderPMXOutline(VkCommandBuffer cmd, GBufferTextures* inGBuffers, RenderScene* scene, BufferParameterHandle perFrameGPU)
|
|
{
|
|
if (!scene->isPMXExist())
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto* pass = m_context->getPasses().get<PMXPass>();
|
|
|
|
auto& hdrSceneColor = inGBuffers->hdrSceneColor->getImage();
|
|
auto& gbufferV = inGBuffers->gbufferV->getImage();
|
|
auto& sceneDepthZ = inGBuffers->depthTexture->getImage();
|
|
auto& selectionMask = inGBuffers->selectionOutlineMask->getImage();
|
|
|
|
selectionMask.transitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
hdrSceneColor.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferV.transitionLayout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
sceneDepthZ.transitionLayout(cmd, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT));
|
|
|
|
std::vector<VkRenderingAttachmentInfo> colorAttachments = ColorAttachmentsBuilder()
|
|
.add(hdrSceneColor, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.add(gbufferV, VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
.result;
|
|
VkRenderingAttachmentInfo depthAttachment = getDepthAttachment(sceneDepthZ, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE);
|
|
|
|
|
|
|
|
{
|
|
ScopeRenderCmdObject renderCmdScope(cmd, "PMXOutline", sceneDepthZ, colorAttachments, depthAttachment);
|
|
pass->pmxOutlinePass->bind(cmd);
|
|
|
|
PushSetBuilder(cmd)
|
|
.addBuffer(perFrameGPU)
|
|
.addUAV(selectionMask)
|
|
.addSRV(m_averageLum ? m_averageLum->getImage() : getContext()->getEngineTextureWhite()->getImage())
|
|
.push(pass->pmxOutlinePass.get());
|
|
|
|
pass->pmxOutlinePass->bindSet(cmd, std::vector<VkDescriptorSet>
|
|
{
|
|
getContext()->getSamplerCache().getCommonDescriptorSet(),
|
|
getRenderer()->getBlueNoise().spp_1_buffer.set,
|
|
getContext()->getBindlessTextureSet(),
|
|
m_context->getBindlessSSBOSet()
|
|
, m_context->getBindlessSSBOSet()
|
|
}, 1);
|
|
|
|
const auto& pmxes = scene->getPMXes();
|
|
for (const auto& pmx : pmxes)
|
|
{
|
|
pmx.lock()->onRenderCollect(this, cmd, pass->pmxOutlinePass->pipelineLayout, false);
|
|
}
|
|
|
|
}
|
|
|
|
selectionMask.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
hdrSceneColor.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
gbufferV.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT));
|
|
sceneDepthZ.transitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, RHIDefaultImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT));
|
|
|
|
m_gpuTimer.getTimeStamp(cmd, "pmx outline");
|
|
}
|
|
|
|
|
|
void PMXComponent::onRenderCollect(
|
|
RendererInterface* renderer,
|
|
VkCommandBuffer cmd,
|
|
VkPipelineLayout pipelinelayout,
|
|
bool bTranslucentPass)
|
|
{
|
|
if (!m_proxy || !m_proxy->isInit())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (auto node = m_node.lock())
|
|
{
|
|
const auto& modelMatrix = node->getTransform()->getWorldMatrix();
|
|
const auto& modelMatrixPrev = node->getTransform()->getPrevWorldMatrix();
|
|
|
|
m_proxy->onRenderCollect(
|
|
renderer, cmd, pipelinelayout, modelMatrix, modelMatrixPrev, bTranslucentPass, node->getId(),
|
|
Editor::get()->getSceneNodeSelections().isSelected(SceneNodeSelctor(getNode())));
|
|
}
|
|
}
|
|
|
|
|
|
void PMXComponent::onRenderTick(const RuntimeModuleTickData& tickData, VkCommandBuffer cmd,
|
|
std::vector<GPUStaticMeshPerObjectData>& collector, std::vector<VkAccelerationStructureInstanceKHR>& asInstances)
|
|
{
|
|
m_dtSum += tickData.deltaTime;
|
|
|
|
if (!m_proxy) { return; }
|
|
if (!m_proxy->isInit()) { return; }
|
|
|
|
if (auto node = m_node.lock())
|
|
{
|
|
const auto& modelMatrix = node->getTransform()->getWorldMatrix();
|
|
const auto& modelMatrixPrev = node->getTransform()->getPrevWorldMatrix();
|
|
|
|
// if (m_dtSum > kDt)
|
|
{
|
|
m_proxy->updateAnimation(tickData.gameTime, tickData.deltaTime);
|
|
|
|
m_proxy->updateVertex(cmd);
|
|
|
|
if (getContext()->getGraphicsCardState().bSupportRaytrace)
|
|
{
|
|
m_proxy->updateBLAS(cmd);
|
|
}
|
|
|
|
m_dtSum = 0.0f;
|
|
}
|
|
|
|
m_proxy->collectObjectInfos(collector, asInstances, node->getId(), Editor::get()->getSceneNodeSelections().isSelected(SceneNodeSelctor(getNode())),
|
|
modelMatrix, modelMatrixPrev);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void PMXMeshProxy::onRenderCollect(
|
|
RendererInterface* renderer,
|
|
VkCommandBuffer cmd,
|
|
VkPipelineLayout pipelinelayout,
|
|
const glm::mat4& modelMatrix,
|
|
const glm::mat4& modelMatrixPrev,
|
|
bool bTranslucentPass,
|
|
uint32_t sceneNodeId,
|
|
bool bSelected)
|
|
{
|
|
// then draw every submesh.
|
|
size_t subMeshCount = m_mmdModel->GetSubMeshCount();
|
|
for (uint32_t i = 0; i < subMeshCount; i++)
|
|
{
|
|
const auto& subMesh = m_mmdModel->GetSubMeshes()[i];
|
|
const auto& material = m_pmxAsset->getMaterials().at(subMesh.m_materialID);
|
|
|
|
if (material.bHide)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bool bShouldDraw = true;
|
|
if (bTranslucentPass)
|
|
{
|
|
bShouldDraw = material.bTranslucent;
|
|
}
|
|
else
|
|
{
|
|
bShouldDraw = !material.bTranslucent;
|
|
}
|
|
|
|
if (!bShouldDraw)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
PMXGpuParams params{};
|
|
params.modelMatrix = modelMatrix;
|
|
params.modelMatrixPrev = modelMatrixPrev;
|
|
params.texId = material.mmdTex;
|
|
params.spTexID = material.mmdSphereTex;
|
|
params.toonTexID = material.mmdToonTex;
|
|
params.pixelDepthOffset = material.pixelDepthOffset;
|
|
params.sceneNodeId = sceneNodeId;
|
|
params.shadingModel = shadingModelConvert(material.pmxShadingModel);
|
|
params.bSelected = bSelected ? 1 : 0;
|
|
params.indicesArrayId = m_indicesBindless;
|
|
params.normalsArrayId = m_normalBindless;
|
|
params.positionsArrayId = m_positionBindless;
|
|
params.uv0sArrayId = m_uvBindless;
|
|
params.positionsPrevArrayId = m_positionPrevBindless;
|
|
params.smoothNormalArrayId = m_smoothNormalBindless;
|
|
|
|
params.edgeColorSize = material.material.m_edgeColor;
|
|
params.edgeColorSize.w = material.material.m_edgeSize;
|
|
|
|
params.translucentUnlitScale = material.translucentUnlitScale;
|
|
params.eyeHighlightScale = material.eyeHighlightScale;
|
|
|
|
{
|
|
uint32_t dynamicOffset = getContext()->getDynamicUniformBuffers().alloc(sizeof(params));
|
|
memcpy((char*)(getContext()->getDynamicUniformBuffers().getBuffer()->getMapped()) + dynamicOffset, ¶ms, sizeof(params));
|
|
auto set = getContext()->getDynamicUniformBuffers().getSet();
|
|
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelinelayout, 6, 1, &set, 1, &dynamicOffset);
|
|
}
|
|
|
|
vkCmdDraw(cmd, subMesh.m_vertexCount, 1, subMesh.m_beginIndex, 0);
|
|
}
|
|
}
|
|
|
|
void PMXMeshProxy::collectObjectInfos(
|
|
std::vector<GPUStaticMeshPerObjectData>& collector,
|
|
std::vector<VkAccelerationStructureInstanceKHR>& asInstances,
|
|
uint32_t sceneNodeId,
|
|
bool bSelected,
|
|
const glm::mat4& modelMatrix,
|
|
const glm::mat4& modelMatrixPrev)
|
|
{
|
|
const size_t objectOffsetId = collector.size();
|
|
|
|
VkAccelerationStructureInstanceKHR instanceTamplate{};
|
|
{
|
|
math::mat4 temp = math::transpose(modelMatrix);
|
|
memcpy(&instanceTamplate.transform, &temp, sizeof(VkTransformMatrixKHR));
|
|
}
|
|
|
|
size_t subMeshCount = m_mmdModel->GetSubMeshCount();
|
|
for (uint32_t i = 0; i < subMeshCount; i++)
|
|
{
|
|
const auto& subMesh = m_mmdModel->GetSubMeshes()[i];
|
|
const auto& material = m_pmxAsset->getMaterials().at(subMesh.m_materialID);
|
|
|
|
if (material.bHide)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bool bShouldDraw = !material.bTranslucent && material.bCastShadow;
|
|
if (!bShouldDraw)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
GPUStaticMeshPerObjectData object{};
|
|
object.uv0sArrayId = m_uvBindless;
|
|
object.normalsArrayId = m_normalBindless;
|
|
object.indicesArrayId = m_indicesBindless;
|
|
object.positionsArrayId = m_positionBindless;
|
|
object.objectId = sceneNodeId;
|
|
object.indexStartPosition = subMesh.m_beginIndex;
|
|
object.indexCount = subMesh.m_vertexCount;
|
|
object.objectType = uint32_t(EStaticMeshType::PMXStaticMesh);
|
|
object.positionsPrevArrayId = m_positionPrevBindless;
|
|
object.smoothNormalArrayId = m_smoothNormalBindless;
|
|
object.bSelected = bSelected ? 1 : 0;
|
|
object.modelMatrix = modelMatrix;
|
|
object.modelMatrixPrev = modelMatrixPrev;
|
|
|
|
object.material = GPUMaterialStandardPBR::getDefault();
|
|
object.material.baseColorId = material.mmdTex;
|
|
|
|
collector.push_back(object);
|
|
|
|
if (getContext()->getGraphicsCardState().bSupportRaytrace)
|
|
{
|
|
VkAccelerationStructureInstanceKHR as{};
|
|
as.accelerationStructureReference = m_blasBuilder.getBlasDeviceAddress(i);
|
|
as.mask = 0xFF;
|
|
as.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
|
as.instanceShaderBindingTableRecordOffset = 0;
|
|
as.transform = instanceTamplate.transform;
|
|
as.instanceCustomIndex = objectOffsetId + i;
|
|
|
|
asInstances.push_back(as);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void PMXMeshProxy::updateAnimation(float vmdFrameTime, float physicElapsed)
|
|
{
|
|
if (m_vmd)
|
|
{
|
|
m_mmdModel->BeginAnimation();
|
|
m_mmdModel->UpdateAllAnimation(m_vmd.get(), vmdFrameTime * 30.0f, physicElapsed);
|
|
m_mmdModel->EndAnimation();
|
|
}
|
|
}
|
|
|
|
void PMXMeshProxy::updateVertex(VkCommandBuffer cmd)
|
|
{
|
|
// Copy last positions, todo: can optimize.
|
|
std::vector<glm::vec3> positionLast = m_mmdModel->getUpdatePositions();
|
|
std::vector<glm::vec3> smoothNormalPrev = m_mmdModel->getUpdateSmoothNormals();
|
|
m_mmdModel->Update();
|
|
const glm::vec3* position = m_mmdModel->GetUpdatePositions();
|
|
const glm::vec3* normal = m_mmdModel->GetUpdateNormals();
|
|
const glm::vec2* uv = m_mmdModel->GetUpdateUVs();
|
|
glm::vec3* positionLastPtr = &positionLast[0];
|
|
|
|
|
|
// copy vertex buffer gpu.
|
|
m_stageBufferPosition->copyAndUpload(cmd, position, m_positionBuffer.get());
|
|
m_stageBufferNormal->copyAndUpload(cmd, normal, m_normalBuffer.get());
|
|
m_stageBufferUv->copyAndUpload(cmd, uv, m_uvBuffer.get());
|
|
m_stageBufferPositionPrevFrame->copyAndUpload(cmd, positionLastPtr, m_positionPrevFrameBuffer.get());
|
|
m_stageSmoothNormal->copyAndUpload(cmd, &smoothNormalPrev[0], m_smoothNormalBuffer.get());
|
|
}
|
|
|
|
void PMXMeshProxy::updateBLAS(VkCommandBuffer cmd)
|
|
{
|
|
const uint32_t maxVertex = m_mmdModel->GetVertexCount();
|
|
|
|
size_t subMeshCount = m_mmdModel->GetSubMeshCount();
|
|
|
|
std::vector<BLASBuilder::BlasInput> allBlas(subMeshCount);
|
|
for (size_t i = 0; i < subMeshCount; i++)
|
|
{
|
|
const auto& subMesh = m_mmdModel->GetSubMeshes()[i];
|
|
|
|
const uint32_t maxPrimitiveCount = subMesh.m_vertexCount / 3;
|
|
|
|
// Describe buffer as array of VertexObj.
|
|
VkAccelerationStructureGeometryTrianglesDataKHR triangles{ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR };
|
|
triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
|
|
triangles.vertexData.deviceAddress = m_positionBuffer->getDeviceAddress();
|
|
triangles.vertexStride = sizeof(math::vec3);
|
|
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
|
triangles.indexData.deviceAddress = m_indexBuffer->getDeviceAddress();
|
|
triangles.maxVertex = maxVertex;
|
|
|
|
// Identify the above data as containing opaque triangles.
|
|
VkAccelerationStructureGeometryKHR asGeom{ VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR };
|
|
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
|
asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR;
|
|
asGeom.geometry.triangles = triangles;
|
|
|
|
VkAccelerationStructureBuildRangeInfoKHR offset{ };
|
|
offset.firstVertex = 0; // No vertex offset, current all vertex buffer start from zero.
|
|
offset.primitiveCount = maxPrimitiveCount;
|
|
offset.primitiveOffset = subMesh.m_beginIndex * sizeof(VertexIndexType);
|
|
offset.transformOffset = 0;
|
|
|
|
allBlas[i].asGeometry.emplace_back(asGeom);
|
|
allBlas[i].asBuildOffsetInfo.emplace_back(offset);
|
|
}
|
|
|
|
if (m_blasBuilder.isInit())
|
|
{
|
|
m_blasBuilder.update(cmd, allBlas,
|
|
VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR |
|
|
VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
|
|
}
|
|
else
|
|
{
|
|
m_blasBuilder.build(allBlas,
|
|
VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR |
|
|
VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|