Add configurable MSAA anti-aliasing, update auth screen and terrain shader

- MSAA: conditional 2-att (off) vs 3-att (on) render pass with auto-resolve
- MSAA: multisampled color+depth images, query max supported sample count
- MSAA: .setMultisample() on all 25+ main-pass pipelines across 17 renderers
- MSAA: recreatePipelines() on every sub-renderer for runtime MSAA changes
- MSAA: Renderer::setMsaaSamples() orchestrates swapchain+pipeline+ImGui rebuild
- MSAA: Anti-Aliasing combo (Off/2x/4x/8x) in Video settings, persisted
- Update auth screen assets and terrain fragment shader
This commit is contained in:
Kelsi 2026-02-22 02:59:24 -08:00
parent 6d213ad49b
commit e12141a673
54 changed files with 2069 additions and 144 deletions

View file

@ -125,6 +125,7 @@ bool WaterRenderer::initialize(VkContext* ctx, VkDescriptorSetLayout perFrameLay
.setRasterization(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE)
.setDepthTest(true, false, VK_COMPARE_OP_LESS_OR_EQUAL) // depth test yes, write no
.setColorBlendAttachment(PipelineBuilder::blendAlpha())
.setMultisample(vkCtx->getMsaaSamples())
.setLayout(pipelineLayout)
.setRenderPass(mainPass)
.setDynamicStates({ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR })
@ -142,6 +143,60 @@ bool WaterRenderer::initialize(VkContext* ctx, VkDescriptorSetLayout perFrameLay
return true;
}
void WaterRenderer::recreatePipelines() {
if (!vkCtx) return;
VkDevice device = vkCtx->getDevice();
// Destroy old pipeline (keep layout)
if (waterPipeline) { vkDestroyPipeline(device, waterPipeline, nullptr); waterPipeline = VK_NULL_HANDLE; }
// Load shaders
VkShaderModule vertShader, fragShader;
if (!vertShader.loadFromFile(device, "assets/shaders/water.vert.spv")) {
LOG_ERROR("WaterRenderer::recreatePipelines: failed to load vertex shader");
return;
}
if (!fragShader.loadFromFile(device, "assets/shaders/water.frag.spv")) {
LOG_ERROR("WaterRenderer::recreatePipelines: failed to load fragment shader");
vertShader.destroy();
return;
}
// Vertex input (same as initialize)
VkVertexInputBindingDescription vertBinding{};
vertBinding.binding = 0;
vertBinding.stride = 8 * sizeof(float);
vertBinding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
std::vector<VkVertexInputAttributeDescription> vertAttribs = {
{ 0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0 },
{ 1, 0, VK_FORMAT_R32G32_SFLOAT, 6 * sizeof(float) },
};
VkRenderPass mainPass = vkCtx->getImGuiRenderPass();
waterPipeline = PipelineBuilder()
.setShaders(vertShader.stageInfo(VK_SHADER_STAGE_VERTEX_BIT),
fragShader.stageInfo(VK_SHADER_STAGE_FRAGMENT_BIT))
.setVertexInput({ vertBinding }, vertAttribs)
.setTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
.setRasterization(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE)
.setDepthTest(true, false, VK_COMPARE_OP_LESS_OR_EQUAL)
.setColorBlendAttachment(PipelineBuilder::blendAlpha())
.setMultisample(vkCtx->getMsaaSamples())
.setLayout(pipelineLayout)
.setRenderPass(mainPass)
.setDynamicStates({ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR })
.build(device);
vertShader.destroy();
fragShader.destroy();
if (!waterPipeline) {
LOG_ERROR("WaterRenderer::recreatePipelines: failed to create pipeline");
}
}
void WaterRenderer::shutdown() {
clear();