Phase 7.1 tuning: reduce saturation, increase contrast, multi-angle screenshots

- Saturation 1.40→1.15, exposure 2.2→1.8 (less oversaturated)
- Shadow factor 0.55→0.45 (more contrast between lit and shadow)
- Ambient reduced slightly for better contrast
- Screenshot mode: 4 camera views (landscape, sideview, topdown, backlit)
- AO history reset between view changes (prevents temporal contamination)
This commit is contained in:
Samuel Bouchet 2026-03-29 15:11:42 +02:00
parent 55c67686f2
commit 82307269e8
4 changed files with 59 additions and 19 deletions

View file

@ -107,7 +107,7 @@ void main(uint3 DTid : SV_DispatchThreadID) {
float shadowFactor = 1.0; float shadowFactor = 1.0;
if (NdotL <= 0.0) { if (NdotL <= 0.0) {
shadowFactor = 0.55; // back-facing = fully in shadow shadowFactor = 0.45; // back-facing = fully in shadow
} else { } else {
RayDesc ray; RayDesc ray;
ray.Origin = origin; ray.Origin = origin;
@ -120,7 +120,7 @@ void main(uint3 DTid : SV_DispatchThreadID) {
[loop] while (q.Proceed()) {} [loop] while (q.Proceed()) {}
if (q.CommittedStatus() == COMMITTED_TRIANGLE_HIT) { if (q.CommittedStatus() == COMMITTED_TRIANGLE_HIT) {
shadowFactor = 0.55; shadowFactor = 0.45;
} }
} }

View file

@ -195,20 +195,47 @@ int APIENTRY wWinMain(
else { else {
application.Run(); application.Run();
// Screenshot mode: wait for rendering + AO convergence, then capture and quit // Screenshot mode: cycle through multiple camera views
if (renderPath.screenshotMode) { if (renderPath.screenshotMode) {
screenshotFrameCounter++; struct CamView { float x, y, z, pitch, yaw; const char* name; };
// Only start counting convergence frames once we have actual rendered quads static const CamView views[] = {
bool hasRendered = renderPath.renderer.getGpuMeshQuadCount() > 0; { 270.f, 48.f, 240.f, -0.30f, 0.6f, "landscape" }, // wide terrain, slight down
{ 272.f, 44.f, 248.f, -0.20f, 1.0f, "sideview" }, // side angle, ground level
{ 268.f, 55.f, 242.f, -0.70f, 0.5f, "topdown" }, // steep top-down
{ 275.f, 46.f, 235.f, -0.15f, 2.8f, "backlit" }, // looking toward sun
};
static const int numViews = sizeof(views) / sizeof(views[0]);
static int currentView = 0;
static int convergenceFrames = 0; static int convergenceFrames = 0;
static bool waitingForRender = true;
screenshotFrameCounter++;
// Set camera for current view on first frame or after capture
if (screenshotFrameCounter == 1 || convergenceFrames == 0) {
renderPath.setCamera(views[currentView].x, views[currentView].y,
views[currentView].z, views[currentView].pitch, views[currentView].yaw);
}
bool hasRendered = renderPath.renderer.getGpuMeshQuadCount() > 0;
if (hasRendered) convergenceFrames++; if (hasRendered) convergenceFrames++;
// Wait 60 frames after first render for AO temporal convergence
if (convergenceFrames == 60) { // Wait 50 frames for AO convergence per view
bool ok = wi::helper::saveTextureToFile( if (convergenceFrames >= 50) {
renderPath.getVoxelRT(), "bvle_screenshot.png"); char filename[64];
wi::backlog::post(ok ? "Screenshot saved: bvle_screenshot.png" snprintf(filename, sizeof(filename), "bvle_screenshot_%s.png",
: "Screenshot FAILED"); views[currentView].name);
PostQuitMessage(0); wi::helper::saveTextureToFile(renderPath.getVoxelRT(), filename);
currentView++;
if (currentView >= numViews) {
PostQuitMessage(0);
} else {
convergenceFrames = 0;
renderPath.setCamera(views[currentView].x, views[currentView].y,
views[currentView].z, views[currentView].pitch, views[currentView].yaw);
renderPath.resetAOHistory(); // invalidate temporal AO for new view
}
} }
} }
} }

View file

@ -1450,15 +1450,15 @@ void VoxelRenderer::render(
cb.bleedMask = (1u << 1) | (1u << 2) | (1u << 4) | (1u << 5); cb.bleedMask = (1u << 1) | (1u << 2) | (1u << 4) | (1u << 5);
cb.resistBleedMask = (1u << 1); cb.resistBleedMask = (1u << 1);
cb.windTime = windTime_; cb.windTime = windTime_;
// Stylized lighting (Phase 7) — Wonderbox-inspired, iteration 4 // Stylized lighting (Phase 7) — Wonderbox-inspired
cb.skyAmbient = XMFLOAT4(0.65f, 0.68f, 0.75f, 0.0f); // very high ambient fill cb.skyAmbient = XMFLOAT4(0.50f, 0.55f, 0.65f, 0.0f); // cool sky fill
cb.groundAmbient = XMFLOAT4(0.40f, 0.33f, 0.22f, 0.0f); // warm brown, high fill cb.groundAmbient = XMFLOAT4(0.28f, 0.22f, 0.15f, 0.0f); // warm brown ground
cb.shadowTint = XMFLOAT4(0.55f, 0.45f, 0.72f, 0.0f); // purple-blue shadows cb.shadowTint = XMFLOAT4(0.50f, 0.42f, 0.70f, 0.0f); // purple-blue shadows
cb.fogColor = XMFLOAT4(0.80f, 0.75f, 0.60f, 1.0f); // warm sandy-golden fog cb.fogColor = XMFLOAT4(0.78f, 0.73f, 0.60f, 1.0f); // warm sandy fog
cb.fogParams = XMFLOAT4(0.004f, 0.0f, 0.0f, 0.0f); // fog density cb.fogParams = XMFLOAT4(0.004f, 0.0f, 0.0f, 0.0f); // fog density
cb.rimColor = XMFLOAT4(0.90f, 0.80f, 0.55f, 0.0f); // warm golden rim cb.rimColor = XMFLOAT4(0.90f, 0.80f, 0.55f, 0.0f); // warm golden rim
cb.rimParams = XMFLOAT4(2.5f, 0.45f, 0.0f, 0.0f); // exponent, intensity cb.rimParams = XMFLOAT4(2.5f, 0.45f, 0.0f, 0.0f); // exponent, intensity
cb.toneMapParams = XMFLOAT4(1.40f, 2.2f, 0.0f, 0.0f); // vivid saturation, high exposure cb.toneMapParams = XMFLOAT4(1.15f, 1.8f, 0.0f, 0.0f); // moderate saturation, good exposure
dev->UpdateBuffer(&constantBuffer_, &cb, cmd, sizeof(cb)); dev->UpdateBuffer(&constantBuffer_, &cb, cmd, sizeof(cb));
// Save current VP for next frame's temporal reprojection // Save current VP for next frame's temporal reprojection
XMStoreFloat4x4(&prevViewProjection_, vpMatrix); XMStoreFloat4x4(&prevViewProjection_, vpMatrix);
@ -2780,4 +2780,15 @@ void VoxelRenderPath::Compose(CommandList cmd) const {
wi::font::Draw(stats, fp, cmd); wi::font::Draw(stats, fp, cmd);
} }
void VoxelRenderPath::setCamera(float x, float y, float z, float pitch, float yaw) {
cameraPos = { x, y, z };
cameraPitch = pitch;
cameraYaw = yaw;
}
void VoxelRenderPath::resetAOHistory() {
renderer.aoHistoryValid_ = false;
renderer.frameCounter_ = 0;
}
} // namespace voxel } // namespace voxel

View file

@ -317,6 +317,8 @@ public:
bool debugMode = false; bool debugMode = false;
bool debugSmooth = false; bool debugSmooth = false;
bool screenshotMode = false; // CLI "screenshot": auto-position camera, capture, quit bool screenshotMode = false; // CLI "screenshot": auto-position camera, capture, quit
void setCamera(float x, float y, float z, float pitch, float yaw);
void resetAOHistory(); // invalidate temporal AO after camera jump
float cameraSpeed = 50.0f; float cameraSpeed = 50.0f;
float cameraSensitivity = 0.003f; float cameraSensitivity = 0.003f;