#pragma once #include "hd2d/Camera.h" #include "hd2d/RenderTarget.h" #include "hd2d/Scene.h" #include "hd2d/Shader.h" #include #include #include namespace hd2d { // All tunable look parameters of the HD-2D pipeline. struct RenderSettings { // Shadows int shadowMapSize = 4096; float shadowExtent = 34.0f; // half-size of the sun's ortho frustum, world units float shadowSoftness = 1.5f; // PCF radius in texels // Dappled canopy light ("cookie" projected along the sun direction) float cookieStrength = 0.55f; float cookieScale = 0.13f; float cookieSpeed = 0.05f; float cookieCoverage = 0.48f; // fraction of light blocked // God ray beams: the same implied canopy, sparser, applied inside the fog float shaftStrength = 0.9f; // 1 = sun scatters only inside beams float shaftCoverage = 0.62f; // higher = fewer, narrower beams float shaftScale = 0.45f; // beam pattern frequency (larger = thinner beams) // Volumetric fog + god rays bool volumetrics = true; glm::vec3 fogColor{0.30f, 0.36f, 0.45f}; // ambient fog in-scatter tint float fogDensity = 0.008f; float fogHeightFalloff = 0.15f; float fogBaseHeight = 0.0f; float fogNoise = 0.6f; float fogAnisotropy = 0.62f; // Henyey-Greenstein g (forward scattering) float godRayIntensity = 4.5f; float fogMaxDistance = 90.0f; int fogSteps = 56; // Wind for foliage glm::vec2 windDirection{0.8f, 0.35f}; float windStrength = 0.06f; float windGustSpeed = 1.2f; // Depth of field (tilt-shift miniature look) bool dof = true; float focusRange = 6.0f; // fully sharp half-width around the focus distance float focusTransition = 12.0f; // distance over which blur ramps up float dofMaxRadius = 9.0f; // max blur radius in half-res pixels float tiltShift = 0.35f; // extra blur toward screen top/bottom // Bloom bool bloom = true; float bloomStrength = 0.075f; float bloomRadius = 1.0f; // Color grading float exposure = 1.0f; float contrast = 1.08f; float saturation = 1.12f; glm::vec3 lift{0.012f, 0.010f, 0.025f}; // added to shadows glm::vec3 gain{1.04f, 1.00f, 0.93f}; // multiplied into highlights float vignette = 0.42f; float chromaticAberration = 0.0015f; float grain = 0.025f; bool reflections = true; bool occluderFade = true; // dither away 3D scenery between the camera and the player // Screen-space ambient occlusion (contact darkening everywhere; the baked // GroundOcclusion handles the large soft shade under trees) bool ssao = true; bool groundOcclusion = true; // use Scene::groundOcclusion (baked contact AO) float ssaoRadius = 0.7f; // world units float ssaoIntensity = 1.6f; int maxRainDrops = 18000; // streaks drawn at Scene::rain = 1 }; class Renderer { public: Renderer(); ~Renderer(); bool init(const std::string& shaderDir, int width, int height); void resize(int width, int height); bool reloadShaders(); void render(const Scene& scene, const Camera& camera, float time); // Framebuffer the final tonemap pass writes to (0 = the window's // backbuffer). render() leaves it bound with a full-size viewport, so UI // drawn afterwards (DebugUI, ImGui) lands in it too. It must be at least // the size given to init()/resize() and use a non-sRGB RGBA8 color // attachment like the default framebuffer (the tonemap shader // gamma-encodes itself); OffscreenTarget in Screenshot.h does this. void setOutputFramebuffer(GLuint fbo) { outputFbo_ = fbo; } GLuint outputFramebuffer() const { return outputFbo_; } RenderSettings settings; float gpuFrameMs() const { return gpuMs_; } private: struct Impl; std::unique_ptr impl_; float gpuMs_ = 0.0f; GLuint outputFbo_ = 0; }; } // namespace hd2d