mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-24 00:00:13 +00:00
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:
parent
6d213ad49b
commit
e12141a673
54 changed files with 2069 additions and 144 deletions
|
|
@ -138,6 +138,7 @@ bool TerrainRenderer::initialize(VkContext* ctx, VkDescriptorSetLayout perFrameL
|
|||
.setRasterization(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE)
|
||||
.setDepthTest(true, true, VK_COMPARE_OP_LESS_OR_EQUAL)
|
||||
.setColorBlendAttachment(PipelineBuilder::blendDisabled())
|
||||
.setMultisample(vkCtx->getMsaaSamples())
|
||||
.setLayout(pipelineLayout)
|
||||
.setRenderPass(mainPass)
|
||||
.setDynamicStates({ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR })
|
||||
|
|
@ -159,6 +160,7 @@ bool TerrainRenderer::initialize(VkContext* ctx, VkDescriptorSetLayout perFrameL
|
|||
.setRasterization(VK_POLYGON_MODE_LINE, VK_CULL_MODE_NONE)
|
||||
.setDepthTest(true, true, VK_COMPARE_OP_LESS_OR_EQUAL)
|
||||
.setColorBlendAttachment(PipelineBuilder::blendDisabled())
|
||||
.setMultisample(vkCtx->getMsaaSamples())
|
||||
.setLayout(pipelineLayout)
|
||||
.setRenderPass(mainPass)
|
||||
.setDynamicStates({ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR })
|
||||
|
|
@ -188,6 +190,86 @@ bool TerrainRenderer::initialize(VkContext* ctx, VkDescriptorSetLayout perFrameL
|
|||
return true;
|
||||
}
|
||||
|
||||
void TerrainRenderer::recreatePipelines() {
|
||||
if (!vkCtx) return;
|
||||
VkDevice device = vkCtx->getDevice();
|
||||
|
||||
// Destroy old pipelines (keep layouts)
|
||||
if (pipeline) { vkDestroyPipeline(device, pipeline, nullptr); pipeline = VK_NULL_HANDLE; }
|
||||
if (wireframePipeline) { vkDestroyPipeline(device, wireframePipeline, nullptr); wireframePipeline = VK_NULL_HANDLE; }
|
||||
|
||||
// Load shaders
|
||||
VkShaderModule vertShader, fragShader;
|
||||
if (!vertShader.loadFromFile(device, "assets/shaders/terrain.vert.spv")) {
|
||||
LOG_ERROR("TerrainRenderer::recreatePipelines: failed to load vertex shader");
|
||||
return;
|
||||
}
|
||||
if (!fragShader.loadFromFile(device, "assets/shaders/terrain.frag.spv")) {
|
||||
LOG_ERROR("TerrainRenderer::recreatePipelines: failed to load fragment shader");
|
||||
vertShader.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// Vertex input (same as initialize)
|
||||
VkVertexInputBindingDescription vertexBinding{};
|
||||
vertexBinding.binding = 0;
|
||||
vertexBinding.stride = sizeof(pipeline::TerrainVertex);
|
||||
vertexBinding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
std::vector<VkVertexInputAttributeDescription> vertexAttribs(4);
|
||||
vertexAttribs[0] = { 0, 0, VK_FORMAT_R32G32B32_SFLOAT,
|
||||
static_cast<uint32_t>(offsetof(pipeline::TerrainVertex, position)) };
|
||||
vertexAttribs[1] = { 1, 0, VK_FORMAT_R32G32B32_SFLOAT,
|
||||
static_cast<uint32_t>(offsetof(pipeline::TerrainVertex, normal)) };
|
||||
vertexAttribs[2] = { 2, 0, VK_FORMAT_R32G32_SFLOAT,
|
||||
static_cast<uint32_t>(offsetof(pipeline::TerrainVertex, texCoord)) };
|
||||
vertexAttribs[3] = { 3, 0, VK_FORMAT_R32G32_SFLOAT,
|
||||
static_cast<uint32_t>(offsetof(pipeline::TerrainVertex, layerUV)) };
|
||||
|
||||
VkRenderPass mainPass = vkCtx->getImGuiRenderPass();
|
||||
|
||||
// Rebuild fill pipeline
|
||||
pipeline = PipelineBuilder()
|
||||
.setShaders(vertShader.stageInfo(VK_SHADER_STAGE_VERTEX_BIT),
|
||||
fragShader.stageInfo(VK_SHADER_STAGE_FRAGMENT_BIT))
|
||||
.setVertexInput({ vertexBinding }, vertexAttribs)
|
||||
.setTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
|
||||
.setRasterization(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE)
|
||||
.setDepthTest(true, true, VK_COMPARE_OP_LESS_OR_EQUAL)
|
||||
.setColorBlendAttachment(PipelineBuilder::blendDisabled())
|
||||
.setMultisample(vkCtx->getMsaaSamples())
|
||||
.setLayout(pipelineLayout)
|
||||
.setRenderPass(mainPass)
|
||||
.setDynamicStates({ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR })
|
||||
.build(device);
|
||||
|
||||
if (!pipeline) {
|
||||
LOG_ERROR("TerrainRenderer::recreatePipelines: failed to create fill pipeline");
|
||||
}
|
||||
|
||||
// Rebuild wireframe pipeline
|
||||
wireframePipeline = PipelineBuilder()
|
||||
.setShaders(vertShader.stageInfo(VK_SHADER_STAGE_VERTEX_BIT),
|
||||
fragShader.stageInfo(VK_SHADER_STAGE_FRAGMENT_BIT))
|
||||
.setVertexInput({ vertexBinding }, vertexAttribs)
|
||||
.setTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
|
||||
.setRasterization(VK_POLYGON_MODE_LINE, VK_CULL_MODE_NONE)
|
||||
.setDepthTest(true, true, VK_COMPARE_OP_LESS_OR_EQUAL)
|
||||
.setColorBlendAttachment(PipelineBuilder::blendDisabled())
|
||||
.setMultisample(vkCtx->getMsaaSamples())
|
||||
.setLayout(pipelineLayout)
|
||||
.setRenderPass(mainPass)
|
||||
.setDynamicStates({ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR })
|
||||
.build(device);
|
||||
|
||||
if (!wireframePipeline) {
|
||||
LOG_WARNING("TerrainRenderer::recreatePipelines: wireframe pipeline not available");
|
||||
}
|
||||
|
||||
vertShader.destroy();
|
||||
fragShader.destroy();
|
||||
}
|
||||
|
||||
void TerrainRenderer::shutdown() {
|
||||
LOG_INFO("Shutting down terrain renderer");
|
||||
|
||||
|
|
@ -482,7 +564,39 @@ void TerrainRenderer::writeMaterialDescriptors(VkDescriptorSet set, const Terrai
|
|||
}
|
||||
|
||||
void TerrainRenderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const Camera& camera) {
|
||||
if (chunks.empty() || !pipeline) return;
|
||||
if (chunks.empty() || !pipeline) {
|
||||
static int emptyLog = 0;
|
||||
if (++emptyLog <= 3)
|
||||
LOG_WARNING("TerrainRenderer::render: chunks=", chunks.size(), " pipeline=", (pipeline != VK_NULL_HANDLE));
|
||||
return;
|
||||
}
|
||||
|
||||
// One-time diagnostic: log chunk nearest to camera
|
||||
static bool loggedDiag = false;
|
||||
if (!loggedDiag && !chunks.empty()) {
|
||||
loggedDiag = true;
|
||||
glm::vec3 cam = camera.getPosition();
|
||||
// Find chunk nearest to camera
|
||||
const TerrainChunkGPU* nearest = nullptr;
|
||||
float nearestDist = 1e30f;
|
||||
for (const auto& ch : chunks) {
|
||||
float dx = ch.boundingSphereCenter.x - cam.x;
|
||||
float dy = ch.boundingSphereCenter.y - cam.y;
|
||||
float dz = ch.boundingSphereCenter.z - cam.z;
|
||||
float d = dx*dx + dy*dy + dz*dz;
|
||||
if (d < nearestDist) { nearestDist = d; nearest = &ch; }
|
||||
}
|
||||
if (nearest) {
|
||||
float d2d = std::sqrt((nearest->boundingSphereCenter.x-cam.x)*(nearest->boundingSphereCenter.x-cam.x) +
|
||||
(nearest->boundingSphereCenter.y-cam.y)*(nearest->boundingSphereCenter.y-cam.y));
|
||||
LOG_INFO("Terrain diag: chunks=", chunks.size(),
|
||||
" cam=(", cam.x, ",", cam.y, ",", cam.z, ")",
|
||||
" nearest_center=(", nearest->boundingSphereCenter.x, ",", nearest->boundingSphereCenter.y, ",", nearest->boundingSphereCenter.z, ")",
|
||||
" dist2d=", d2d, " dist3d=", std::sqrt(nearestDist),
|
||||
" radius=", nearest->boundingSphereRadius,
|
||||
" matSet=", (nearest->materialSet != VK_NULL_HANDLE ? "ok" : "NULL"));
|
||||
}
|
||||
}
|
||||
|
||||
VkPipeline activePipeline = (wireframe && wireframePipeline) ? wireframePipeline : pipeline;
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, activePipeline);
|
||||
|
|
@ -507,6 +621,13 @@ void TerrainRenderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, c
|
|||
renderedChunks = 0;
|
||||
culledChunks = 0;
|
||||
|
||||
// Periodic culling summary (every ~5s at 60fps)
|
||||
static int renderCallCount = 0;
|
||||
if (++renderCallCount % 300 == 1) {
|
||||
glm::vec3 cam = camera.getPosition();
|
||||
LOG_INFO("Terrain render call: total=", chunks.size(), " cam=(", cam.x, ",", cam.y, ",", cam.z, ")");
|
||||
}
|
||||
|
||||
for (const auto& chunk : chunks) {
|
||||
if (!chunk.isValid() || !chunk.materialSet) continue;
|
||||
|
||||
|
|
@ -533,6 +654,11 @@ void TerrainRenderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, c
|
|||
vkCmdDrawIndexed(cmd, chunk.indexCount, 1, 0, 0, 0);
|
||||
renderedChunks++;
|
||||
}
|
||||
|
||||
// Log culling result periodically
|
||||
if (renderCallCount % 300 == 1) {
|
||||
LOG_INFO("Terrain culling: rendered=", renderedChunks, " culled=", culledChunks);
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainRenderer::renderShadow(VkCommandBuffer /*cmd*/, const glm::vec3& /*shadowCenter*/, float /*halfExtent*/) {
|
||||
|
|
@ -589,6 +715,13 @@ void TerrainRenderer::destroyChunkGPU(TerrainChunkGPU& chunk) {
|
|||
chunk.paramsUBO = VK_NULL_HANDLE;
|
||||
}
|
||||
chunk.materialSet = VK_NULL_HANDLE;
|
||||
|
||||
// Destroy owned alpha textures (VkTexture::~VkTexture is a no-op, must call destroy() explicitly)
|
||||
VkDevice device = vkCtx->getDevice();
|
||||
for (auto& tex : chunk.ownedAlphaTextures) {
|
||||
if (tex) tex->destroy(device, allocator);
|
||||
}
|
||||
chunk.ownedAlphaTextures.clear();
|
||||
}
|
||||
|
||||
int TerrainRenderer::getTriangleCount() const {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue