diff --git a/neo/doom3/game/gamesys/TypeInfoGen.h b/neo/doom3/game/gamesys/TypeInfoGen.h index 0ffe4060..2c78abac 100644 --- a/neo/doom3/game/gamesys/TypeInfoGen.h +++ b/neo/doom3/game/gamesys/TypeInfoGen.h @@ -7,7 +7,7 @@ This file has been generated with the Type Info Generator v1.1 (c) 2004 id Software - 1199 constants + 1200 constants 135 enums 624 classes/structs/unions 38 templates @@ -382,6 +382,7 @@ static constantInfo_t constantInfo[] = { { "int", "GEOMETRY_FLAG_SKELETAL", "1" }, { "int", "GEOMETRY_FLAG_UNLIT", "2" }, { "int", "GEOMETRY_FLAG_GLASS", "4" }, + { "int", "GEOMETRY_FLAG_SKYDOME", "8" }, { "static const uint32_t", "GL_RAYTRACING_MAX_LIGHTS", "256" }, { "static const uint32_t", "GL_RAYTRACING_PROC_SURFACE_EMISSIVE", "0x00000001" }, { "static const uint32_t", "GL_RAYTRACING_PROC_SURFACE_UNLIT", "0x00000002" }, @@ -1681,6 +1682,7 @@ static enumValueInfo_t GeometryFlag_t_typeInfo[] = { { "GEOMETRY_FLAG_SKELETAL", 1 }, { "GEOMETRY_FLAG_UNLIT", 2 }, { "GEOMETRY_FLAG_GLASS", 4 }, + { "GEOMETRY_FLAG_SKYDOME", 8 }, { NULL, 0 } }; @@ -4184,6 +4186,13 @@ static classVariableInfo_t glSkyClouds_t_typeInfo[] = { { "float", "coverage", (intptr_t)(&((glSkyClouds_t *)0)->coverage), sizeof( ((glSkyClouds_t *)0)->coverage ) }, { "float", "density", (intptr_t)(&((glSkyClouds_t *)0)->density), sizeof( ((glSkyClouds_t *)0)->density ) }, { "float", "seedOffset", (intptr_t)(&((glSkyClouds_t *)0)->seedOffset), sizeof( ((glSkyClouds_t *)0)->seedOffset ) }, + { "float[3]", "fogColor", (intptr_t)(&((glSkyClouds_t *)0)->fogColor), sizeof( ((glSkyClouds_t *)0)->fogColor ) }, + { "float", "fogOpacity", (intptr_t)(&((glSkyClouds_t *)0)->fogOpacity), sizeof( ((glSkyClouds_t *)0)->fogOpacity ) }, + { "float", "fogHeight", (intptr_t)(&((glSkyClouds_t *)0)->fogHeight), sizeof( ((glSkyClouds_t *)0)->fogHeight ) }, + { "float", "fogPower", (intptr_t)(&((glSkyClouds_t *)0)->fogPower), sizeof( ((glSkyClouds_t *)0)->fogPower ) }, + { "float", "time", (intptr_t)(&((glSkyClouds_t *)0)->time), sizeof( ((glSkyClouds_t *)0)->time ) }, + { "float[2]", "wind", (intptr_t)(&((glSkyClouds_t *)0)->wind), sizeof( ((glSkyClouds_t *)0)->wind ) }, + { "float", "volume", (intptr_t)(&((glSkyClouds_t *)0)->volume), sizeof( ((glSkyClouds_t *)0)->volume ) }, { NULL, 0 } }; diff --git a/neo/engine/opengl/gl_d3d12shim.cpp b/neo/engine/opengl/gl_d3d12shim.cpp index a6350695..5e22d6e0 100644 --- a/neo/engine/opengl/gl_d3d12shim.cpp +++ b/neo/engine/opengl/gl_d3d12shim.cpp @@ -3143,6 +3143,7 @@ cbuffer DrawCB : register(b0) #define QD3D12_TESS_DISTANCE_NEAR 512.0 #define QD3D12_TESS_DISTANCE_FAR 2200.0 #define QD3D12_GEOMETRY_FLAG_SKELETAL 1u +#define QD3D12_GEOMETRY_FLAG_SKYDOME 8u #define QD3D12_POM_DISTANCE_NEAR 384.0 #define QD3D12_POM_DISTANCE_FAR 1800.0 @@ -4167,6 +4168,23 @@ QD3D12MaterialEval QD3D12_BuildMaterialEval(VSOut i) float4 BuildTerrainColor(VSOut i); +float3 QD3D12_ApplySkyDomeGrade(float3 rgb) +{ + rgb = saturate(rgb); + + float3 sCurve = rgb * rgb * (3.0 - 2.0 * rgb); + float luma = dot(rgb, float3(0.299, 0.587, 0.114)); + float highlight = smoothstep(0.54, 0.92, luma); + float shadow = 1.0 - smoothstep(0.06, 0.42, luma); + + float3 graded = lerp(rgb, sCurve, 0.72); + graded = saturate((graded - 0.42) * 1.34 + 0.42); + graded *= 1.0 - shadow * 0.18; + graded += rgb * rgb * (0.28 * highlight); + + return saturate(graded); +} + float4 BuildTexturedColorCached(VSOut i, QD3D12MaterialEval m) { if (gUseTerrainBlend > 0.5) @@ -4211,6 +4229,12 @@ float4 BuildTexturedColorCached(VSOut i, QD3D12MaterialEval m) outColor.rgb *= (1.0 - glowMask); } + uint geometryBits = (uint)floor(max(i.attr.x, 0.0) + 0.5); + if ((geometryBits & QD3D12_GEOMETRY_FLAG_SKYDOME) != 0u) + { + outColor.rgb = QD3D12_ApplySkyDomeGrade(outColor.rgb); + } + // outColor.xyz = ApplySoftwareRendererLook(outColor.xyz); outColor = ApplyFog(outColor, i.fogCoord); @@ -4917,6 +4941,7 @@ cbuffer PostCB : register(b0) #define gToneMapExposure gPostParams1.x #define gToneMapWhiteScale gPostParams1.y #define gToneMapBrightness gPostParams1.z +#define gSkyHorizonFogOpacity gPostParams1.w #define gPostFogEnabled gPostParams2.x #define gPostFogMode gPostParams2.y #define gPostFogDensity gPostParams2.z @@ -4943,6 +4968,12 @@ cbuffer PostCB : register(b0) #define gSkyCloudCoverage gSkyCloudParams.y #define gSkyCloudDensity gSkyCloudParams.z #define gSkyCloudSeed gSkyCloudParams.w +#define gSkyHorizonFogColor gPostParams2.rgb +#define gSkyHorizonFogHeight gPostParams2.w +#define gSkyHorizonFogPower gPostParams3.x +#define gSkyCloudTime gPostParams3.y +#define gSkyCloudWind gPostParams3.zw +#define gSkyCloudVolume gPostParticleParams.w #define QD3D12_TONEMAP_TILE_DIM 64u static const uint GL_RAYTRACING_LIGHT_TYPE_POINT = 0u; @@ -5308,7 +5339,8 @@ float QD3D12_SkyCloudNoise(float3 p) return lerp(lerp(x00, x10, f.y), lerp(x01, x11, f.y), f.z); } - +)HLSL" +R"HLSL( float QD3D12_SkyCloudFBm(float3 p) { float sum = 0.0; @@ -5338,57 +5370,80 @@ float4 PSSkyClouds(VSOut i) : SV_Target0 float2 ndc = float2(i.uv.x * 2.0 - 1.0, 1.0 - i.uv.y * 2.0); float3 ray = normalize(gSkyCloudForward + gSkyCloudRight * (ndc.x * gSkyCloudTanX) + gSkyCloudUp * (ndc.y * gSkyCloudTanY)); float horizonMask = smoothstep(-0.015, 0.18, ray.z); - if (horizonMask <= 0.0001) - discard; - float zMin = gSkyCloudZMin; - float zMax = max(gSkyCloudZMax, zMin + 64.0); - float slabDepth = zMax - zMin; - float cloudZ = zMin + slabDepth * 0.55; - float rayZ = max(ray.z, 0.10); - float baseT = (cloudZ - gSkyCloudViewOrigin.z) / rayZ; - if (baseT <= 0.0) - discard; - - float2 baseWorld = (gSkyCloudViewOrigin + ray * baseT).xy; - float alpha = 0.0; - float shade = 0.0; - float scale = max(gSkyCloudScale, 0.00001); - float seed = gSkyCloudSeed; - float3 seedVec = float3(11.7 + seed * 0.00011, 3.4 - seed * 0.00007, 9.1); - - [unroll] - for (int layer = 0; layer < 7; ++layer) + float cloudAlpha = 0.0; + float3 brightCloud = saturate(gSkyCloudColor); + if (gSkyCloudOpacity > 0.0001 && gSkyCloudDensity > 0.0001 && horizonMask > 0.0001) { - float l = ((float)layer + 0.5) * (1.0 / 7.0); - float heightFade = smoothstep(0.02, 0.34, l) * (1.0 - smoothstep(0.70, 1.0, l)); - float2 layerDrift = float2(0.62, -0.28) * (seed * 0.00003 + l * 310.0); - float2 parallax = ray.xy * ((l - 0.5) * slabDepth * 0.16); - float2 cloudXY = (baseWorld + parallax + layerDrift) * scale; - float3 p = float3(cloudXY, seed * 0.00009 + l * 2.7); + float zMin = gSkyCloudZMin; + float zMax = max(gSkyCloudZMax, zMin + 64.0); + float slabDepth = zMax - zMin; + float cloudZ = zMin + slabDepth * 0.55; + float rayZ = max(ray.z, 0.10); + float baseT = (cloudZ - gSkyCloudViewOrigin.z) / rayZ; - float broad = QD3D12_SkyCloudFBm(p * 0.48 + seedVec); - float warpA = QD3D12_SkyCloudFBm(p * 0.82 + broad * 0.85 + seedVec.yzx); - float billowA = smoothstep(0.18, 0.96, QD3D12_SkyCloudBillow(p * 1.35 + warpA * 1.20)); - float billowB = smoothstep(0.42, 0.96, QD3D12_SkyCloudBillow(p * 2.05 + seedVec.zxy)); + if (baseT > 0.0) + { + float2 windScroll = gSkyCloudWind * gSkyCloudTime; + float2 baseWorld = (gSkyCloudViewOrigin + ray * baseT).xy + windScroll; + float shade = 0.0; + float shadow = 0.0; + float scale = max(gSkyCloudScale, 0.00001); + float seed = gSkyCloudSeed; + float3 seedVec = float3(11.7 + seed * 0.00011, 3.4 - seed * 0.00007, 9.1); - float anvil = smoothstep(0.20, 0.76, broad); - float shape = anvil * (billowA * 0.88 + billowB * 0.12); - shape = smoothstep(saturate(gSkyCloudCoverage) * 0.66, 0.94, shape); + [unroll] + for (int layer = 0; layer < 7; ++layer) + { + float l = ((float)layer + 0.5) * (1.0 / 7.0); + float heightFade = smoothstep(0.02, 0.34, l) * (1.0 - smoothstep(0.70, 1.0, l)); + float windShear = (l - 0.5) * gSkyCloudTime * 5.5; + float2 layerDrift = float2(0.62, -0.28) * (seed * 0.00003 + l * 310.0 + windShear); + float2 parallax = ray.xy * ((l - 0.5) * slabDepth * lerp(0.12, 0.22, saturate(gSkyCloudVolume))); + float2 cloudXY = (baseWorld + parallax + layerDrift) * scale; + float3 p = float3(cloudXY, seed * 0.00009 + l * 2.7); - float density = shape * heightFade * max(gSkyCloudDensity, 0.0); - alpha += (1.0 - alpha) * density * 0.36; - shade += density * (0.66 + l * 0.22 + broad * 0.12); + float broad = QD3D12_SkyCloudFBm(p * 0.48 + seedVec); + float warpA = QD3D12_SkyCloudFBm(p * 0.82 + broad * 0.85 + seedVec.yzx); + float billowA = smoothstep(0.18, 0.96, QD3D12_SkyCloudBillow(p * 1.35 + warpA * 1.20 + gSkyCloudTime * 0.012)); + float billowB = smoothstep(0.42, 0.96, QD3D12_SkyCloudBillow(p * 2.05 + seedVec.zxy - gSkyCloudTime * 0.018)); + + float anvil = smoothstep(0.20, 0.76, broad); + float shape = anvil * (billowA * 0.88 + billowB * 0.12); + shape = smoothstep(saturate(gSkyCloudCoverage) * 0.66, 0.94, shape); + + float volume = saturate(gSkyCloudVolume); + float coreLift = lerp(1.0, smoothstep(0.04, 0.72, l), volume * 0.42); + float selfShadow = lerp(1.0, exp(-shadow * 1.65), volume); + float density = shape * heightFade * coreLift * max(gSkyCloudDensity, 0.0); + cloudAlpha += (1.0 - cloudAlpha) * density * 0.36; + shade += density * selfShadow * (0.70 + l * 0.26 + broad * 0.10); + shadow += density * (0.52 + (1.0 - l) * 0.35); + } + + cloudAlpha = saturate(cloudAlpha * saturate(gSkyCloudOpacity) * horizonMask); + + float skyLum = dot(saturate(gSkyCloudColor), float3(0.299, 0.587, 0.114)); + float3 cloudTint = saturate(gSkyCloudColor * (1.22 + skyLum * 0.18)); + float volumeShade = lerp(1.0, 0.82 + exp(-shadow * 0.38) * 0.26, saturate(gSkyCloudVolume)); + brightCloud = lerp(cloudTint, float3(1.0, 0.985, 0.94), 0.48); + brightCloud *= (0.88 + saturate(shade) * 0.24 + saturate(skyLum) * 0.12) * volumeShade; + brightCloud = saturate(brightCloud); + } } - alpha = saturate(alpha * saturate(gSkyCloudOpacity) * horizonMask); + float fogHeight = max(gSkyHorizonFogHeight, 0.01); + float fogShape = 1.0 - smoothstep(-0.02, fogHeight, ray.z); + fogShape = pow(saturate(fogShape), max(gSkyHorizonFogPower, 0.25)); + float fogAlpha = saturate(gSkyHorizonFogOpacity) * fogShape; + + float alpha = cloudAlpha + fogAlpha * (1.0 - cloudAlpha); if (alpha <= 0.001) discard; - float skyLum = dot(saturate(gSkyCloudColor), float3(0.299, 0.587, 0.114)); - float3 brightCloud = lerp(saturate(gSkyCloudColor * 1.28), float3(1.0, 0.985, 0.94), 0.76); - brightCloud *= 0.92 + saturate(shade) * 0.16 + saturate(skyLum) * 0.16; - return float4(saturate(brightCloud), alpha); + float3 fogColor = saturate(gSkyHorizonFogColor); + float3 composite = (brightCloud * cloudAlpha + fogColor * fogAlpha * (1.0 - cloudAlpha)) / max(alpha, 0.001); + return float4(saturate(composite), alpha); } )HLSL" R"HLSL( @@ -8971,6 +9026,16 @@ static void QD3D12_SetPostConstants( constants[27] = screenParticleDepthScaleY; if (skyClouds) { + constants[7] = skyClouds->fogOpacity; + constants[8] = skyClouds->fogColor[0]; + constants[9] = skyClouds->fogColor[1]; + constants[10] = skyClouds->fogColor[2]; + constants[11] = skyClouds->fogHeight; + constants[12] = skyClouds->fogPower; + constants[13] = skyClouds->time; + constants[14] = skyClouds->wind[0]; + constants[15] = skyClouds->wind[1]; + constants[27] = skyClouds->volume; constants[20] = skyClouds->viewOrigin[0]; constants[21] = skyClouds->viewOrigin[1]; constants[22] = skyClouds->viewOrigin[2]; @@ -9457,7 +9522,9 @@ void APIENTRY glDrawScreenSpaceDecalsQD3D12(void) void APIENTRY glDrawSkyCloudsQD3D12(const glSkyClouds_t* clouds) { - if (!clouds || clouds->opacity <= 0.0f || clouds->density <= 0.0f) + if (!clouds) + return; + if ((clouds->opacity <= 0.0f || clouds->density <= 0.0f) && clouds->fogOpacity <= 0.0f) return; QD3D12Window* window = g_currentWindow; diff --git a/neo/engine/opengl/opengl.h b/neo/engine/opengl/opengl.h index 4f6449e5..f114dc8f 100644 --- a/neo/engine/opengl/opengl.h +++ b/neo/engine/opengl/opengl.h @@ -1571,7 +1571,8 @@ enum GeometryFlag_t GEOMETRY_FLAG_NONE = 0, GEOMETRY_FLAG_SKELETAL = 1, GEOMETRY_FLAG_UNLIT = 2, - GEOMETRY_FLAG_GLASS = 4 + GEOMETRY_FLAG_GLASS = 4, + GEOMETRY_FLAG_SKYDOME = 8 }; void APIENTRY glGeometryFlagf(GLfloat flag); @@ -1810,6 +1811,13 @@ typedef struct glSkyClouds_s float coverage; float density; float seedOffset; + float fogColor[3]; + float fogOpacity; + float fogHeight; + float fogPower; + float time; + float wind[2]; + float volume; } glSkyClouds_t; int glRaytracingInit(void); diff --git a/neo/engine/renderer/tr_skydome.cpp b/neo/engine/renderer/tr_skydome.cpp index 843753a0..39557535 100644 --- a/neo/engine/renderer/tr_skydome.cpp +++ b/neo/engine/renderer/tr_skydome.cpp @@ -19,7 +19,13 @@ static idCVar r_skyCloudCoverage("r_skyCloudCoverage", "0.30", CVAR_RENDERER | C static idCVar r_skyCloudDensity("r_skyCloudDensity", "0.5", CVAR_RENDERER | CVAR_FLOAT, "sky cloud density accumulation"); static idCVar r_skyCloudOpacity("r_skyCloudOpacity", "0.78", CVAR_RENDERER | CVAR_FLOAT, "sky cloud final opacity"); static idCVar r_skyCloudSeedOffset("r_skyCloudSeedOffset", "12000", CVAR_RENDERER | CVAR_FLOAT, "sky cloud world noise seed offset"); -static idCVar r_skyCloudColor("r_skyCloudColor", "0.85 0.62 0.48", CVAR_RENDERER, "sky cloud color override as 'r g b' in 0..1 or 0..255; auto samples the skydome"); +static idCVar r_skyCloudColor("r_skyCloudColor", "auto", CVAR_RENDERER, "sky cloud color override as 'r g b' in 0..1 or 0..255; auto samples the skydome"); +static idCVar r_skyCloudWind("r_skyCloudWind", "55 -18", CVAR_RENDERER, "sky cloud scroll wind as world x y units per second"); +static idCVar r_skyCloudVolume("r_skyCloudVolume", "0.65", CVAR_RENDERER | CVAR_FLOAT, "cheap cloud self-shadow and height shaping amount"); +static idCVar r_skyFog("r_skyFog", "1", CVAR_RENDERER | CVAR_BOOL, "render sky horizon fog"); +static idCVar r_skyFogOpacity("r_skyFogOpacity", "0.36", CVAR_RENDERER | CVAR_FLOAT, "sky horizon fog opacity"); +static idCVar r_skyFogHeight("r_skyFogHeight", "0.30", CVAR_RENDERER | CVAR_FLOAT, "view ray z height where sky horizon fog fades out"); +static idCVar r_skyFogPower("r_skyFogPower", "1.15", CVAR_RENDERER | CVAR_FLOAT, "sky horizon fog falloff power"); static void R_UploadSkyDomeMeshToVertexCache(srfTriangles_t* tri) { if (!tri) { @@ -195,7 +201,14 @@ static void R_GetSkyCloudColor(float color[3]) { } static void RB_DrawSkyCloudOverlay(const viewDef_t* viewDef) { - if (!viewDef || !r_skyClouds.GetBool()) { + if (!viewDef) { + return; + } + + const bool drawClouds = r_skyClouds.GetBool(); + const bool drawFog = r_skyFog.GetBool() && r_skyFogOpacity.GetFloat() > 0.0f; + + if (!drawClouds && !drawFog) { return; } @@ -203,7 +216,11 @@ static void RB_DrawSkyCloudOverlay(const viewDef_t* viewDef) { memset(&clouds, 0, sizeof(clouds)); R_GetSkyCloudColor(clouds.skyColor); - clouds.opacity = idMath::ClampFloat(0.0f, 1.0f, r_skyCloudOpacity.GetFloat()); + R_GetSkyAverageColor(clouds.fogColor); + clouds.opacity = drawClouds ? idMath::ClampFloat(0.0f, 1.0f, r_skyCloudOpacity.GetFloat()) : 0.0f; + clouds.fogOpacity = drawFog ? idMath::ClampFloat(0.0f, 1.0f, r_skyFogOpacity.GetFloat()) : 0.0f; + clouds.fogHeight = Max(r_skyFogHeight.GetFloat(), 0.01f); + clouds.fogPower = Max(r_skyFogPower.GetFloat(), 0.25f); const idVec3& viewOrg = viewDef->renderView.vieworg; clouds.viewOrigin[0] = viewOrg.x; @@ -226,8 +243,13 @@ static void RB_DrawSkyCloudOverlay(const viewDef_t* viewDef) { clouds.tanHalfFovY = idMath::Tan(DEG2RAD(viewDef->renderView.fov_y * 0.5f)); clouds.noiseScale = Max(r_skyCloudScale.GetFloat(), 0.00001f); clouds.coverage = idMath::ClampFloat(0.0f, 1.0f, r_skyCloudCoverage.GetFloat()); - clouds.density = Max(r_skyCloudDensity.GetFloat(), 0.0f); + clouds.density = drawClouds ? Max(r_skyCloudDensity.GetFloat(), 0.0f) : 0.0f; clouds.seedOffset = r_skyCloudSeedOffset.GetFloat(); + clouds.time = viewDef->renderView.time * 0.001f; + clouds.wind[0] = 55.0f; + clouds.wind[1] = -18.0f; + sscanf(r_skyCloudWind.GetString(), "%f %f", &clouds.wind[0], &clouds.wind[1]); + clouds.volume = idMath::ClampFloat(0.0f, 1.0f, r_skyCloudVolume.GetFloat()); glDrawSkyCloudsQD3D12(&clouds); } @@ -327,7 +349,7 @@ void RB_DrawSkyDome(const viewDef_t* viewDef) { verts->st.ToFloatPtr() ); - glGeometryFlagf(GEOMETRY_FLAG_UNLIT); + glGeometryFlagf(GEOMETRY_FLAG_UNLIT + GEOMETRY_FLAG_SKYDOME); RB_DrawElementsWithCounters(g_skyDomeTri); RB_DrawSkyCloudOverlay(viewDef); glGeometryFlagf(GEOMETRY_FLAG_NONE);