From ec5f1880638e0af9f97d6aaf78a3ae8d6b6180a2 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Mon, 14 Mar 2022 19:12:18 -0400 Subject: [PATCH] Implement fog --- Runtime/Graphics/CCubeRenderer.cpp | 2 +- Runtime/Graphics/CGX.hpp | 7 ++--- Runtime/Graphics/CGraphics.cpp | 13 --------- aurora/lib/gfx/gx.cpp | 26 ++++++++++++++++-- aurora/lib/gfx/gx.hpp | 18 ++++++++++-- aurora/lib/gfx/gx_shader.cpp | 44 ++++++++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 23 deletions(-) diff --git a/Runtime/Graphics/CCubeRenderer.cpp b/Runtime/Graphics/CCubeRenderer.cpp index f0b5523aa..ac7cb7087 100644 --- a/Runtime/Graphics/CCubeRenderer.cpp +++ b/Runtime/Graphics/CCubeRenderer.cpp @@ -801,7 +801,7 @@ void CCubeRenderer::SetWireframeFlags(s32 flags) { } void CCubeRenderer::SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) { - // TODO + CGraphics::SetFog(x318_28_disableFog ? ERglFogMode::None : mode, startz, endz, color); } void CCubeRenderer::RenderFogVolume(const zeus::CColor& color, const zeus::CAABox& aabb, diff --git a/Runtime/Graphics/CGX.hpp b/Runtime/Graphics/CGX.hpp index 134952125..69faa94f1 100644 --- a/Runtime/Graphics/CGX.hpp +++ b/Runtime/Graphics/CGX.hpp @@ -59,10 +59,10 @@ static inline void update_fog(u32 value) noexcept { return; } if ((value & 0xE0) == 0x20) { - // TODO + GXSetFogColor(zeus::skClear); return; } - // TODO + GXSetFogColor(sGXState.x25c_fogColor); } static inline void FlushState() noexcept { @@ -186,8 +186,7 @@ static inline void SetFog(GX::FogType type, float startZ, float endZ, float near if ((sGXState.x56_blendMode & 0xE0) == 0x20) { fogColor = zeus::skClear; } - // TODO - // GXSetFog(type, startZ, endZ, nearZ, farZ, fogColor); + GXSetFog(type, startZ, endZ, nearZ, farZ, fogColor); } void SetIndTexMtxSTPointFive(GX::IndTexMtxID id, s8 scaleExp) noexcept; diff --git a/Runtime/Graphics/CGraphics.cpp b/Runtime/Graphics/CGraphics.cpp index 699d272a1..5383dd5ac 100644 --- a/Runtime/Graphics/CGraphics.cpp +++ b/Runtime/Graphics/CGraphics.cpp @@ -117,19 +117,6 @@ void CGraphics::SetAmbientColor(const zeus::CColor& col) { } void CGraphics::SetFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) { - // g_Fog.m_mode = mode > ERglFogMode::PerspRevExp2 ? ERglFogMode(int(mode) - 8) : mode; - // g_Fog.m_color = color; - // if (CGraphics::g_Proj.x18_far == CGraphics::g_Proj.x14_near || endz == startz) { - // g_Fog.m_A = 0.f; - // g_Fog.m_B = 0.5f; - // g_Fog.m_C = 0.f; - // } else { - // float depthrange = CGraphics::g_Proj.x18_far - CGraphics::g_Proj.x14_near; - // float fogrange = endz - startz; - // g_Fog.m_A = (CGraphics::g_Proj.x18_far * CGraphics::g_Proj.x14_near) / (depthrange * fogrange); - // g_Fog.m_B = CGraphics::g_Proj.x18_far / depthrange; - // g_Fog.m_C = startz / fogrange; - // } CGX::SetFog(GX::FogType(mode), startz, endz, g_Proj.x14_near, g_Proj.x18_far, color); } diff --git a/aurora/lib/gfx/gx.cpp b/aurora/lib/gfx/gx.cpp index eaba1fd17..02e0819a8 100644 --- a/aurora/lib/gfx/gx.cpp +++ b/aurora/lib/gfx/gx.cpp @@ -183,6 +183,10 @@ void GXSetViewport(float left, float top, float width, float height, float nearZ void GXSetScissor(u32 left, u32 top, u32 width, u32 height) noexcept { aurora::gfx::set_scissor(left, top, width, height); } +void GXSetFog(GX::FogType type, float startZ, float endZ, float nearZ, float farZ, const GXColor& color) noexcept { + g_gxState.fog = {type, startZ, endZ, nearZ, farZ, color}; +} +void GXSetFogColor(const GXColor& color) noexcept { g_gxState.fog.color = color; } namespace aurora::gfx { static logvisor::Module Log("aurora::gfx::gx"); @@ -196,8 +200,6 @@ void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHan } void unbind_texture(GX::TexMapID id) noexcept { gx::g_gxState.textures[static_cast(id)].reset(); } -void update_fog_state(const metaforce::CFogState& state) noexcept { gx::g_gxState.fogState = state; } - void load_light(GX::LightID id, const Light& light) noexcept { gx::g_gxState.lights[std::log2(id)] = light; } void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept { gx::g_gxState.lights[std::log2(id)] = ambient; @@ -395,6 +397,7 @@ ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primit config.shaderConfig.tcgs[i] = g_gxState.tcgs[i]; } config.shaderConfig.alphaDiscard = g_gxState.alphaDiscard; + config.shaderConfig.fogType = g_gxState.fog.type; config = { .shaderConfig = config.shaderConfig, .primitive = primitive, @@ -501,6 +504,25 @@ Range build_uniform(const ShaderInfo& info) noexcept { } buf.append(&g_gxState.ptTexMtxs[i], 48); } + if (info.usesFog) { + const auto& state = g_gxState.fog; + struct Fog { + zeus::CColor color = state.color; + float a = 0.f; + float b = 0.5f; + float c = 0.f; + float pad = FLT_MAX; + } fog{}; + static_assert(sizeof(Fog) == 32); + if (state.nearZ != state.farZ && state.startZ != state.endZ) { + const float depthRange = state.farZ - state.nearZ; + const float fogRange = state.endZ - state.startZ; + fog.a = (state.farZ * state.nearZ) / (depthRange * fogRange); + fog.b = state.farZ / depthRange; + fog.c = state.startZ / fogRange; + } + buf.append(&fog, 32); + } for (int i = 0; i < info.sampledTextures.size(); ++i) { if (!info.sampledTextures.test(i)) { continue; diff --git a/aurora/lib/gfx/gx.hpp b/aurora/lib/gfx/gx.hpp index e10ef594a..39d9dc0e7 100644 --- a/aurora/lib/gfx/gx.hpp +++ b/aurora/lib/gfx/gx.hpp @@ -73,12 +73,20 @@ struct TcgConfig { GX::PTTexMtx postMtx = GX::PTIDENTITY; bool normalize = false; }; +struct FogState { + GX::FogType type = GX::FOG_NONE; + float startZ = 0.f; + float endZ = 0.f; + float nearZ = 0.f; + float farZ = 0.f; + zeus::CColor color; +}; struct GXState { zeus::CMatrix4f mv; zeus::CMatrix4f mvInv; zeus::CMatrix4f proj; - metaforce::CFogState fogState; + FogState fog; GX::CullMode cullMode = GX::CULL_BACK; GX::BlendMode blendMode = GX::BM_NONE; GX::BlendFactor blendFacSrc = GX::BL_SRCALPHA; @@ -114,6 +122,7 @@ void shutdown() noexcept; const TextureBind& get_texture(GX::TexMapID id) noexcept; struct ShaderConfig { + GX::FogType fogType; std::array, MaxTevStages> tevStages; std::array colorChannels; std::array tcgs; @@ -155,6 +164,7 @@ struct ShaderInfo { u32 uniformSize = 0; bool usesVtxColor : 1 = false; bool usesNormal : 1 = false; + bool usesFog : 1 = false; }; struct BindGroupRanges { Range vtxDataRange; @@ -247,7 +257,9 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input) if (input.alphaDiscard) { XXH3_64bits_update(&state, &*input.alphaDiscard, sizeof(float)); } - XXH3_64bits_update(&state, &input.denormalizedVertexAttributes, sizeof(bool)); - XXH3_64bits_update(&state, &input.denormalizedHasNrm, sizeof(bool)); + XXH3_64bits_update(&state, &input.denormalizedVertexAttributes, + sizeof(gfx::gx::ShaderConfig::denormalizedVertexAttributes)); + XXH3_64bits_update(&state, &input.denormalizedHasNrm, sizeof(gfx::gx::ShaderConfig::denormalizedHasNrm)); + XXH3_64bits_update(&state, &input.fogType, sizeof(gfx::gx::ShaderConfig::fogType)); } } // namespace aurora diff --git a/aurora/lib/gfx/gx_shader.cpp b/aurora/lib/gfx/gx_shader.cpp index 76d4d7ed5..aa7e45372 100644 --- a/aurora/lib/gfx/gx_shader.cpp +++ b/aurora/lib/gfx/gx_shader.cpp @@ -400,6 +400,7 @@ std::pair build_shader(const ShaderConfig& confi } Log.report(logvisor::Info, FMT_STRING(" alphaDiscard: {}"), config.alphaDiscard.value_or(0.f)); Log.report(logvisor::Info, FMT_STRING(" denormalizedVertexAttributes: {}"), config.denormalizedVertexAttributes); + Log.report(logvisor::Info, FMT_STRING(" fogType: {}"), config.fogType); } std::string uniformPre; @@ -684,6 +685,49 @@ var v_packed_uvs: Vec2Block; uniBufAttrs += fmt::format(FMT_STRING("\n postmtx{}: mat4x3;"), i); info.uniformSize += 64; } + if (config.fogType != GX::FOG_NONE) { + info.usesFog = true; + + uniformPre += "\n" + "struct Fog {\n" + " color: vec4;\n" + " a: f32;\n" + " b: f32;\n" + " c: f32;\n" + " pad: f32;\n" + "}"; + uniBufAttrs += "\n fog: Fog;"; + info.uniformSize += 32; + + fragmentFn += "\n var fogF = clamp((ubuf.fog.a / (ubuf.fog.b - in.pos.z)) - ubuf.fog.c, 0.0, 1.0);"; + switch (config.fogType) { + case GX::FOG_PERSP_LIN: + case GX::FOG_ORTHO_LIN: + fragmentFn += "\n var fogZ = fogF;"; + break; + case GX::FOG_PERSP_EXP: + case GX::FOG_ORTHO_EXP: + fragmentFn += "\n var fogZ = 1.0 - exp2(-8.0 * fogF);"; + break; + case GX::FOG_PERSP_EXP2: + case GX::FOG_ORTHO_EXP2: + fragmentFn += "\n var fogZ = 1.0 - exp2(-8.0 * fogF * fogF);"; + break; + case GX::FOG_PERSP_REVEXP: + case GX::FOG_ORTHO_REVEXP: + fragmentFn += "\n var fogZ = exp2(-8.0 * (1.0 - fogF));"; + break; + case GX::FOG_PERSP_REVEXP2: + case GX::FOG_ORTHO_REVEXP2: + fragmentFn += "\n fogF = 1.0 - fogF;" + "\n var fogZ = exp2(-8.0 * fogF * fogF);"; + break; + default: + Log.report(logvisor::Fatal, FMT_STRING("invalid fog type {}"), config.fogType); + unreachable(); + } + fragmentFn += "\n prev = vec4(mix(prev.rgb, ubuf.fog.color.rgb, clamp(fogZ, 0.0, 1.0)), prev.a);"; + } for (int i = 0; i < info.sampledTextures.size(); ++i) { if (!info.sampledTextures.test(i)) { continue;