mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-23 07:40:14 +00:00
Player interaction ripples: vertex shader adds radial damped-sine displacement centered on player position, fragment shader adds matching normal perturbation for specular highlights. Player XY packed into shadowParams.zw, ripple strength into fogParams.w. Separate 1x render pass for water when MSAA is active to avoid MSAA-induced darkening — water renders after main pass resolves, using the resolved swapchain image and depth resolve target. Water 1x framebuffers rebuilt on swapchain recreate (window resize).
291 lines
11 KiB
C++
291 lines
11 KiB
C++
#include "rendering/vk_pipeline.hpp"
|
|
#include "core/logger.hpp"
|
|
|
|
namespace wowee {
|
|
namespace rendering {
|
|
|
|
PipelineBuilder::PipelineBuilder() {
|
|
// Default: one blend attachment with blending disabled
|
|
colorBlendAttachments_.push_back(blendDisabled());
|
|
|
|
// Default dynamic states: viewport + scissor (almost always dynamic)
|
|
dynamicStates_ = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setShaders(
|
|
VkPipelineShaderStageCreateInfo vert, VkPipelineShaderStageCreateInfo frag)
|
|
{
|
|
shaderStages_ = {vert, frag};
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setVertexInput(
|
|
const std::vector<VkVertexInputBindingDescription>& bindings,
|
|
const std::vector<VkVertexInputAttributeDescription>& attributes)
|
|
{
|
|
vertexBindings_ = bindings;
|
|
vertexAttributes_ = attributes;
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setNoVertexInput() {
|
|
vertexBindings_.clear();
|
|
vertexAttributes_.clear();
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setTopology(VkPrimitiveTopology topology,
|
|
VkBool32 primitiveRestart)
|
|
{
|
|
topology_ = topology;
|
|
primitiveRestart_ = primitiveRestart;
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setRasterization(VkPolygonMode polygonMode,
|
|
VkCullModeFlags cullMode, VkFrontFace frontFace)
|
|
{
|
|
polygonMode_ = polygonMode;
|
|
cullMode_ = cullMode;
|
|
frontFace_ = frontFace;
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setDepthTest(bool enable, bool writeEnable,
|
|
VkCompareOp compareOp)
|
|
{
|
|
depthTestEnable_ = enable;
|
|
depthWriteEnable_ = writeEnable;
|
|
depthCompareOp_ = compareOp;
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setNoDepthTest() {
|
|
depthTestEnable_ = false;
|
|
depthWriteEnable_ = false;
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setDepthBias(float constantFactor, float slopeFactor) {
|
|
depthBiasEnable_ = true;
|
|
depthBiasConstant_ = constantFactor;
|
|
depthBiasSlope_ = slopeFactor;
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setColorBlendAttachment(
|
|
VkPipelineColorBlendAttachmentState blendState)
|
|
{
|
|
colorBlendAttachments_ = {blendState};
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setNoColorAttachment() {
|
|
colorBlendAttachments_.clear();
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setMultisample(VkSampleCountFlagBits samples) {
|
|
msaaSamples_ = samples;
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setAlphaToCoverage(bool enable) {
|
|
alphaToCoverage_ = enable;
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setLayout(VkPipelineLayout layout) {
|
|
pipelineLayout_ = layout;
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setRenderPass(VkRenderPass renderPass, uint32_t subpass) {
|
|
renderPass_ = renderPass;
|
|
subpass_ = subpass;
|
|
return *this;
|
|
}
|
|
|
|
PipelineBuilder& PipelineBuilder::setDynamicStates(const std::vector<VkDynamicState>& states) {
|
|
dynamicStates_ = states;
|
|
return *this;
|
|
}
|
|
|
|
VkPipeline PipelineBuilder::build(VkDevice device) const {
|
|
// Vertex input
|
|
VkPipelineVertexInputStateCreateInfo vertexInput{};
|
|
vertexInput.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
|
vertexInput.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexBindings_.size());
|
|
vertexInput.pVertexBindingDescriptions = vertexBindings_.data();
|
|
vertexInput.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexAttributes_.size());
|
|
vertexInput.pVertexAttributeDescriptions = vertexAttributes_.data();
|
|
|
|
// Input assembly
|
|
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
|
|
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
|
inputAssembly.topology = topology_;
|
|
inputAssembly.primitiveRestartEnable = primitiveRestart_;
|
|
|
|
// Viewport / scissor (dynamic, so just specify count)
|
|
VkPipelineViewportStateCreateInfo viewportState{};
|
|
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
|
viewportState.viewportCount = 1;
|
|
viewportState.scissorCount = 1;
|
|
|
|
// Rasterization
|
|
VkPipelineRasterizationStateCreateInfo rasterizer{};
|
|
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
|
rasterizer.depthClampEnable = VK_FALSE;
|
|
rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
|
rasterizer.polygonMode = polygonMode_;
|
|
rasterizer.lineWidth = 1.0f;
|
|
rasterizer.cullMode = cullMode_;
|
|
rasterizer.frontFace = frontFace_;
|
|
rasterizer.depthBiasEnable = depthBiasEnable_ ? VK_TRUE : VK_FALSE;
|
|
rasterizer.depthBiasConstantFactor = depthBiasConstant_;
|
|
rasterizer.depthBiasSlopeFactor = depthBiasSlope_;
|
|
|
|
// Multisampling
|
|
VkPipelineMultisampleStateCreateInfo multisampling{};
|
|
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
|
multisampling.sampleShadingEnable = VK_FALSE;
|
|
multisampling.rasterizationSamples = msaaSamples_;
|
|
multisampling.alphaToCoverageEnable = alphaToCoverage_ ? VK_TRUE : VK_FALSE;
|
|
|
|
// Depth/stencil
|
|
VkPipelineDepthStencilStateCreateInfo depthStencil{};
|
|
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
|
depthStencil.depthTestEnable = depthTestEnable_ ? VK_TRUE : VK_FALSE;
|
|
depthStencil.depthWriteEnable = depthWriteEnable_ ? VK_TRUE : VK_FALSE;
|
|
depthStencil.depthCompareOp = depthCompareOp_;
|
|
depthStencil.depthBoundsTestEnable = VK_FALSE;
|
|
depthStencil.stencilTestEnable = VK_FALSE;
|
|
|
|
// Color blending
|
|
VkPipelineColorBlendStateCreateInfo colorBlending{};
|
|
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
|
colorBlending.logicOpEnable = VK_FALSE;
|
|
colorBlending.attachmentCount = static_cast<uint32_t>(colorBlendAttachments_.size());
|
|
colorBlending.pAttachments = colorBlendAttachments_.data();
|
|
|
|
// Dynamic state
|
|
VkPipelineDynamicStateCreateInfo dynamicState{};
|
|
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
|
dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStates_.size());
|
|
dynamicState.pDynamicStates = dynamicStates_.data();
|
|
|
|
// Create pipeline
|
|
VkGraphicsPipelineCreateInfo pipelineInfo{};
|
|
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
|
pipelineInfo.stageCount = static_cast<uint32_t>(shaderStages_.size());
|
|
pipelineInfo.pStages = shaderStages_.data();
|
|
pipelineInfo.pVertexInputState = &vertexInput;
|
|
pipelineInfo.pInputAssemblyState = &inputAssembly;
|
|
pipelineInfo.pViewportState = &viewportState;
|
|
pipelineInfo.pRasterizationState = &rasterizer;
|
|
pipelineInfo.pMultisampleState = &multisampling;
|
|
pipelineInfo.pDepthStencilState = &depthStencil;
|
|
pipelineInfo.pColorBlendState = colorBlendAttachments_.empty() ? nullptr : &colorBlending;
|
|
pipelineInfo.pDynamicState = dynamicStates_.empty() ? nullptr : &dynamicState;
|
|
pipelineInfo.layout = pipelineLayout_;
|
|
pipelineInfo.renderPass = renderPass_;
|
|
pipelineInfo.subpass = subpass_;
|
|
|
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
|
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo,
|
|
nullptr, &pipeline) != VK_SUCCESS)
|
|
{
|
|
LOG_ERROR("Failed to create graphics pipeline");
|
|
return VK_NULL_HANDLE;
|
|
}
|
|
|
|
return pipeline;
|
|
}
|
|
|
|
VkPipelineColorBlendAttachmentState PipelineBuilder::blendDisabled() {
|
|
VkPipelineColorBlendAttachmentState state{};
|
|
state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
|
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
state.blendEnable = VK_FALSE;
|
|
return state;
|
|
}
|
|
|
|
VkPipelineColorBlendAttachmentState PipelineBuilder::blendAlpha() {
|
|
VkPipelineColorBlendAttachmentState state{};
|
|
state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
|
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
state.blendEnable = VK_TRUE;
|
|
state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
state.colorBlendOp = VK_BLEND_OP_ADD;
|
|
state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
state.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
return state;
|
|
}
|
|
|
|
VkPipelineColorBlendAttachmentState PipelineBuilder::blendPremultiplied() {
|
|
VkPipelineColorBlendAttachmentState state{};
|
|
state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
|
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
state.blendEnable = VK_TRUE;
|
|
state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
state.colorBlendOp = VK_BLEND_OP_ADD;
|
|
state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
state.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
return state;
|
|
}
|
|
|
|
VkPipelineColorBlendAttachmentState PipelineBuilder::blendAdditive() {
|
|
VkPipelineColorBlendAttachmentState state{};
|
|
state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
|
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
state.blendEnable = VK_TRUE;
|
|
state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
state.colorBlendOp = VK_BLEND_OP_ADD;
|
|
state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
state.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
return state;
|
|
}
|
|
|
|
VkPipelineLayout createPipelineLayout(VkDevice device,
|
|
const std::vector<VkDescriptorSetLayout>& setLayouts,
|
|
const std::vector<VkPushConstantRange>& pushConstants)
|
|
{
|
|
VkPipelineLayoutCreateInfo layoutInfo{};
|
|
layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
|
layoutInfo.setLayoutCount = static_cast<uint32_t>(setLayouts.size());
|
|
layoutInfo.pSetLayouts = setLayouts.data();
|
|
layoutInfo.pushConstantRangeCount = static_cast<uint32_t>(pushConstants.size());
|
|
layoutInfo.pPushConstantRanges = pushConstants.data();
|
|
|
|
VkPipelineLayout layout = VK_NULL_HANDLE;
|
|
if (vkCreatePipelineLayout(device, &layoutInfo, nullptr, &layout) != VK_SUCCESS) {
|
|
LOG_ERROR("Failed to create pipeline layout");
|
|
}
|
|
|
|
return layout;
|
|
}
|
|
|
|
VkDescriptorSetLayout createDescriptorSetLayout(VkDevice device,
|
|
const std::vector<VkDescriptorSetLayoutBinding>& bindings)
|
|
{
|
|
VkDescriptorSetLayoutCreateInfo layoutInfo{};
|
|
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
|
layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
|
|
layoutInfo.pBindings = bindings.data();
|
|
|
|
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
|
|
if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &layout) != VK_SUCCESS) {
|
|
LOG_ERROR("Failed to create descriptor set layout");
|
|
}
|
|
|
|
return layout;
|
|
}
|
|
|
|
} // namespace rendering
|
|
} // namespace wowee
|