Added citybuilder and cloud pass.

This commit is contained in:
Justin Marshall
2026-05-28 01:09:16 -07:00
parent 5d2cb8640d
commit a7e7e8edbc
30 changed files with 58019 additions and 36996 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
DewmAAS "1.07" DewmAAS "1.07"
3369270893 207147058
settings settings
{ {
+1 -1
View File
@@ -1,6 +1,6 @@
DewmAAS "1.07" DewmAAS "1.07"
3369270893 207147058
settings settings
{ {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
worldDecals 1 {
}
+57
View File
@@ -0,0 +1,57 @@
// Auto-generated Mars city builder materials for Doom 3 / Radiant.
textures/mars_citybuilder/mars_dirt
{
qer_editorimage textures/mars_citybuilder/mars_dirt_d.tga
diffusemap textures/mars_citybuilder/mars_dirt_d.tga
specularmap textures/mars_citybuilder/mars_dirt_s.tga
bumpmap textures/mars_citybuilder/mars_dirt_local.tga
}
textures/mars_citybuilder/mars_road_dusty_center
{
qer_editorimage textures/mars_citybuilder/mars_road_dusty_center_d.tga
diffusemap textures/mars_citybuilder/mars_road_dusty_center_d.tga
specularmap textures/mars_citybuilder/mars_road_dusty_center_s.tga
bumpmap textures/mars_citybuilder/mars_road_dusty_center_local.tga
}
textures/mars_citybuilder/mars_sidewalk_dusty
{
qer_editorimage textures/mars_citybuilder/mars_sidewalk_dusty_d.tga
diffusemap textures/mars_citybuilder/mars_sidewalk_dusty_d.tga
specularmap textures/mars_citybuilder/mars_sidewalk_dusty_s.tga
bumpmap textures/mars_citybuilder/mars_sidewalk_dusty_local.tga
}
textures/mars_citybuilder/mars_building_dark_01
{
qer_editorimage textures/mars_citybuilder/mars_building_dark_01_d.tga
diffusemap textures/mars_citybuilder/mars_building_dark_01_d.tga
specularmap textures/mars_citybuilder/mars_building_dark_01_s.tga
bumpmap textures/mars_citybuilder/mars_building_dark_01_local.tga
}
textures/mars_citybuilder/mars_building_dark_02
{
qer_editorimage textures/mars_citybuilder/mars_building_dark_02_d.tga
diffusemap textures/mars_citybuilder/mars_building_dark_02_d.tga
specularmap textures/mars_citybuilder/mars_building_dark_02_s.tga
bumpmap textures/mars_citybuilder/mars_building_dark_02_local.tga
}
textures/mars_citybuilder/mars_road_dusty_center_east_west
{
qer_editorimage textures/mars_citybuilder/mars_road_dusty_center_east_west_d.tga
diffusemap textures/mars_citybuilder/mars_road_dusty_center_east_west_d.tga
specularmap textures/mars_citybuilder/mars_road_dusty_center_east_west_s.tga
bumpmap textures/mars_citybuilder/mars_road_dusty_center_east_west_local.tga
}
textures/mars_citybuilder/mars_road_dusty_intersection
{
qer_editorimage textures/mars_citybuilder/mars_road_dusty_intersection_d.tga
diffusemap textures/mars_citybuilder/mars_road_dusty_intersection_d.tga
specularmap textures/mars_citybuilder/mars_road_dusty_intersection_s.tga
bumpmap textures/mars_citybuilder/mars_road_dusty_intersection_local.tga
}
+26 -7
View File
@@ -9,7 +9,7 @@
1204 constants 1204 constants
135 enums 135 enums
621 classes/structs/unions 622 classes/structs/unions
38 templates 38 templates
7 max inheritance level for 'idAI_Vagary' 7 max inheritance level for 'idAI_Vagary'
@@ -4174,6 +4174,24 @@ static classVariableInfo_t glScreenSpaceParticleVertex_t_typeInfo[] = {
{ NULL, 0 } { NULL, 0 }
}; };
static classVariableInfo_t glSkyClouds_t_typeInfo[] = {
{ "float[3]", "skyColor", (intptr_t)(&((glSkyClouds_t *)0)->skyColor), sizeof( ((glSkyClouds_t *)0)->skyColor ) },
{ "float", "opacity", (intptr_t)(&((glSkyClouds_t *)0)->opacity), sizeof( ((glSkyClouds_t *)0)->opacity ) },
{ "float[3]", "viewOrigin", (intptr_t)(&((glSkyClouds_t *)0)->viewOrigin), sizeof( ((glSkyClouds_t *)0)->viewOrigin ) },
{ "float", "zMin", (intptr_t)(&((glSkyClouds_t *)0)->zMin), sizeof( ((glSkyClouds_t *)0)->zMin ) },
{ "float[3]", "viewForward", (intptr_t)(&((glSkyClouds_t *)0)->viewForward), sizeof( ((glSkyClouds_t *)0)->viewForward ) },
{ "float", "zMax", (intptr_t)(&((glSkyClouds_t *)0)->zMax), sizeof( ((glSkyClouds_t *)0)->zMax ) },
{ "float[3]", "viewRight", (intptr_t)(&((glSkyClouds_t *)0)->viewRight), sizeof( ((glSkyClouds_t *)0)->viewRight ) },
{ "float", "tanHalfFovX", (intptr_t)(&((glSkyClouds_t *)0)->tanHalfFovX), sizeof( ((glSkyClouds_t *)0)->tanHalfFovX ) },
{ "float[3]", "viewUp", (intptr_t)(&((glSkyClouds_t *)0)->viewUp), sizeof( ((glSkyClouds_t *)0)->viewUp ) },
{ "float", "tanHalfFovY", (intptr_t)(&((glSkyClouds_t *)0)->tanHalfFovY), sizeof( ((glSkyClouds_t *)0)->tanHalfFovY ) },
{ "float", "noiseScale", (intptr_t)(&((glSkyClouds_t *)0)->noiseScale), sizeof( ((glSkyClouds_t *)0)->noiseScale ) },
{ "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 ) },
{ NULL, 0 }
};
static classVariableInfo_t QD3D12NeuralPOMImageRGBA8_typeInfo[] = { static classVariableInfo_t QD3D12NeuralPOMImageRGBA8_typeInfo[] = {
{ "uint32_t", "width", (intptr_t)(&((QD3D12NeuralPOMImageRGBA8 *)0)->width), sizeof( ((QD3D12NeuralPOMImageRGBA8 *)0)->width ) }, { "uint32_t", "width", (intptr_t)(&((QD3D12NeuralPOMImageRGBA8 *)0)->width), sizeof( ((QD3D12NeuralPOMImageRGBA8 *)0)->width ) },
{ "uint32_t", "height", (intptr_t)(&((QD3D12NeuralPOMImageRGBA8 *)0)->height), sizeof( ((QD3D12NeuralPOMImageRGBA8 *)0)->height ) }, { "uint32_t", "height", (intptr_t)(&((QD3D12NeuralPOMImageRGBA8 *)0)->height), sizeof( ((QD3D12NeuralPOMImageRGBA8 *)0)->height ) },
@@ -5294,11 +5312,11 @@ static classVariableInfo_t frameLookup_t_typeInfo[] = {
{ NULL, 0 } { NULL, 0 }
}; };
static classVariableInfo_t class_289_class_289_typeInfo[] = { static classVariableInfo_t class_290_class_290_typeInfo[] = {
// { "const idSoundShader *", "soundShader", (intptr_t)(&((class_289::class_289 *)0)->soundShader), sizeof( ((class_289::class_289 *)0)->soundShader ) }, // { "const idSoundShader *", "soundShader", (intptr_t)(&((class_290::class_290 *)0)->soundShader), sizeof( ((class_290::class_290 *)0)->soundShader ) },
// { "const function_t *", "function", (intptr_t)(&((class_289::class_289 *)0)->function), sizeof( ((class_289::class_289 *)0)->function ) }, // { "const function_t *", "function", (intptr_t)(&((class_290::class_290 *)0)->function), sizeof( ((class_290::class_290 *)0)->function ) },
// { "const idDeclSkin *", "skin", (intptr_t)(&((class_289::class_289 *)0)->skin), sizeof( ((class_289::class_289 *)0)->skin ) }, // { "const idDeclSkin *", "skin", (intptr_t)(&((class_290::class_290 *)0)->skin), sizeof( ((class_290::class_290 *)0)->skin ) },
// { "int", "index", (intptr_t)(&((class_289::class_289 *)0)->index), sizeof( ((class_289::class_289 *)0)->index ) }, // { "int", "index", (intptr_t)(&((class_290::class_290 *)0)->index), sizeof( ((class_290::class_290 *)0)->index ) },
{ NULL, 0 } { NULL, 0 }
}; };
@@ -9222,6 +9240,7 @@ static classTypeInfo_t classTypeInfo[] = {
{ "glRaytracingProfileCounters_t", "", sizeof(glRaytracingProfileCounters_t), glRaytracingProfileCounters_t_typeInfo }, { "glRaytracingProfileCounters_t", "", sizeof(glRaytracingProfileCounters_t), glRaytracingProfileCounters_t_typeInfo },
{ "glScreenSpaceDecal_t", "", sizeof(glScreenSpaceDecal_t), glScreenSpaceDecal_t_typeInfo }, { "glScreenSpaceDecal_t", "", sizeof(glScreenSpaceDecal_t), glScreenSpaceDecal_t_typeInfo },
{ "glScreenSpaceParticleVertex_t", "", sizeof(glScreenSpaceParticleVertex_t), glScreenSpaceParticleVertex_t_typeInfo }, { "glScreenSpaceParticleVertex_t", "", sizeof(glScreenSpaceParticleVertex_t), glScreenSpaceParticleVertex_t_typeInfo },
{ "glSkyClouds_t", "", sizeof(glSkyClouds_t), glSkyClouds_t_typeInfo },
{ "QD3D12NeuralPOMImageRGBA8", "", sizeof(QD3D12NeuralPOMImageRGBA8), QD3D12NeuralPOMImageRGBA8_typeInfo }, { "QD3D12NeuralPOMImageRGBA8", "", sizeof(QD3D12NeuralPOMImageRGBA8), QD3D12NeuralPOMImageRGBA8_typeInfo },
{ "QD3D12NeuralPOMTrainDesc", "", sizeof(QD3D12NeuralPOMTrainDesc), QD3D12NeuralPOMTrainDesc_typeInfo }, { "QD3D12NeuralPOMTrainDesc", "", sizeof(QD3D12NeuralPOMTrainDesc), QD3D12NeuralPOMTrainDesc_typeInfo },
{ "QD3D12NeuralPOMTrainStats", "", sizeof(QD3D12NeuralPOMTrainStats), QD3D12NeuralPOMTrainStats_typeInfo }, { "QD3D12NeuralPOMTrainStats", "", sizeof(QD3D12NeuralPOMTrainStats), QD3D12NeuralPOMTrainStats_typeInfo },
@@ -9332,7 +9351,7 @@ static classTypeInfo_t classTypeInfo[] = {
{ "jointAnimInfo_t", "", sizeof(jointAnimInfo_t), jointAnimInfo_t_typeInfo }, { "jointAnimInfo_t", "", sizeof(jointAnimInfo_t), jointAnimInfo_t_typeInfo },
{ "jointMod_t", "", sizeof(jointMod_t), jointMod_t_typeInfo }, { "jointMod_t", "", sizeof(jointMod_t), jointMod_t_typeInfo },
{ "frameLookup_t", "", sizeof(frameLookup_t), frameLookup_t_typeInfo }, { "frameLookup_t", "", sizeof(frameLookup_t), frameLookup_t_typeInfo },
// { "class_289::class_289", "", sizeof(class_289::class_289), class_289_class_289_typeInfo }, // { "class_290::class_290", "", sizeof(class_290::class_290), class_290_class_290_typeInfo },
{ "frameCommand_t", "", sizeof(frameCommand_t), frameCommand_t_typeInfo }, { "frameCommand_t", "", sizeof(frameCommand_t), frameCommand_t_typeInfo },
{ "animFlags_t", "", sizeof(animFlags_t), animFlags_t_typeInfo }, { "animFlags_t", "", sizeof(animFlags_t), animFlags_t_typeInfo },
{ "idModelExport", "", sizeof(idModelExport), idModelExport_typeInfo }, { "idModelExport", "", sizeof(idModelExport), idModelExport_typeInfo },
+10
View File
@@ -1071,6 +1071,11 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
</CustomBuildStep> </CustomBuildStep>
<CustomBuildStep Include="tools\radiant\CityBuilder.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
</CustomBuildStep>
<CustomBuildStep Include="tools\radiant\CameraTargetDlg.h"> <CustomBuildStep Include="tools\radiant\CameraTargetDlg.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
@@ -2609,6 +2614,11 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="tools\radiant\CityBuilder.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="tools\radiant\CameraTargetDlg.cpp"> <ClCompile Include="tools\radiant\CameraTargetDlg.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug with inlines|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Dedicated Debug|x64'">true</ExcludedFromBuild>
+6
View File
@@ -1388,6 +1388,9 @@
<ClCompile Include="tools\radiant\autocaulk.cpp"> <ClCompile Include="tools\radiant\autocaulk.cpp">
<Filter>Tools\Radiant</Filter> <Filter>Tools\Radiant</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="tools\radiant\CityBuilder.cpp">
<Filter>Tools\Radiant</Filter>
</ClCompile>
<ClCompile Include="tools\radiant\CameraTargetDlg.cpp"> <ClCompile Include="tools\radiant\CameraTargetDlg.cpp">
<Filter>Tools\Radiant</Filter> <Filter>Tools\Radiant</Filter>
</ClCompile> </ClCompile>
@@ -2354,6 +2357,9 @@
<CustomBuildStep Include="tools\radiant\autocaulk.h"> <CustomBuildStep Include="tools\radiant\autocaulk.h">
<Filter>Tools\Radiant</Filter> <Filter>Tools\Radiant</Filter>
</CustomBuildStep> </CustomBuildStep>
<CustomBuildStep Include="tools\radiant\CityBuilder.h">
<Filter>Tools\Radiant</Filter>
</CustomBuildStep>
<CustomBuildStep Include="tools\radiant\CameraTargetDlg.h"> <CustomBuildStep Include="tools\radiant\CameraTargetDlg.h">
<Filter>Tools\Radiant</Filter> <Filter>Tools\Radiant</Filter>
</CustomBuildStep> </CustomBuildStep>
+132 -15
View File
@@ -1582,7 +1582,8 @@ static int glRaytracingUploadMeshBuffers(glRaytracingMeshRecord_t* mesh);
static int glRaytracingBuildDirtyMeshesInternal(void) static int glRaytracingBuildDirtyMeshesInternal(void)
{ {
std::vector<glRaytracingMeshRecord_t*> dirtyMeshes; static thread_local std::vector<glRaytracingMeshRecord_t*> dirtyMeshes;
dirtyMeshes.clear();
dirtyMeshes.reserve(g_glRaytracingScene.meshes.size()); dirtyMeshes.reserve(g_glRaytracingScene.meshes.size());
for (size_t i = 0; i < g_glRaytracingScene.meshes.size(); ++i) for (size_t i = 0; i < g_glRaytracingScene.meshes.size(); ++i)
@@ -1608,7 +1609,8 @@ static int glRaytracingBuildDirtyMeshesInternal(void)
int newBlasIndex; int newBlasIndex;
}; };
std::vector<glRaytracingMeshBuildInfo_t> builds; static thread_local std::vector<glRaytracingMeshBuildInfo_t> builds;
builds.clear();
builds.resize(dirtyMeshes.size()); builds.resize(dirtyMeshes.size());
for (size_t i = 0; i < dirtyMeshes.size(); ++i) for (size_t i = 0; i < dirtyMeshes.size(); ++i)
@@ -2570,6 +2572,11 @@ struct glRaytracingLightingConstants_t
uint32_t secondaryCorrectionBudget; uint32_t secondaryCorrectionBudget;
float secondaryLightCompensation; float secondaryLightCompensation;
uint32_t historyReset; uint32_t historyReset;
uint32_t externalDenoiser;
float giAmount;
float worldGrimeAmount;
uint32_t pad2;
}; };
struct glRaytracingMeshMetadata_t struct glRaytracingMeshMetadata_t
@@ -2853,6 +2860,10 @@ cbuffer LightingCB : register(b0)
uint gSecondaryCorrectionBudget; uint gSecondaryCorrectionBudget;
float gSecondaryLightCompensation; float gSecondaryLightCompensation;
uint gHistoryReset; uint gHistoryReset;
uint gExternalDenoiser;
float gGiAmount;
float gWorldGrimeAmount;
uint gPadding2;
}; };
StructuredBuffer<Light> gLights : register(t0); StructuredBuffer<Light> gLights : register(t0);
@@ -3338,6 +3349,53 @@ float Hash12(float2 p)
return frac((p3.x + p3.y) * p3.z); return frac((p3.x + p3.y) * p3.z);
} }
float Hash13(float3 p)
{
p = frac(p * 0.1031);
p += dot(p, p.yzx + 33.33);
return frac((p.x + p.y) * p.z);
}
float ValueNoise3D(float3 p)
{
float3 i = floor(p);
float3 f = frac(p);
f = f * f * (3.0 - 2.0 * f);
float n000 = Hash13(i + float3(0, 0, 0));
float n100 = Hash13(i + float3(1, 0, 0));
float n010 = Hash13(i + float3(0, 1, 0));
float n110 = Hash13(i + float3(1, 1, 0));
float n001 = Hash13(i + float3(0, 0, 1));
float n101 = Hash13(i + float3(1, 0, 1));
float n011 = Hash13(i + float3(0, 1, 1));
float n111 = Hash13(i + float3(1, 1, 1));
float nx00 = lerp(n000, n100, f.x);
float nx10 = lerp(n010, n110, f.x);
float nx01 = lerp(n001, n101, f.x);
float nx11 = lerp(n011, n111, f.x);
float nxy0 = lerp(nx00, nx10, f.y);
float nxy1 = lerp(nx01, nx11, f.y);
return lerp(nxy0, nxy1, f.z);
}
void ApplyWorldGrime(float3 worldPos, float cavity, float ao, bool isSkeletal, inout float3 baseAlbedo, inout float3 specularAlbedo)
{
if (isSkeletal || gWorldGrimeAmount <= 0.0001)
return;
float crevice = saturate((1.0 - cavity) * 1.35 + (1.0 - ao) * 0.55);
float largeNoise = ValueNoise3D(worldPos * 0.025);
float fineNoise = ValueNoise3D(worldPos * 0.11 + float3(17.0, 41.0, 9.0));
float grimeMask = saturate(crevice * (0.65 + 0.55 * largeNoise) + fineNoise * 0.18);
float amount = saturate(grimeMask * gWorldGrimeAmount);
float3 dirtTint = float3(0.36, 0.31, 0.24);
baseAlbedo = lerp(baseAlbedo, baseAlbedo * dirtTint, amount);
specularAlbedo *= lerp(1.0, 0.55, amount);
}
float2 Hammersley2D(uint i, uint N, float rand) float2 Hammersley2D(uint i, uint N, float rand)
{ {
float e1 = frac((float)i / (float)N + rand); float e1 = frac((float)i / (float)N + rand);
@@ -4346,6 +4404,24 @@ uint InitSpatialRng(uint2 pixel, float3 worldPos, uint salt)
return PcgHash(seed) | 1u; return PcgHash(seed) | 1u;
} }
uint InitSurfaceStableRng(uint2 pixel, float3 worldPos, float3 normal, uint sampleIndex, uint frameIndex)
{
if (gExternalDenoiser == 0u)
return InitRng(pixel, frameIndex, sampleIndex);
uint3 cell = (uint3)floor(abs(worldPos) * 16.0 + 0.5);
uint3 ncell = (uint3)floor(saturate(normal * 0.5 + 0.5) * 255.0 + 0.5);
uint seed =
cell.x * 73856093u ^
cell.y * 19349663u ^
cell.z * 83492791u ^
ncell.x * 1597334677u ^
ncell.y * 3812015801u ^
ncell.z * 2798796415u ^
sampleIndex * 0x9E3779B9u;
return PcgHash(seed) | 1u;
}
float Rand(inout uint rng) float Rand(inout uint rng)
{ {
rng = PcgHash(rng); rng = PcgHash(rng);
@@ -5587,7 +5663,8 @@ float2 GetStratifiedBounceXi(uint2 pixel, float3 worldPos, float3 pathNormal, ui
{ {
uint spp = max(gSamplesPerPixel, 1u); uint spp = max(gSamplesPerPixel, 1u);
uint sequenceLength = max(spp * 64u, 64u); uint sequenceLength = max(spp * 64u, 64u);
uint sequenceIndex = (sampleIndex + (gFrameIndex & 63u) * spp) % sequenceLength; uint rngFrameIndex = (gEnableDenoiser != 0u && gExternalDenoiser == 0u) ? gFrameIndex : 0u;
uint sequenceIndex = (sampleIndex + (rngFrameIndex & 63u) * spp) % sequenceLength;
float rand = Hash12( float rand = Hash12(
(float2)pixel + (float2)pixel +
@@ -6212,21 +6289,24 @@ void RayGen()
// All four of these are deterministic for this pixel. Compute them once, // All four of these are deterministic for this pixel. Compute them once,
// then reuse them for every stochastic GI sample. // then reuse them for every stochastic GI sample.
float cavity = ComputeCavity(pixel, worldPos, N); const bool externalCharacterPixel = (gExternalDenoiser != 0u) && isSkeletal;
float cavity = externalCharacterPixel ? 1.0 : ComputeCavity(pixel, worldPos, N);
if (isSkeletal) if (isSkeletal)
cavity = lerp(cavity, 1.0, 0.65); cavity = lerp(cavity, 1.0, 0.65);
float ao = ComputeAmbientOcclusion(worldPos, N, pixel, isSkeletal); float ao = externalCharacterPixel ? 1.0 : ComputeAmbientOcclusion(worldPos, N, pixel, isSkeletal);
float skyVis = 0; //ComputeSkyVisibility(worldPos, N, pixel); float skyVis = 0; //ComputeSkyVisibility(worldPos, N, pixel);
float ambientSkyVis = 0; //TraceStraightUpToSky(worldPos, N); float ambientSkyVis = 0; //TraceStraightUpToSky(worldPos, N);
float microShadow = lerp(0.75, 1.0, cavity); float microShadow = lerp(0.75, 1.0, cavity);
ApplyWorldGrime(worldPos, cavity, ao, isSkeletal, baseAlbedo, specularAlbedo);
float3 reactiveFinalGather = 0.0; float3 reactiveFinalGather = 0.0;
uint rngFrameIndex = (gEnableDenoiser != 0u && gExternalDenoiser == 0u) ? gFrameIndex : 0u;
if (gMaxBounces > 1u) if (gMaxBounces > 1u)
{ {
// Evaluate this deterministic screen-space irradiance reuse once per // Evaluate this deterministic screen-space irradiance reuse once per
// pixel, not once per SPP. That makes the GI more responsive without // pixel, not once per SPP. That makes the GI more responsive without
// multiplying the light-list work inside the stochastic sample loop. // multiplying the light-list work inside the stochastic sample loop.
uint gatherRng = InitRng(pixel, gFrameIndex, 1337u); uint gatherRng = InitSurfaceStableRng(pixel, worldPos, N, 1337u, rngFrameIndex);
reactiveFinalGather = EstimateReactiveScreenSpaceFinalGather( reactiveFinalGather = EstimateReactiveScreenSpaceFinalGather(
pixel, pixel,
worldPos, worldPos,
@@ -6257,17 +6337,17 @@ void RayGen()
// Only the indirect bounce path uses per-SPP randomness now. Direct lights, // Only the indirect bounce path uses per-SPP randomness now. Direct lights,
// AO, sky visibility, cavity, and final gather are deterministic and should // AO, sky visibility, cavity, and final gather are deterministic and should
// not be re-traced spp times. // not be re-traced spp times.
if (gMaxBounces > 1u) if (gMaxBounces > 1u && !externalCharacterPixel)
{ {
float3 indirectAccum = 0.0; float3 indirectAccum = 0.0;
[loop] [loop]
for (uint s = 0; s < spp; ++s) for (uint s = 0; s < spp; ++s)
{ {
// Frame-vary the GI path now that a temporal accumulator is present. // Frame-vary only when the internal temporal accumulator is active.
// This lets the stochastic light subset, sky sample, and diffuse path // External denoisers get a surface-stable raw GI pattern so texture
// converge instead of staying locked to one noisy sample pattern. // detail does not boil under reconstruction.
uint rng = InitRng(pixel, gFrameIndex, s); uint rng = InitSurfaceStableRng(pixel, worldPos, N, s, rngFrameIndex);
indirectAccum += EstimatePathTracedIndirectBounce( indirectAccum += EstimatePathTracedIndirectBounce(
pixel, pixel,
worldPos, worldPos,
@@ -6279,7 +6359,7 @@ void RayGen()
} }
float3 indirectLighting = indirectAccum / (float)spp; float3 indirectLighting = indirectAccum / (float)spp;
lightingAccum += ApplyPrimaryDiffusePost(indirectLighting, ao, microShadow, isSkeletal); lightingAccum += ApplyPrimaryDiffusePost(indirectLighting, ao, microShadow, isSkeletal) * gGiAmount;
} }
uint reflectionRng = InitRng(pixel, 0u, 0x5EECu); uint reflectionRng = InitRng(pixel, 0u, 0x5EECu);
@@ -6301,11 +6381,10 @@ void RayGen()
{ {
// reactiveFinalGather is incoming indirect radiance. Apply the primary // reactiveFinalGather is incoming indirect radiance. Apply the primary
// diffuse albedo here, matching the regular lighting path. // diffuse albedo here, matching the regular lighting path.
finalColor += baseAlbedo * reactiveFinalGather; finalColor += baseAlbedo * reactiveFinalGather * gGiAmount;
} }
float outputAo = isSkeletal ? lerp(ao, 1.0, 0.55) : ao; float outputAo = isSkeletal ? lerp(ao, 1.0, 0.55) : ao;
finalColor *= clamp(outputAo + 0.3, 0.0, 1.0);
finalColor += subsurfaceAccum; finalColor += subsurfaceAccum;
// Volumetric light scattering is radiance in the camera ray, not surface // Volumetric light scattering is radiance in the camera ray, not surface
@@ -6321,7 +6400,7 @@ void RayGen()
// the eventual swap-chain/backbuffer is LDR. // the eventual swap-chain/backbuffer is LDR.
finalColor += emissiveSurface + emissiveBloom; finalColor += emissiveSurface + emissiveBloom;
gOutputTex[pixel] = float4(PreparePathTraceOutputColor(finalColor), primaryHitDistance); gOutputTex[pixel] = float4(PreparePathTraceOutputColor(finalColor) * outputAo, primaryHitDistance);
} }
)"; )";
@@ -6354,6 +6433,10 @@ cbuffer LightingCB : register(b0)
uint gSecondaryCorrectionBudget; uint gSecondaryCorrectionBudget;
float gSecondaryLightCompensation; float gSecondaryLightCompensation;
uint gHistoryReset; uint gHistoryReset;
uint gExternalDenoiser;
float gGiAmount;
float gWorldGrimeAmount;
uint gPadding2;
}; };
Texture2D<float4> gAlbedoTex : register(t1); Texture2D<float4> gAlbedoTex : register(t1);
@@ -6640,6 +6723,10 @@ cbuffer LightingCB : register(b0)
uint gSecondaryCorrectionBudget; uint gSecondaryCorrectionBudget;
float gSecondaryLightCompensation; float gSecondaryLightCompensation;
uint gHistoryReset; uint gHistoryReset;
uint gExternalDenoiser;
float gGiAmount;
float gWorldGrimeAmount;
uint gPadding2;
}; };
Texture2D<float4> gAlbedoTex : register(t1); Texture2D<float4> gAlbedoTex : register(t1);
@@ -8059,6 +8146,7 @@ static bool glRaytracingLightingExecuteInternal(
g_glRaytracingLighting.constants.screenSize[2] = 1.0f / (float)pass->width; g_glRaytracingLighting.constants.screenSize[2] = 1.0f / (float)pass->width;
g_glRaytracingLighting.constants.screenSize[3] = 1.0f / (float)pass->height; g_glRaytracingLighting.constants.screenSize[3] = 1.0f / (float)pass->height;
g_glRaytracingLighting.constants.frameIndex = g_glRaytracingLighting.frameCounter; g_glRaytracingLighting.constants.frameIndex = g_glRaytracingLighting.frameCounter;
g_glRaytracingLighting.constants.externalDenoiser = g_glRaytracingLighting.externalDenoiser ? 1u : 0u;
g_glRaytracingLighting.constants.lightCount = g_glRaytracingLighting.constants.lightCount =
(uint32_t)glRaytracingClamp<size_t>(g_glRaytracingLighting.cpuLights.size(), 0, GL_RAYTRACING_MAX_LIGHTS); (uint32_t)glRaytracingClamp<size_t>(g_glRaytracingLighting.cpuLights.size(), 0, GL_RAYTRACING_MAX_LIGHTS);
@@ -8424,6 +8512,9 @@ bool glRaytracingLightingInit(void)
g_glRaytracingLighting.constants.secondaryCorrectionBudget = 0; g_glRaytracingLighting.constants.secondaryCorrectionBudget = 0;
g_glRaytracingLighting.constants.secondaryLightCompensation = 0.62f; g_glRaytracingLighting.constants.secondaryLightCompensation = 0.62f;
g_glRaytracingLighting.constants.historyReset = 1u; g_glRaytracingLighting.constants.historyReset = 1u;
g_glRaytracingLighting.constants.externalDenoiser = 0u;
g_glRaytracingLighting.constants.giAmount = 1.0f;
g_glRaytracingLighting.constants.worldGrimeAmount = 0.35f;
glRaytracingLightingResetDenoiseHistory(); glRaytracingLightingResetDenoiseHistory();
glRaytracingLightingUpdateConstants(); glRaytracingLightingUpdateConstants();
@@ -8653,6 +8744,30 @@ void glRaytracingLightingSetPathTracingOptions(uint32_t samplesPerPixel, uint32_
glRaytracingLightingUpdateConstants(); glRaytracingLightingUpdateConstants();
} }
void glRaytracingLightingSetGIAmount(float amount)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
amount = glRaytracingClamp<float>(amount, 0.0f, 8.0f);
if (g_glRaytracingLighting.constants.giAmount != amount)
glRaytracingLightingResetDenoiseHistory();
g_glRaytracingLighting.constants.giAmount = amount;
glRaytracingLightingUpdateConstants();
}
void glRaytracingLightingSetWorldGrime(float amount)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
amount = glRaytracingClamp<float>(amount, 0.0f, 4.0f);
if (g_glRaytracingLighting.constants.worldGrimeAmount != amount)
glRaytracingLightingResetDenoiseHistory();
g_glRaytracingLighting.constants.worldGrimeAmount = amount;
glRaytracingLightingUpdateConstants();
}
void glRaytracingLightingSetSecondaryLightBudget(int budget, float compensation) void glRaytracingLightingSetSecondaryLightBudget(int budget, float compensation)
{ {
std::lock_guard<std::mutex> lock(g_glRaytracingMutex); std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
@@ -8717,6 +8832,8 @@ void glRaytracingLightingSetExternalDenoiser(int enabled)
glRaytracingLightingResetDenoiseHistory(); glRaytracingLightingResetDenoiseHistory();
g_glRaytracingLighting.externalDenoiser = newValue; g_glRaytracingLighting.externalDenoiser = newValue;
g_glRaytracingLighting.constants.externalDenoiser = newValue ? 1u : 0u;
glRaytracingLightingUpdateConstants();
} }
void glRaytracingLightingUseExternalDenoiser(int enabled) void glRaytracingLightingUseExternalDenoiser(int enabled)
+266 -11
View File
@@ -542,7 +542,7 @@ static const UINT QD3D12_UploadBufferSize = 128 * 1024 * 1024;
static const UINT QD3D12_RequestedGBufferSampleCount = 1; static const UINT QD3D12_RequestedGBufferSampleCount = 1;
static constexpr UINT QD3D12_PostSrvCount = 16; static constexpr UINT QD3D12_PostSrvCount = 16;
static constexpr UINT QD3D12_PostRootConstants = QD3D12_PostSrvCount; static constexpr UINT QD3D12_PostRootConstants = QD3D12_PostSrvCount;
static constexpr UINT QD3D12_PostConstantDwords = 28; static constexpr UINT QD3D12_PostConstantDwords = 48;
static constexpr UINT QD3D12_ToneMapTileDim = 64; static constexpr UINT QD3D12_ToneMapTileDim = 64;
static constexpr UINT QD3D12_MaxScreenSpaceDecals = 64; static constexpr UINT QD3D12_MaxScreenSpaceDecals = 64;
static constexpr UINT QD3D12_MaxScreenSpaceParticleLights = GL_RAYTRACING_MAX_LIGHTS; static constexpr UINT QD3D12_MaxScreenSpaceParticleLights = GL_RAYTRACING_MAX_LIGHTS;
@@ -1798,6 +1798,7 @@ struct GLState
ComPtr<ID3D12PipelineState> postScreenParticlePSO; ComPtr<ID3D12PipelineState> postScreenParticlePSO;
ComPtr<ID3D12PipelineState> postScreenParticleAdditivePSO; ComPtr<ID3D12PipelineState> postScreenParticleAdditivePSO;
ComPtr<ID3D12PipelineState> postScreenParticleEmissivePSO; ComPtr<ID3D12PipelineState> postScreenParticleEmissivePSO;
ComPtr<ID3D12PipelineState> postSkyCloudsPSO;
ComPtr<ID3DBlob> vsMainBlob; ComPtr<ID3DBlob> vsMainBlob;
ComPtr<ID3DBlob> hsMainBlob; ComPtr<ID3DBlob> hsMainBlob;
@@ -1822,6 +1823,7 @@ struct GLState
ComPtr<ID3DBlob> postPsScreenDecalBlob; ComPtr<ID3DBlob> postPsScreenDecalBlob;
ComPtr<ID3DBlob> postVsScreenParticleBlob; ComPtr<ID3DBlob> postVsScreenParticleBlob;
ComPtr<ID3DBlob> postPsScreenParticleBlob; ComPtr<ID3DBlob> postPsScreenParticleBlob;
ComPtr<ID3DBlob> postPsSkyCloudsBlob;
TextureResource whiteTexture; TextureResource whiteTexture;
@@ -4778,6 +4780,11 @@ cbuffer PostCB : register(b0)
float4 gPostFogColor; float4 gPostFogColor;
float4 gPostFogCameraWorldPos; float4 gPostFogCameraWorldPos;
float4 gPostParticleParams; float4 gPostParticleParams;
float4 gSkyCloudColorOpacity;
float4 gSkyCloudForwardZMax;
float4 gSkyCloudRightTanX;
float4 gSkyCloudUpTanY;
float4 gSkyCloudParams;
}; };
#define gPostSharpness gPostParams0.x #define gPostSharpness gPostParams0.x
@@ -4799,6 +4806,20 @@ cbuffer PostCB : register(b0)
#define gScreenParticleEmissiveScale gPostParticleParams.x #define gScreenParticleEmissiveScale gPostParticleParams.x
#define gScreenParticleOutputMode gPostParticleParams.y #define gScreenParticleOutputMode gPostParticleParams.y
#define gScreenParticleDepthScale gPostParticleParams.zw #define gScreenParticleDepthScale gPostParticleParams.zw
#define gSkyCloudColor gSkyCloudColorOpacity.rgb
#define gSkyCloudOpacity gSkyCloudColorOpacity.a
#define gSkyCloudViewOrigin gPostFogCameraWorldPos.xyz
#define gSkyCloudZMin gPostFogCameraWorldPos.w
#define gSkyCloudForward gSkyCloudForwardZMax.xyz
#define gSkyCloudZMax gSkyCloudForwardZMax.w
#define gSkyCloudRight gSkyCloudRightTanX.xyz
#define gSkyCloudTanX gSkyCloudRightTanX.w
#define gSkyCloudUp gSkyCloudUpTanY.xyz
#define gSkyCloudTanY gSkyCloudUpTanY.w
#define gSkyCloudScale gSkyCloudParams.x
#define gSkyCloudCoverage gSkyCloudParams.y
#define gSkyCloudDensity gSkyCloudParams.z
#define gSkyCloudSeed gSkyCloudParams.w
#define QD3D12_TONEMAP_TILE_DIM 64u #define QD3D12_TONEMAP_TILE_DIM 64u
static const uint GL_RAYTRACING_LIGHT_TYPE_POINT = 0u; static const uint GL_RAYTRACING_LIGHT_TYPE_POINT = 0u;
@@ -5134,12 +5155,124 @@ float4 PSCopy(VSOut i) : SV_Target0
{ {
return QD3D12_ApplyPostFog(gTex0.Sample(gSamp0, i.uv), i.uv); return QD3D12_ApplyPostFog(gTex0.Sample(gSamp0, i.uv), i.uv);
} }
float QD3D12_SkyCloudFade(float t)
{
t = saturate(t);
return t * t * (3.0 - 2.0 * t);
}
float QD3D12_SkyCloudHash(int3 p)
{
uint h = (uint)p.x * 374761393u + (uint)p.y * 668265263u + (uint)p.z * 2147483647u;
h = (h ^ (h >> 13)) * 1274126177u;
h ^= h >> 16;
return (float)(h & 0xffffu) * (1.0 / 65535.0);
}
float QD3D12_SkyCloudNoise(float3 p)
{
int3 ip = int3(floor(p));
float3 f = float3(
QD3D12_SkyCloudFade(p.x - (float)ip.x),
QD3D12_SkyCloudFade(p.y - (float)ip.y),
QD3D12_SkyCloudFade(p.z - (float)ip.z));
float x00 = lerp(QD3D12_SkyCloudHash(ip + int3(0, 0, 0)), QD3D12_SkyCloudHash(ip + int3(1, 0, 0)), f.x);
float x10 = lerp(QD3D12_SkyCloudHash(ip + int3(0, 1, 0)), QD3D12_SkyCloudHash(ip + int3(1, 1, 0)), f.x);
float x01 = lerp(QD3D12_SkyCloudHash(ip + int3(0, 0, 1)), QD3D12_SkyCloudHash(ip + int3(1, 0, 1)), f.x);
float x11 = lerp(QD3D12_SkyCloudHash(ip + int3(0, 1, 1)), QD3D12_SkyCloudHash(ip + int3(1, 1, 1)), f.x);
return lerp(lerp(x00, x10, f.y), lerp(x01, x11, f.y), f.z);
}
float QD3D12_SkyCloudFBm(float3 p)
{
float sum = 0.0;
float amp = 0.56;
float norm = 0.0;
[unroll]
for (int octave = 0; octave < 5; ++octave)
{
sum += QD3D12_SkyCloudNoise(p) * amp;
norm += amp;
p *= 2.06;
amp *= 0.52;
}
return sum / max(norm, 1.0e-4);
}
float QD3D12_SkyCloudBillow(float3 p)
{
return 1.0 - abs(QD3D12_SkyCloudFBm(p) * 2.0 - 1.0);
}
)HLSL"
R"HLSL(
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 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 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));
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 density = shape * heightFade * max(gSkyCloudDensity, 0.0);
alpha += (1.0 - alpha) * density * 0.36;
shade += density * (0.66 + l * 0.22 + broad * 0.12);
}
alpha = saturate(alpha * saturate(gSkyCloudOpacity) * horizonMask);
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);
}
)HLSL" )HLSL"
R"HLSL( R"HLSL(
float4 PSSharpen(VSOut i) : SV_Target0 float4 PSSharpen(VSOut i) : SV_Target0
{ {
float4 center = gTex0.Sample(gSamp0, i.uv); float4 center = gTex0.Sample(gSamp0, i.uv);
float amount = saturate(gPostSharpness); float amount = saturate(gPostSharpness) * 2.35;
if (amount <= 0.0001) if (amount <= 0.0001)
return center; return center;
@@ -5151,11 +5284,23 @@ float4 PSSharpen(VSOut i) : SV_Target0
float3 s = gTex0.Sample(gSamp0, saturate(i.uv + float2(0.0, texel.y))).rgb; float3 s = gTex0.Sample(gSamp0, saturate(i.uv + float2(0.0, texel.y))).rgb;
float3 e = gTex0.Sample(gSamp0, saturate(i.uv + float2( texel.x, 0.0))).rgb; float3 e = gTex0.Sample(gSamp0, saturate(i.uv + float2( texel.x, 0.0))).rgb;
float3 w = gTex0.Sample(gSamp0, saturate(i.uv + float2(-texel.x, 0.0))).rgb; float3 w = gTex0.Sample(gSamp0, saturate(i.uv + float2(-texel.x, 0.0))).rgb;
float3 blur = (n + s + e + w) * 0.25; float3 ne = gTex0.Sample(gSamp0, saturate(i.uv + float2( texel.x, -texel.y))).rgb;
float3 nw = gTex0.Sample(gSamp0, saturate(i.uv + float2(-texel.x, -texel.y))).rgb;
float3 se = gTex0.Sample(gSamp0, saturate(i.uv + float2( texel.x, texel.y))).rgb;
float3 sw = gTex0.Sample(gSamp0, saturate(i.uv + float2(-texel.x, texel.y))).rgb;
float3 blur = (n + s + e + w) * 0.18 + (ne + nw + se + sw) * 0.07;
float3 albedoC = gScreenDecalNormal.Sample(gSamp0, i.uv).rgb;
float3 albedoN = gScreenDecalNormal.Sample(gSamp0, saturate(i.uv + float2(0.0, -texel.y))).rgb;
float3 albedoS = gScreenDecalNormal.Sample(gSamp0, saturate(i.uv + float2(0.0, texel.y))).rgb;
float3 albedoE = gScreenDecalNormal.Sample(gSamp0, saturate(i.uv + float2( texel.x, 0.0))).rgb;
float3 albedoW = gScreenDecalNormal.Sample(gSamp0, saturate(i.uv + float2(-texel.x, 0.0))).rgb;
float3 albedoBlur = (albedoN + albedoS + albedoE + albedoW) * 0.25;
float3 albedoDetail = clamp(albedoC - albedoBlur, -0.18, 0.18);
// Sharpen strictly after temporal reconstruction. Keep it conservative so // Sharpen strictly after temporal reconstruction. Keep it conservative so
// the TAA resolve is not undone by ringing on high-contrast UI/geometry edges. // the TAA resolve is not undone by ringing on high-contrast UI/geometry edges.
float3 sharp = center.rgb + (center.rgb - blur) * amount; float3 sharp = center.rgb + (center.rgb - blur) * amount + albedoDetail * (amount * 0.38);
return QD3D12_ApplyPostFog(float4(saturate(sharp), center.a), i.uv); return QD3D12_ApplyPostFog(float4(saturate(sharp), center.a), i.uv);
} }
@@ -5226,7 +5371,7 @@ float4 PSToneMapFinalMax(VSOut i) : SV_Target0
R"HLSL( R"HLSL(
float3 QD3D12_PostSharpenHDR(float2 uv, float3 center) float3 QD3D12_PostSharpenHDR(float2 uv, float3 center)
{ {
float amount = saturate(gPostSharpness); float amount = saturate(gPostSharpness) * 2.35;
if (amount <= 0.0001) if (amount <= 0.0001)
return center; return center;
@@ -5238,11 +5383,23 @@ float3 QD3D12_PostSharpenHDR(float2 uv, float3 center)
float3 s = max(gTex0.Sample(gSamp0, saturate(uv + float2(0.0, texel.y))).rgb, 0.0); float3 s = max(gTex0.Sample(gSamp0, saturate(uv + float2(0.0, texel.y))).rgb, 0.0);
float3 e = max(gTex0.Sample(gSamp0, saturate(uv + float2( texel.x, 0.0))).rgb, 0.0); float3 e = max(gTex0.Sample(gSamp0, saturate(uv + float2( texel.x, 0.0))).rgb, 0.0);
float3 w = max(gTex0.Sample(gSamp0, saturate(uv + float2(-texel.x, 0.0))).rgb, 0.0); float3 w = max(gTex0.Sample(gSamp0, saturate(uv + float2(-texel.x, 0.0))).rgb, 0.0);
float3 blur = (n + s + e + w) * 0.25; float3 ne = max(gTex0.Sample(gSamp0, saturate(uv + float2( texel.x, -texel.y))).rgb, 0.0);
float3 nw = max(gTex0.Sample(gSamp0, saturate(uv + float2(-texel.x, -texel.y))).rgb, 0.0);
float3 se = max(gTex0.Sample(gSamp0, saturate(uv + float2( texel.x, texel.y))).rgb, 0.0);
float3 sw = max(gTex0.Sample(gSamp0, saturate(uv + float2(-texel.x, texel.y))).rgb, 0.0);
float3 blur = (n + s + e + w) * 0.18 + (ne + nw + se + sw) * 0.07;
float3 albedoC = max(gScreenDecalNormal.Sample(gSamp0, uv).rgb, 0.0);
float3 albedoN = max(gScreenDecalNormal.Sample(gSamp0, saturate(uv + float2(0.0, -texel.y))).rgb, 0.0);
float3 albedoS = max(gScreenDecalNormal.Sample(gSamp0, saturate(uv + float2(0.0, texel.y))).rgb, 0.0);
float3 albedoE = max(gScreenDecalNormal.Sample(gSamp0, saturate(uv + float2( texel.x, 0.0))).rgb, 0.0);
float3 albedoW = max(gScreenDecalNormal.Sample(gSamp0, saturate(uv + float2(-texel.x, 0.0))).rgb, 0.0);
float3 albedoBlur = (albedoN + albedoS + albedoE + albedoW) * 0.25;
float3 albedoDetail = clamp(albedoC - albedoBlur, -0.18, 0.18);
// Sharpen before tone mapping so highlights keep their shoulder instead of // Sharpen before tone mapping so highlights keep their shoulder instead of
// ringing after they have already been compressed to display range. // ringing after they have already been compressed to display range.
return min(max(center + (center - blur) * amount, 0.0), 65504.0); return min(max(center + (center - blur) * amount + albedoDetail * (amount * 0.38), 0.0), 65504.0);
} }
float3 QD3D12_ExtendedReinhard(float3 hdr, float whitePoint) float3 QD3D12_ExtendedReinhard(float3 hdr, float whitePoint)
@@ -8531,7 +8688,8 @@ static void QD3D12_SetPostConstants(
float screenParticleEmissiveScale = 0.0f, float screenParticleEmissiveScale = 0.0f,
float screenParticleOutputMode = 0.0f, float screenParticleOutputMode = 0.0f,
float screenParticleDepthScaleX = 1.0f, float screenParticleDepthScaleX = 1.0f,
float screenParticleDepthScaleY = 1.0f) float screenParticleDepthScaleY = 1.0f,
const glSkyClouds_t* skyClouds = nullptr)
{ {
if (!cl) if (!cl)
return; return;
@@ -8574,12 +8732,48 @@ static void QD3D12_SetPostConstants(
constants[25] = screenParticleOutputMode; constants[25] = screenParticleOutputMode;
constants[26] = screenParticleDepthScaleX; constants[26] = screenParticleDepthScaleX;
constants[27] = screenParticleDepthScaleY; constants[27] = screenParticleDepthScaleY;
if (skyClouds)
{
constants[20] = skyClouds->viewOrigin[0];
constants[21] = skyClouds->viewOrigin[1];
constants[22] = skyClouds->viewOrigin[2];
constants[23] = skyClouds->zMin;
constants[28] = skyClouds->skyColor[0];
constants[29] = skyClouds->skyColor[1];
constants[30] = skyClouds->skyColor[2];
constants[31] = skyClouds->opacity;
constants[32] = skyClouds->viewForward[0];
constants[33] = skyClouds->viewForward[1];
constants[34] = skyClouds->viewForward[2];
constants[35] = skyClouds->zMax;
constants[36] = skyClouds->viewRight[0];
constants[37] = skyClouds->viewRight[1];
constants[38] = skyClouds->viewRight[2];
constants[39] = skyClouds->tanHalfFovX;
constants[40] = skyClouds->viewUp[0];
constants[41] = skyClouds->viewUp[1];
constants[42] = skyClouds->viewUp[2];
constants[43] = skyClouds->tanHalfFovY;
constants[44] = skyClouds->noiseScale;
constants[45] = skyClouds->coverage;
constants[46] = skyClouds->density;
constants[47] = skyClouds->seedOffset;
}
cl->SetGraphicsRoot32BitConstants(QD3D12_PostRootConstants, QD3D12_PostConstantDwords, constants, 0); cl->SetGraphicsRoot32BitConstants(QD3D12_PostRootConstants, QD3D12_PostConstantDwords, constants, 0);
} }
static void QD3D12_BindPostFogResources(ID3D12GraphicsCommandList* cl, QD3D12Window& w, bool applySceneFog) static void QD3D12_BindPostFogResources(ID3D12GraphicsCommandList* cl, QD3D12Window& w, bool applySceneFog)
{ {
if (!cl || !applySceneFog || !g_gl.sceneFogValidThisFrame) if (!cl)
return;
if (w.sceneColorBuffers[w.frameIndex] && w.sceneColorSrvIndex[w.frameIndex] != UINT_MAX)
{
QD3D12_TransitionResource(cl, w.sceneColorBuffers[w.frameIndex].Get(), w.sceneColorState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
cl->SetGraphicsRootDescriptorTable(11, w.sceneColorSrvGpu[w.frameIndex]);
}
if (!applySceneFog || !g_gl.sceneFogValidThisFrame)
return; return;
if (!w.positionBuffers[w.frameIndex] || !w.depthBuffer) if (!w.positionBuffers[w.frameIndex] || !w.depthBuffer)
return; return;
@@ -8895,6 +9089,11 @@ static bool QD3D12_ToneMapFullscreenPass(
cl->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); cl->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
cl->SetGraphicsRootDescriptorTable(0, hdrInputSrv); cl->SetGraphicsRootDescriptorTable(0, hdrInputSrv);
cl->SetGraphicsRootDescriptorTable(7, w.toneMapSceneMaxSrvGpu[frame]); cl->SetGraphicsRootDescriptorTable(7, w.toneMapSceneMaxSrvGpu[frame]);
if (w.sceneColorBuffers[frame] && w.sceneColorSrvIndex[frame] != UINT_MAX)
{
QD3D12_TransitionResource(cl, w.sceneColorBuffers[frame].Get(), w.sceneColorState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
cl->SetGraphicsRootDescriptorTable(11, w.sceneColorSrvGpu[frame]);
}
QD3D12_BindPostFogResources(cl, w, applySceneFog); QD3D12_BindPostFogResources(cl, w, applySceneFog);
cl->DrawInstanced(3, 1, 0, 0); cl->DrawInstanced(3, 1, 0, 0);
return true; return true;
@@ -9019,6 +9218,52 @@ void APIENTRY glDrawScreenSpaceDecalsQD3D12(void)
} }
} }
void APIENTRY glDrawSkyCloudsQD3D12(const glSkyClouds_t* clouds)
{
if (!clouds || clouds->opacity <= 0.0f || clouds->density <= 0.0f)
return;
QD3D12Window* window = g_currentWindow;
if (!window || !g_gl.device || !g_gl.cmdList || !g_gl.postSkyCloudsPSO)
return;
if (!window->sceneColorBuffers[window->frameIndex])
return;
QD3D12_EnsureFrameOpen();
QD3D12_FlushQueuedBatches();
const UINT frame = window->frameIndex;
ID3D12GraphicsCommandList* cl = g_gl.cmdList.Get();
QD3D12_TransitionResource(cl, window->sceneColorBuffers[frame].Get(), window->sceneColorState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
D3D12_VIEWPORT viewport{};
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = (float)window->renderWidth;
viewport.Height = (float)window->renderHeight;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
D3D12_RECT scissor{};
scissor.left = 0;
scissor.top = 0;
scissor.right = (LONG)window->renderWidth;
scissor.bottom = (LONG)window->renderHeight;
ID3D12DescriptorHeap* heaps[] = { g_gl.srvHeap.Get() };
cl->SetDescriptorHeaps(_countof(heaps), heaps);
cl->SetGraphicsRootSignature(g_gl.postRootSig.Get());
QD3D12_SetPostConstants(cl, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, false, 0.0f, 0.0f, false, 16.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, clouds);
cl->SetPipelineState(g_gl.postSkyCloudsPSO.Get());
cl->SetGraphicsRootDescriptorTable(0, g_gl.whiteTexture.srvGpu);
D3D12_CPU_DESCRIPTOR_HANDLE sceneColorRtv = QD3D12_RtvAt(*window, QD3D12_RTV_SCENE_RENDER, frame);
cl->OMSetRenderTargets(1, &sceneColorRtv, FALSE, nullptr);
cl->RSSetViewports(1, &viewport);
cl->RSSetScissorRects(1, &scissor);
cl->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
cl->DrawInstanced(3, 1, 0, 0);
}
static void QD3D12_DrawScreenSpaceParticleBatch(const QD3D12ScreenSpaceParticleBatch& batch, ID3D12Resource* tlas, bool emissiveOnly, bool nativeOutput) static void QD3D12_DrawScreenSpaceParticleBatch(const QD3D12ScreenSpaceParticleBatch& batch, ID3D12Resource* tlas, bool emissiveOnly, bool nativeOutput)
{ {
const glScreenSpaceParticleVertex_t* verts = batch.vertices.empty() ? nullptr : batch.vertices.data(); const glScreenSpaceParticleVertex_t* verts = batch.vertices.empty() ? nullptr : batch.vertices.data();
@@ -9538,7 +9783,6 @@ static void QD3D12_RunUpscalerOrBlit(QD3D12Window& w)
sl::Resource depth = { sl::ResourceType::eTex2d, w.depthBuffer.Get(), nullptr, nullptr, uint32_t(w.depthState) }; sl::Resource depth = { sl::ResourceType::eTex2d, w.depthBuffer.Get(), nullptr, nullptr, uint32_t(w.depthState) };
sl::Resource mvec = { sl::ResourceType::eTex2d, w.velocityBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.velocityBufferState[w.frameIndex]) }; sl::Resource mvec = { sl::ResourceType::eTex2d, w.velocityBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.velocityBufferState[w.frameIndex]) };
sl::Resource diffuseAlbedo = { sl::ResourceType::eTex2d, w.sceneColorBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.sceneColorState[w.frameIndex]) }; sl::Resource diffuseAlbedo = { sl::ResourceType::eTex2d, w.sceneColorBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.sceneColorState[w.frameIndex]) };
sl::Resource specularMvec = { sl::ResourceType::eTex2d, w.velocityBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.velocityBufferState[w.frameIndex]) };
sl::Resource specularAlbedo = { sl::ResourceType::eTex2d, w.specularBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.specularBufferState[w.frameIndex]) }; sl::Resource specularAlbedo = { sl::ResourceType::eTex2d, w.specularBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.specularBufferState[w.frameIndex]) };
sl::Resource normalRoughness = { sl::ResourceType::eTex2d, w.normalBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.normalBufferState[w.frameIndex]) }; sl::Resource normalRoughness = { sl::ResourceType::eTex2d, w.normalBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.normalBufferState[w.frameIndex]) };
@@ -9549,7 +9793,6 @@ static void QD3D12_RunUpscalerOrBlit(QD3D12Window& w)
sl::ResourceTag{ &depth, sl::kBufferTypeDepth, sl::ResourceLifecycle::eValidUntilPresent, &renderExtent }, sl::ResourceTag{ &depth, sl::kBufferTypeDepth, sl::ResourceLifecycle::eValidUntilPresent, &renderExtent },
sl::ResourceTag{ &mvec, sl::kBufferTypeMotionVectors, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent }, sl::ResourceTag{ &mvec, sl::kBufferTypeMotionVectors, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent },
sl::ResourceTag{ &diffuseAlbedo, sl::kBufferTypeAlbedo, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent }, sl::ResourceTag{ &diffuseAlbedo, sl::kBufferTypeAlbedo, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent },
sl::ResourceTag{ &specularMvec, sl::kBufferTypeSpecularMotionVectors, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent },
sl::ResourceTag{ &specularAlbedo, sl::kBufferTypeSpecularAlbedo, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent }, sl::ResourceTag{ &specularAlbedo, sl::kBufferTypeSpecularAlbedo, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent },
sl::ResourceTag{ &normalRoughness, sl::kBufferTypeNormalRoughness, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent } sl::ResourceTag{ &normalRoughness, sl::kBufferTypeNormalRoughness, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent }
}; };
@@ -10784,6 +11027,7 @@ static void QD3D12_CompileShaders()
g_gl.postPsScreenDecalBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSScreenDecals", "ps_6_0"); g_gl.postPsScreenDecalBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSScreenDecals", "ps_6_0");
g_gl.postVsScreenParticleBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "VSParticle", "vs_6_0"); g_gl.postVsScreenParticleBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "VSParticle", "vs_6_0");
g_gl.postPsScreenParticleBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSScreenParticles", "ps_6_5", L"QD3D12_SCREEN_PARTICLE_RAYQUERY=1"); g_gl.postPsScreenParticleBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSScreenParticles", "ps_6_5", L"QD3D12_SCREEN_PARTICLE_RAYQUERY=1");
g_gl.postPsSkyCloudsBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSSkyClouds", "ps_6_0");
} }
static const D3D12_INPUT_ELEMENT_DESC kGLVertexInputLayout[] = static const D3D12_INPUT_ELEMENT_DESC kGLVertexInputLayout[] =
@@ -11015,6 +11259,16 @@ static void QD3D12_CreatePSOs()
d.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE; d.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&d, IID_PPV_ARGS(&g_gl.postScreenDecalStainPSO))); QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&d, IID_PPV_ARGS(&g_gl.postScreenDecalStainPSO)));
d.PS = { g_gl.postPsSkyCloudsBlob->GetBufferPointer(), g_gl.postPsSkyCloudsBlob->GetBufferSize() };
d.BlendState.RenderTarget[0].BlendEnable = TRUE;
d.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
d.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
d.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
d.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
d.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
d.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&d, IID_PPV_ARGS(&g_gl.postSkyCloudsPSO)));
D3D12_GRAPHICS_PIPELINE_STATE_DESC particleDesc = d; D3D12_GRAPHICS_PIPELINE_STATE_DESC particleDesc = d;
particleDesc.VS = { g_gl.postVsScreenParticleBlob->GetBufferPointer(), g_gl.postVsScreenParticleBlob->GetBufferSize() }; particleDesc.VS = { g_gl.postVsScreenParticleBlob->GetBufferPointer(), g_gl.postVsScreenParticleBlob->GetBufferSize() };
particleDesc.PS = { g_gl.postPsScreenParticleBlob->GetBufferPointer(), g_gl.postPsScreenParticleBlob->GetBufferSize() }; particleDesc.PS = { g_gl.postPsScreenParticleBlob->GetBufferPointer(), g_gl.postPsScreenParticleBlob->GetBufferSize() };
@@ -17881,6 +18135,7 @@ PROC WINAPI qd3d12_wglGetProcAddress(LPCSTR name) {
{ "glDrawScreenSpaceDecalsQD3D12",(PROC)glDrawScreenSpaceDecalsQD3D12 }, { "glDrawScreenSpaceDecalsQD3D12",(PROC)glDrawScreenSpaceDecalsQD3D12 },
{ "glSetScreenSpaceParticleLightsQD3D12",(PROC)glSetScreenSpaceParticleLightsQD3D12 }, { "glSetScreenSpaceParticleLightsQD3D12",(PROC)glSetScreenSpaceParticleLightsQD3D12 },
{ "glDrawScreenSpaceParticlesQD3D12",(PROC)glDrawScreenSpaceParticlesQD3D12 }, { "glDrawScreenSpaceParticlesQD3D12",(PROC)glDrawScreenSpaceParticlesQD3D12 },
{ "glDrawSkyCloudsQD3D12", (PROC)glDrawSkyCloudsQD3D12 },
{ "QD3D12_SetUpscalerBackend", (PROC)QD3D12_SetUpscalerBackend }, { "QD3D12_SetUpscalerBackend", (PROC)QD3D12_SetUpscalerBackend },
{ "QD3D12_SetUpscalerQuality", (PROC)QD3D12_SetUpscalerQuality }, { "QD3D12_SetUpscalerQuality", (PROC)QD3D12_SetUpscalerQuality },
{ "QD3D12_SetUpscalerSharpness", (PROC)QD3D12_SetUpscalerSharpness }, { "QD3D12_SetUpscalerSharpness", (PROC)QD3D12_SetUpscalerSharpness },
+21
View File
@@ -1794,6 +1794,24 @@ typedef struct glScreenSpaceParticleVertex_s
float pad0; float pad0;
} glScreenSpaceParticleVertex_t; } glScreenSpaceParticleVertex_t;
typedef struct glSkyClouds_s
{
float skyColor[3];
float opacity;
float viewOrigin[3];
float zMin;
float viewForward[3];
float zMax;
float viewRight[3];
float tanHalfFovX;
float viewUp[3];
float tanHalfFovY;
float noiseScale;
float coverage;
float density;
float seedOffset;
} glSkyClouds_t;
int glRaytracingInit(void); int glRaytracingInit(void);
void glRaytracingShutdown(void); void glRaytracingShutdown(void);
void glRaytracingClear(void); void glRaytracingClear(void);
@@ -1893,6 +1911,7 @@ void glSetScreenSpaceDecalsQD3D12(const glScreenSpaceDecal
void glDrawScreenSpaceDecalsQD3D12(void); void glDrawScreenSpaceDecalsQD3D12(void);
void glSetScreenSpaceParticleLightsQD3D12(const glRaytracingLight_t* lights, uint32_t lightCount); void glSetScreenSpaceParticleLightsQD3D12(const glRaytracingLight_t* lights, uint32_t lightCount);
void glDrawScreenSpaceParticlesQD3D12(const glScreenSpaceParticleVertex_t* verts, uint32_t vertexCount, uint32_t textureId, uint32_t blendMode, float softDepth, float emissiveScale); void glDrawScreenSpaceParticlesQD3D12(const glScreenSpaceParticleVertex_t* verts, uint32_t vertexCount, uint32_t textureId, uint32_t blendMode, float softDepth, float emissiveScale);
void glDrawSkyCloudsQD3D12(const glSkyClouds_t* clouds);
ID3D12Device* QD3D12_GetDevice(void); ID3D12Device* QD3D12_GetDevice(void);
ID3D12CommandQueue* QD3D12_GetQueue(void); ID3D12CommandQueue* QD3D12_GetQueue(void);
@@ -2313,6 +2332,8 @@ void glUpdateTopLevelAceelStructure(
void glRaytracingLightingSetExternalDenoiser(int enable); void glRaytracingLightingSetExternalDenoiser(int enable);
void glRaytracingLightingUseExternalDenoiser(int enable); void glRaytracingLightingUseExternalDenoiser(int enable);
void glRaytracingLightingSetPathTracingOptions(uint32_t samplesPerPixel, uint32_t maxBounces, int enableDenoiser, float denoiseStrength); void glRaytracingLightingSetPathTracingOptions(uint32_t samplesPerPixel, uint32_t maxBounces, int enableDenoiser, float denoiseStrength);
void glRaytracingLightingSetGIAmount(float amount);
void glRaytracingLightingSetWorldGrime(float amount);
void glRaytracingLightingSetSecondaryLightBudget(int budget, float compensation); void glRaytracingLightingSetSecondaryLightBudget(int budget, float compensation);
void QD3D12_SetPathTracingQuality(uint32_t samplesPerPixel, uint32_t maxBounces); void QD3D12_SetPathTracingQuality(uint32_t samplesPerPixel, uint32_t maxBounces);
void QD3D12_SetPathTracingFallbackSamples(uint32_t samplesPerPixel); void QD3D12_SetPathTracingFallbackSamples(uint32_t samplesPerPixel);
@@ -189,6 +189,8 @@ idCVar r_showInteractionFrustums( "r_showInteractionFrustums", "0", CVAR_RENDERE
idCVar r_showInteractionScissors( "r_showInteractionScissors", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show screen rectangle which contains the interaction frustum, 2 = also draw construction lines", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); idCVar r_showInteractionScissors( "r_showInteractionScissors", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show screen rectangle which contains the interaction frustum, 2 = also draw construction lines", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
idCVar r_showLightCount( "r_showLightCount", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = colors surfaces based on light count, 2 = also count everything through walls, 3 = also print overdraw", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); idCVar r_showLightCount( "r_showLightCount", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = colors surfaces based on light count, 2 = also count everything through walls, 3 = also print overdraw", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
idCVar r_showPathTraceProfile( "r_showPathTraceProfile", "0", CVAR_RENDERER | CVAR_INTEGER, "report path tracer GPU and estimated ray workload, 1 = once per second, 2 = every frame", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); idCVar r_showPathTraceProfile( "r_showPathTraceProfile", "0", CVAR_RENDERER | CVAR_INTEGER, "report path tracer GPU and estimated ray workload, 1 = once per second, 2 = every frame", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
idCVar r_pathTraceGIAmount( "r_pathTraceGIAmount", "0.6", CVAR_RENDERER | CVAR_FLOAT, "scale path traced indirect GI, 0 = off, 1 = normal, values above 1 boost GI" );
idCVar r_pathTraceWorldGrime( "r_pathTraceWorldGrime", "1.5", CVAR_RENDERER | CVAR_FLOAT, "add stable cavity dirt to non-skeletal path traced surfaces, 0 = off" );
idCVar r_pathTraceSecondaryLightBudget( "r_pathTraceSecondaryLightBudget", "0", CVAR_RENDERER | CVAR_INTEGER, "secondary GI light budget, 0 = automatic, -1 = full light list" ); idCVar r_pathTraceSecondaryLightBudget( "r_pathTraceSecondaryLightBudget", "0", CVAR_RENDERER | CVAR_INTEGER, "secondary GI light budget, 0 = automatic, -1 = full light list" );
idCVar r_pathTraceSecondaryLightCompensation( "r_pathTraceSecondaryLightCompensation", "0.62", CVAR_RENDERER | CVAR_FLOAT, "energy compensation for capped secondary GI lights, 0 = none, 1 = full scale" ); idCVar r_pathTraceSecondaryLightCompensation( "r_pathTraceSecondaryLightCompensation", "0.62", CVAR_RENDERER | CVAR_FLOAT, "energy compensation for capped secondary GI lights, 0 = none, 1 = full scale" );
idCVar r_pathTracePortalWorldCulling( "r_pathTracePortalWorldCulling", "0", CVAR_RENDERER | CVAR_BOOL, "use portal flood to hide/show static world ray tracing instances" ); idCVar r_pathTracePortalWorldCulling( "r_pathTracePortalWorldCulling", "0", CVAR_RENDERER | CVAR_BOOL, "use portal flood to hide/show static world ray tracing instances" );
@@ -532,6 +534,8 @@ void R_InitOpenGL( void ) {
glRaytracingLightingSetExternalDenoiser(0); glRaytracingLightingSetExternalDenoiser(0);
glRaytracingLightingSetPathTracingOptions(1, 2, 1, 1.0f); glRaytracingLightingSetPathTracingOptions(1, 2, 1, 1.0f);
glRaytracingLightingSetGIAmount(r_pathTraceGIAmount.GetFloat());
glRaytracingLightingSetWorldGrime(r_pathTraceWorldGrime.GetFloat());
// Create the DXR worlds. // Create the DXR worlds.
for (int i = 0; i < DXR_WORLD_NUM; i++) for (int i = 0; i < DXR_WORLD_NUM; i++)
+2
View File
@@ -400,6 +400,8 @@ void RB_DXDrawInteractions(void)
{ {
backEnd.viewDef->renderWorld->SubmitWorldDecalsToScreenSpace(); backEnd.viewDef->renderWorld->SubmitWorldDecalsToScreenSpace();
glSetScreenSpaceParticleLightsQD3D12(screenParticleLights.Ptr(), screenParticleLights.Num()); glSetScreenSpaceParticleLightsQD3D12(screenParticleLights.Ptr(), screenParticleLights.Num());
glRaytracingLightingSetGIAmount(r_pathTraceGIAmount.GetFloat());
glRaytracingLightingSetWorldGrime(r_pathTraceWorldGrime.GetFloat());
glRaytracingLightingSetSecondaryLightBudget( glRaytracingLightingSetSecondaryLightBudget(
r_pathTraceSecondaryLightBudget.GetInteger(), r_pathTraceSecondaryLightBudget.GetInteger(),
r_pathTraceSecondaryLightCompensation.GetFloat()); r_pathTraceSecondaryLightCompensation.GetFloat());
+2
View File
@@ -960,6 +960,8 @@ extern idCVar r_showEntityScissors; // show entity scissor rectangles
extern idCVar r_showInteractionFrustums;// show a frustum for each interaction extern idCVar r_showInteractionFrustums;// show a frustum for each interaction
extern idCVar r_showInteractionScissors;// show screen rectangle which contains the interaction frustum extern idCVar r_showInteractionScissors;// show screen rectangle which contains the interaction frustum
extern idCVar r_showPathTraceProfile; // report path tracer GPU and estimated ray workload extern idCVar r_showPathTraceProfile; // report path tracer GPU and estimated ray workload
extern idCVar r_pathTraceGIAmount; // scale path traced indirect GI
extern idCVar r_pathTraceWorldGrime; // stable cavity dirt for non-skeletal path traced surfaces
extern idCVar r_pathTraceSecondaryLightBudget; // secondary GI light budget extern idCVar r_pathTraceSecondaryLightBudget; // secondary GI light budget
extern idCVar r_pathTraceSecondaryLightCompensation; // secondary GI energy compensation extern idCVar r_pathTraceSecondaryLightCompensation; // secondary GI energy compensation
extern idCVar r_pathTracePortalWorldCulling; // portal cull static ray tracing world instances extern idCVar r_pathTracePortalWorldCulling; // portal cull static ray tracing world instances
+106 -3
View File
@@ -11,6 +11,16 @@ static idCVar r_skyDomeRadius("r_skyDomeRadius", "8192", CVAR_RENDERER | CVAR_FL
static idCVar r_skyDomeRings("r_skyDomeRings", "24", CVAR_RENDERER | CVAR_INTEGER, "skydome vertical subdivisions"); static idCVar r_skyDomeRings("r_skyDomeRings", "24", CVAR_RENDERER | CVAR_INTEGER, "skydome vertical subdivisions");
static idCVar r_skyDomeSegments("r_skyDomeSegments", "48", CVAR_RENDERER | CVAR_INTEGER, "skydome horizontal subdivisions"); static idCVar r_skyDomeSegments("r_skyDomeSegments", "48", CVAR_RENDERER | CVAR_INTEGER, "skydome horizontal subdivisions");
static idCVar r_skyClouds("r_skyClouds", "1", CVAR_RENDERER | CVAR_BOOL, "render automatic raymarched sky clouds");
static idCVar r_skyCloudZMin("r_skyCloudZMin", "2600", CVAR_RENDERER | CVAR_FLOAT, "sky cloud slab minimum world z");
static idCVar r_skyCloudZMax("r_skyCloudZMax", "7600", CVAR_RENDERER | CVAR_FLOAT, "sky cloud slab maximum world z");
static idCVar r_skyCloudScale("r_skyCloudScale", "0.00021", CVAR_RENDERER | CVAR_FLOAT, "sky cloud world noise scale");
static idCVar r_skyCloudCoverage("r_skyCloudCoverage", "0.30", CVAR_RENDERER | CVAR_FLOAT, "sky cloud coverage threshold, lower is denser");
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 void R_UploadSkyDomeMeshToVertexCache(srfTriangles_t* tri) { static void R_UploadSkyDomeMeshToVertexCache(srfTriangles_t* tri) {
if (!tri) { if (!tri) {
return; return;
@@ -131,6 +141,97 @@ static srfTriangles_t* R_BuildSkyDomeMesh(int rings, int segs, float radius) {
return tri; return tri;
} }
static idImage* R_GetSkyDomeImage() {
if (!g_skyDomeMat || g_skyDomeMat->GetNumStages() <= 0) {
return NULL;
}
const shaderStage_t* stage = g_skyDomeMat->GetStage(0);
if (!stage || !stage->texture.image) {
return NULL;
}
return stage->texture.image;
}
static void R_GetSkyAverageColor(float color[3]) {
color[0] = 0.16f;
color[1] = 0.28f;
color[2] = 0.48f;
idImage* skyImage = R_GetSkyDomeImage();
if (!skyImage) {
return;
}
skyImage->Bind();
const float* average = skyImage->GetAverageColor();
if (!average) {
return;
}
color[0] = idMath::ClampFloat(0.03f, 1.0f, average[0]);
color[1] = idMath::ClampFloat(0.03f, 1.0f, average[1]);
color[2] = idMath::ClampFloat(0.03f, 1.0f, average[2]);
}
static void R_GetSkyCloudColor(float color[3]) {
R_GetSkyAverageColor(color);
float overrideColor[3];
if (sscanf(r_skyCloudColor.GetString(), "%f %f %f", &overrideColor[0], &overrideColor[1], &overrideColor[2]) != 3) {
return;
}
const bool byteColor = overrideColor[0] > 1.0f || overrideColor[1] > 1.0f || overrideColor[2] > 1.0f;
const float scale = byteColor ? (1.0f / 255.0f) : 1.0f;
color[0] = idMath::ClampFloat(0.0f, 1.0f, overrideColor[0] * scale);
color[1] = idMath::ClampFloat(0.0f, 1.0f, overrideColor[1] * scale);
color[2] = idMath::ClampFloat(0.0f, 1.0f, overrideColor[2] * scale);
}
static void RB_DrawSkyCloudOverlay(const viewDef_t* viewDef) {
if (!viewDef || !r_skyClouds.GetBool()) {
return;
}
glSkyClouds_t clouds;
memset(&clouds, 0, sizeof(clouds));
R_GetSkyCloudColor(clouds.skyColor);
clouds.opacity = idMath::ClampFloat(0.0f, 1.0f, r_skyCloudOpacity.GetFloat());
const idVec3& viewOrg = viewDef->renderView.vieworg;
clouds.viewOrigin[0] = viewOrg.x;
clouds.viewOrigin[1] = viewOrg.y;
clouds.viewOrigin[2] = viewOrg.z;
clouds.zMin = r_skyCloudZMin.GetFloat();
clouds.zMax = Max(r_skyCloudZMax.GetFloat(), clouds.zMin + 64.0f);
const idMat3& axis = viewDef->renderView.viewaxis;
clouds.viewForward[0] = axis[0].x;
clouds.viewForward[1] = axis[0].y;
clouds.viewForward[2] = axis[0].z;
clouds.viewRight[0] = -axis[1].x;
clouds.viewRight[1] = -axis[1].y;
clouds.viewRight[2] = -axis[1].z;
clouds.viewUp[0] = axis[2].x;
clouds.viewUp[1] = axis[2].y;
clouds.viewUp[2] = axis[2].z;
clouds.tanHalfFovX = idMath::Tan(DEG2RAD(viewDef->renderView.fov_x * 0.5f));
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.seedOffset = r_skyCloudSeedOffset.GetFloat();
glDrawSkyCloudsQD3D12(&clouds);
}
void R_InitSkyDome() { void R_InitSkyDome() {
if (g_skyDomeTri) { if (g_skyDomeTri) {
return; return;
@@ -198,10 +299,10 @@ void RB_DrawSkyDome(const viewDef_t* viewDef) {
GL_SelectTexture(0); GL_SelectTexture(0);
const shaderStage_t* stage = g_skyDomeMat->GetStage(0); idImage* skyImage = R_GetSkyDomeImage();
if (stage && stage->texture.image) { if (skyImage) {
stage->texture.image->Bind(); skyImage->Bind();
} }
else { else {
globalImages->whiteImage->Bind(); globalImages->whiteImage->Bind();
@@ -228,10 +329,12 @@ void RB_DrawSkyDome(const viewDef_t* viewDef) {
glGeometryFlagf(GEOMETRY_FLAG_UNLIT); glGeometryFlagf(GEOMETRY_FLAG_UNLIT);
RB_DrawElementsWithCounters(g_skyDomeTri); RB_DrawElementsWithCounters(g_skyDomeTri);
RB_DrawSkyCloudOverlay(viewDef);
glGeometryFlagf(GEOMETRY_FLAG_NONE); glGeometryFlagf(GEOMETRY_FLAG_NONE);
glPopMatrix(); glPopMatrix();
GL_State(GLS_DEFAULT);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
+2
View File
@@ -593,6 +593,8 @@ BEGIN
POPUP "&Misc" POPUP "&Misc"
BEGIN BEGIN
MENUITEM "&Benchmark", ID_MISC_BENCHMARK MENUITEM "&Benchmark", ID_MISC_BENCHMARK
MENUITEM "Automatic City Builder", ID_TOOLS_AUTOMATICCITYBUILDER
MENUITEM SEPARATOR
POPUP "&Colors" POPUP "&Colors"
BEGIN BEGIN
POPUP "Themes" POPUP "Themes"
+2 -1
View File
@@ -872,6 +872,7 @@ If you have questions concerning this license or the applicable additional terms
#define ID_SELECTION_VIEW_WIREFRAMEOFF 30403 #define ID_SELECTION_VIEW_WIREFRAMEOFF 30403
#define ID_SELECTION_VIEW_VISIBLEON 30404 #define ID_SELECTION_VIEW_VISIBLEON 30404
#define ID_SELECTION_VIEW_VISIBLEOFF 30405 #define ID_SELECTION_VIEW_VISIBLEOFF 30405
#define ID_TOOLS_AUTOMATICCITYBUILDER 30406
#define ID_ENTITY_START 40000 #define ID_ENTITY_START 40000
#define ID_ENTITY_END 45000 #define ID_ENTITY_END 45000
@@ -881,7 +882,7 @@ If you have questions concerning this license or the applicable additional terms
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS 1 #define _APS_3D_CONTROLS 1
#define _APS_NEXT_RESOURCE_VALUE 10083 #define _APS_NEXT_RESOURCE_VALUE 10083
#define _APS_NEXT_COMMAND_VALUE 30406 #define _APS_NEXT_COMMAND_VALUE 30407
#define _APS_NEXT_CONTROL_VALUE 10555 #define _APS_NEXT_CONTROL_VALUE 10555
#define _APS_NEXT_SYMED_VALUE 10083 #define _APS_NEXT_SYMED_VALUE 10083
#endif #endif
+1 -1
View File
@@ -848,7 +848,7 @@ static void WriteOutputEntity( int entityNum ) {
} }
if ( entityNum == 0 ) { if ( entityNum == 0 ) {
WritePathTraceAreas( e ); // WritePathTraceAreas( e );
} }
} }
+568
View File
@@ -0,0 +1,568 @@
/*
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
This file is part of the IceTech GPL Source Code.
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
#include "qe3.h"
#include "CityBuilder.h"
extern int mapModified;
namespace {
struct cityStats_t {
int brushes;
int entities;
int buildings;
int streets;
};
struct cityBounds_t {
idVec3 mins;
idVec3 maxs;
};
static const float CITY_DEFAULT_HALF_SIZE = 4096.0f;
static const float CITY_MIN_SIZE = 3072.0f;
static const float CITY_MAX_SIZE = 65536.0f;
static const float CITY_ROAD_PITCH = 1152.0f;
static const float CITY_ROAD_WIDTH = 256.0f;
static const float CITY_SIDEWALK_WIDTH = 80.0f;
static const float CITY_CURB_WIDTH = 12.0f;
static const float CITY_CEILING_HEIGHT = 1536.0f;
static const float CITY_TEXTURE_SIZE = 1024.0f;
static const float CITY_ROAD_TEXTURE_LENGTH = 512.0f;
static const float CITY_SIDEWALK_TEXTURE_LENGTH = 256.0f;
static const float CITY_BUILDING_TEXTURE_WIDTH = 256.0f;
static const float CITY_BUILDING_TEXTURE_HEIGHT = 384.0f;
static const float CITY_BUILDING_EDGE_SETBACK = 96.0f;
static const float CITY_BUILDING_LOT_SIZE = 640.0f;
static const float CITY_BUILDING_ALLEY = 56.0f;
static const float CITY_POINT_LIGHT_RADIUS = 300000.0f;
static const char* CITY_MAT_MARS_DIRT = "textures/mars_citybuilder/mars_dirt";
static const char* CITY_MAT_MARS_ROAD = "textures/mars_citybuilder/mars_road_dusty_center";
static const char* CITY_MAT_MARS_ROAD_EAST_WEST = "textures/mars_citybuilder/mars_road_dusty_center_east_west";
static const char* CITY_MAT_MARS_ROAD_INTERSECTION = "textures/mars_citybuilder/mars_road_dusty_intersection";
static const char* CITY_MAT_MARS_SIDEWALK = "textures/mars_citybuilder/mars_sidewalk_dusty";
static const char* CITY_MAT_MARS_BUILDING_01 = "textures/mars_citybuilder/mars_building_dark_01";
static const char* CITY_MAT_MARS_BUILDING_02 = "textures/mars_citybuilder/mars_building_dark_02";
static const idVec3 CITY_POINT_LIGHT_ORIGIN(-3200.0f, 3336.0f, 0.0f);
static const idVec3 CITY_POINT_LIGHT_COLOR(242.0f / 255.0f, 160.0f / 255.0f, 130.0f / 255.0f);
static float City_ClampFloat(float v, float minValue, float maxValue) {
if (v < minValue) {
return minValue;
}
if (v > maxValue) {
return maxValue;
}
return v;
}
static int City_ClampInt(int v, int minValue, int maxValue) {
if (v < minValue) {
return minValue;
}
if (v > maxValue) {
return maxValue;
}
return v;
}
static unsigned int City_Hash(int x, int y, int salt) {
unsigned int h = (unsigned int)(x * 73856093) ^ (unsigned int)(y * 19349663) ^ (unsigned int)(salt * 83492791);
h ^= h >> 13;
h *= 1274126177u;
h ^= h >> 16;
return h;
}
static float City_Random01(int x, int y, int salt) {
return (City_Hash(x, y, salt) & 0xffff) / 65535.0f;
}
static float City_TexScale(float worldUnits) {
return worldUnits / CITY_TEXTURE_SIZE;
}
static float City_TexShift(float worldCoord, float scale) {
if (scale == 0.0f) {
return 0.0f;
}
float shift = fmod(-worldCoord / scale, CITY_TEXTURE_SIZE);
if (shift < 0.0f) {
shift += CITY_TEXTURE_SIZE;
}
return shift;
}
static void City_SetTexdef(texdef_t& td, const char* material, float scale0 = 0.5f, float scale1 = 0.5f, float rotate = 0.0f, float shift0 = 0.0f, float shift1 = 0.0f) {
td.SetName(material);
td.shift[0] = shift0;
td.shift[1] = shift1;
td.rotate = rotate;
td.scale[0] = scale0;
td.scale[1] = scale1;
}
static idEditorBrush* City_AddWorldBrushUV(const idVec3& mins, const idVec3& maxs, const char* material, float scale0, float scale1, float rotate, float shift0, float shift1, cityStats_t& stats) {
if (mins.x >= maxs.x || mins.y >= maxs.y || mins.z >= maxs.z || world_entity == NULL) {
return NULL;
}
texdef_t td;
City_SetTexdef(td, material, scale0, scale1, rotate, shift0, shift1);
idEditorBrush* b = Brush_Create(mins, maxs, &td);
if (b == NULL) {
return NULL;
}
b->Brush_AddToList(&active_brushes);
world_entity->Entity_LinkBrush(b);
b->Brush_Build();
Undo_EndBrush(b);
stats.brushes++;
return b;
}
static idEditorBrush* City_AddWorldBrush(const idVec3& mins, const idVec3& maxs, const char* material, cityStats_t& stats) {
return City_AddWorldBrushUV(mins, maxs, material, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, stats);
}
static idEditorBrush* City_AddVerticalRoadBrush(float x, float y0, float y1, const cityBounds_t& bounds, cityStats_t& stats) {
const float roadHalf = CITY_ROAD_WIDTH * 0.5f;
const float scale0 = City_TexScale(CITY_ROAD_WIDTH);
const float scale1 = City_TexScale(CITY_ROAD_TEXTURE_LENGTH);
const idVec3 mins(x - roadHalf, y0, bounds.mins.z);
const idVec3 maxs(x + roadHalf, y1, bounds.mins.z + 8.0f);
return City_AddWorldBrushUV(mins, maxs, CITY_MAT_MARS_ROAD_EAST_WEST, scale0, scale1, 0.0f, City_TexShift(mins.x, scale0), City_TexShift(mins.y, scale1), stats);
}
static idEditorBrush* City_AddHorizontalRoadBrush(float x0, float x1, float y, const cityBounds_t& bounds, cityStats_t& stats) {
const float roadHalf = CITY_ROAD_WIDTH * 0.5f;
const float scale0 = City_TexScale(CITY_ROAD_TEXTURE_LENGTH);
const float scale1 = City_TexScale(CITY_ROAD_WIDTH);
const idVec3 mins(x0, y - roadHalf, bounds.mins.z);
const idVec3 maxs(x1, y + roadHalf, bounds.mins.z + 8.0f);
return City_AddWorldBrushUV(mins, maxs, CITY_MAT_MARS_ROAD, scale0, scale1, 0.0f, City_TexShift(mins.x, scale0), City_TexShift(mins.y, scale1), stats);
}
static idEditorBrush* City_AddIntersectionRoadBrush(float x, float y, const cityBounds_t& bounds, cityStats_t& stats) {
const float roadHalf = CITY_ROAD_WIDTH * 0.5f;
const float scale = City_TexScale(CITY_ROAD_WIDTH);
const idVec3 mins(x - roadHalf, y - roadHalf, bounds.mins.z);
const idVec3 maxs(x + roadHalf, y + roadHalf, bounds.mins.z + 8.0f);
return City_AddWorldBrushUV(mins, maxs, CITY_MAT_MARS_ROAD_INTERSECTION, scale, scale, 0.0f, City_TexShift(mins.x, scale), City_TexShift(mins.y, scale), stats);
}
static idEditorBrush* City_AddVerticalSidewalkBrush(float x0, float x1, float y0, float y1, const cityBounds_t& bounds, cityStats_t& stats) {
const float scale0 = City_TexScale(CITY_SIDEWALK_WIDTH);
const float scale1 = City_TexScale(CITY_SIDEWALK_TEXTURE_LENGTH);
const idVec3 mins(x0, y0, bounds.mins.z);
const idVec3 maxs(x1, y1, bounds.mins.z + 8.0f);
return City_AddWorldBrushUV(mins, maxs, CITY_MAT_MARS_SIDEWALK, scale0, scale1, 0.0f, City_TexShift(mins.x, scale0), City_TexShift(mins.y, scale1), stats);
}
static idEditorBrush* City_AddHorizontalSidewalkBrush(float x0, float x1, float y0, float y1, const cityBounds_t& bounds, cityStats_t& stats) {
const float scale0 = City_TexScale(CITY_SIDEWALK_TEXTURE_LENGTH);
const float scale1 = City_TexScale(CITY_SIDEWALK_WIDTH);
const idVec3 mins(x0, y0, bounds.mins.z);
const idVec3 maxs(x1, y1, bounds.mins.z + 8.0f);
return City_AddWorldBrushUV(mins, maxs, CITY_MAT_MARS_SIDEWALK, scale0, scale1, 0.0f, City_TexShift(mins.x, scale0), City_TexShift(mins.y, scale1), stats);
}
static idEditorBrush* City_AddBuildingBrush(const idVec3& mins, const idVec3& maxs, const char* material, cityStats_t& stats) {
const float scale0 = City_TexScale(CITY_BUILDING_TEXTURE_WIDTH);
const float scale1 = City_TexScale(CITY_BUILDING_TEXTURE_HEIGHT);
return City_AddWorldBrushUV(mins, maxs, material, scale0, scale1, 0.0f, 0.0f, City_TexShift(mins.z, scale1), stats);
}
static void City_SetVecKey(idEditorEntity* ent, const char* key, const idVec3& value) {
ent->SetKeyValue(key, va("%i %i %i", (int)value.x, (int)value.y, (int)value.z));
}
static idEditorEntity* City_AddFixedEntity(const char* classname, const idVec3& origin, cityStats_t& stats) {
idEditorEntity* ent = idEditorEntity::Entity_New();
if (ent == NULL) {
return NULL;
}
ent->brushes.onext = ent->brushes.oprev = &ent->brushes;
ent->origin = origin;
ent->SetKeyValue("classname", classname);
City_SetVecKey(ent, "origin", origin);
ent->Entity_Name(false);
ent->Entity_PostParse(&active_brushes);
ent->Entity_AddToList(&entities);
g_qeglobals.d_num_entities++;
Undo_EndEntity(ent);
for (idEditorBrush* b = ent->brushes.onext; b != &ent->brushes; b = b->onext) {
b->Brush_Build();
Undo_EndBrush(b);
stats.brushes++;
}
stats.entities++;
return ent;
}
static cityBounds_t City_GetTargetBounds() {
cityBounds_t bounds;
bounds.mins.Set(-CITY_DEFAULT_HALF_SIZE, -CITY_DEFAULT_HALF_SIZE, 0.0f);
bounds.maxs.Set(CITY_DEFAULT_HALF_SIZE, CITY_DEFAULT_HALF_SIZE, CITY_CEILING_HEIGHT);
if (selected_brushes.next != NULL && selected_brushes.next != &selected_brushes) {
idVec3 mins(999999.0f, 999999.0f, 999999.0f);
idVec3 maxs(-999999.0f, -999999.0f, -999999.0f);
for (idEditorBrush* b = selected_brushes.next; b != &selected_brushes; b = b->next) {
for (int i = 0; i < 3; i++) {
if (b->mins[i] < mins[i]) {
mins[i] = b->mins[i];
}
if (b->maxs[i] > maxs[i]) {
maxs[i] = b->maxs[i];
}
}
}
if ((maxs.x - mins.x) >= 128.0f && (maxs.y - mins.y) >= 128.0f) {
bounds.mins.x = mins.x;
bounds.mins.y = mins.y;
bounds.mins.z = mins.z;
bounds.maxs.x = maxs.x;
bounds.maxs.y = maxs.y;
bounds.maxs.z = mins.z + CITY_CEILING_HEIGHT;
}
}
const float centerX = (bounds.mins.x + bounds.maxs.x) * 0.5f;
const float centerY = (bounds.mins.y + bounds.maxs.y) * 0.5f;
float width = City_ClampFloat(bounds.maxs.x - bounds.mins.x, CITY_MIN_SIZE, CITY_MAX_SIZE);
float depth = City_ClampFloat(bounds.maxs.y - bounds.mins.y, CITY_MIN_SIZE, CITY_MAX_SIZE);
width = floor(width / 64.0f) * 64.0f;
depth = floor(depth / 64.0f) * 64.0f;
bounds.mins.x = centerX - width * 0.5f;
bounds.maxs.x = centerX + width * 0.5f;
bounds.mins.y = centerY - depth * 0.5f;
bounds.maxs.y = centerY + depth * 0.5f;
bounds.maxs.z = bounds.mins.z + CITY_CEILING_HEIGHT;
return bounds;
}
static void City_AddVerticalStreetEdges(float x, float y0, float y1, const cityBounds_t& bounds, cityStats_t& stats) {
if (y1 <= y0) {
return;
}
const float z0 = bounds.mins.z;
const float roadHalf = CITY_ROAD_WIDTH * 0.5f;
const float sideHalf = roadHalf + CITY_SIDEWALK_WIDTH;
City_AddVerticalSidewalkBrush(x - sideHalf, x - roadHalf, y0, y1, bounds, stats);
City_AddVerticalSidewalkBrush(x + roadHalf, x + sideHalf, y0, y1, bounds, stats);
City_AddWorldBrush(
idVec3(x - roadHalf - CITY_CURB_WIDTH, y0, z0 + 8.0f),
idVec3(x - roadHalf, y1, z0 + 14.0f),
"textures/base_wall/steel",
stats);
City_AddWorldBrush(
idVec3(x + roadHalf, y0, z0 + 8.0f),
idVec3(x + roadHalf + CITY_CURB_WIDTH, y1, z0 + 14.0f),
"textures/base_wall/steel",
stats);
}
static void City_AddHorizontalStreetEdges(float y, float x0, float x1, const cityBounds_t& bounds, cityStats_t& stats) {
if (x1 <= x0) {
return;
}
const float z0 = bounds.mins.z;
const float roadHalf = CITY_ROAD_WIDTH * 0.5f;
const float sideHalf = roadHalf + CITY_SIDEWALK_WIDTH;
City_AddHorizontalSidewalkBrush(x0, x1, y - sideHalf, y - roadHalf, bounds, stats);
City_AddHorizontalSidewalkBrush(x0, x1, y + roadHalf, y + sideHalf, bounds, stats);
City_AddWorldBrush(
idVec3(x0, y - roadHalf - CITY_CURB_WIDTH, z0 + 8.0f),
idVec3(x1, y - roadHalf, z0 + 14.0f),
"textures/base_wall/steel",
stats);
City_AddWorldBrush(
idVec3(x0, y + roadHalf, z0 + 8.0f),
idVec3(x1, y + roadHalf + CITY_CURB_WIDTH, z0 + 14.0f),
"textures/base_wall/steel",
stats);
}
static void City_AddVerticalStreetEdges(float x, const cityBounds_t& bounds, const idList<float>& blockers, cityStats_t& stats) {
const float clearHalf = CITY_ROAD_WIDTH * 0.5f + CITY_SIDEWALK_WIDTH;
float y0 = bounds.mins.y;
for (int i = 0; i < blockers.Num(); i++) {
const float y1 = blockers[i] - clearHalf;
City_AddVerticalStreetEdges(x, y0, y1, bounds, stats);
y0 = blockers[i] + clearHalf;
}
City_AddVerticalStreetEdges(x, y0, bounds.maxs.y, bounds, stats);
}
static void City_AddHorizontalStreetEdges(float y, const cityBounds_t& bounds, const idList<float>& blockers, cityStats_t& stats) {
const float clearHalf = CITY_ROAD_WIDTH * 0.5f + CITY_SIDEWALK_WIDTH;
float x0 = bounds.mins.x;
for (int i = 0; i < blockers.Num(); i++) {
const float x1 = blockers[i] - clearHalf;
City_AddHorizontalStreetEdges(y, x0, x1, bounds, stats);
x0 = blockers[i] + clearHalf;
}
City_AddHorizontalStreetEdges(y, x0, bounds.maxs.x, bounds, stats);
}
static void City_AddStreetSign(float x, float y, int avenue, int street, const cityBounds_t& bounds, cityStats_t& stats) {
const float z0 = bounds.mins.z;
const float poleX = x + CITY_ROAD_WIDTH * 0.5f + 44.0f;
const float poleY = y - CITY_ROAD_WIDTH * 0.5f - 44.0f;
City_AddWorldBrush(idVec3(poleX - 4.0f, poleY - 4.0f, z0 + 8.0f), idVec3(poleX + 4.0f, poleY + 4.0f, z0 + 128.0f), "textures/base_wall/steel", stats);
City_AddWorldBrush(idVec3(poleX - 56.0f, poleY - 5.0f, z0 + 112.0f), idVec3(poleX + 56.0f, poleY + 5.0f, z0 + 136.0f), "textures/base_wall/greenpanel1", stats);
City_AddWorldBrush(idVec3(poleX - 5.0f, poleY - 56.0f, z0 + 140.0f), idVec3(poleX + 5.0f, poleY + 56.0f, z0 + 164.0f), "textures/base_wall/greenpanel1", stats);
common->Printf("Automatic City Builder: street node A%i / S%i at %.0f %.0f\n", avenue + 1, street + 1, x, y);
}
static void City_AddRoads(const cityBounds_t& bounds, idList<float>& roadX, idList<float>& roadY, cityStats_t& stats) {
const float roadHalf = CITY_ROAD_WIDTH * 0.5f;
const int xRoads = City_ClampInt((int)((bounds.maxs.x - bounds.mins.x) / CITY_ROAD_PITCH), 2, 64);
const int yRoads = City_ClampInt((int)((bounds.maxs.y - bounds.mins.y) / CITY_ROAD_PITCH), 2, 64);
const float xStep = (bounds.maxs.x - bounds.mins.x) / (float)xRoads;
const float yStep = (bounds.maxs.y - bounds.mins.y) / (float)yRoads;
for (int i = 1; i < xRoads; i++) {
roadX.Append(bounds.mins.x + xStep * i);
}
for (int i = 1; i < yRoads; i++) {
roadY.Append(bounds.mins.y + yStep * i);
}
for (int i = 0; i < roadX.Num(); i++) {
const float x = roadX[i];
for (int segment = 0; segment <= roadY.Num(); segment++) {
const float y0 = (segment == 0) ? bounds.mins.y : roadY[segment - 1] + roadHalf;
const float y1 = (segment == roadY.Num()) ? bounds.maxs.y : roadY[segment] - roadHalf;
City_AddVerticalRoadBrush(x, y0, y1, bounds, stats);
}
City_AddVerticalStreetEdges(x, bounds, roadY, stats);
stats.streets++;
}
for (int i = 0; i < roadY.Num(); i++) {
const float y = roadY[i];
for (int segment = 0; segment <= roadX.Num(); segment++) {
const float x0 = (segment == 0) ? bounds.mins.x : roadX[segment - 1] + roadHalf;
const float x1 = (segment == roadX.Num()) ? bounds.maxs.x : roadX[segment] - roadHalf;
City_AddHorizontalRoadBrush(x0, x1, y, bounds, stats);
}
City_AddHorizontalStreetEdges(y, bounds, roadX, stats);
stats.streets++;
}
for (int x = 0; x < roadX.Num(); x++) {
for (int y = 0; y < roadY.Num(); y++) {
City_AddIntersectionRoadBrush(roadX[x], roadY[y], bounds, stats);
if (((x + y) & 1) == 0) {
City_AddStreetSign(roadX[x], roadY[y], x, y, bounds, stats);
}
}
}
}
static void City_AddDirtLot(const cityBounds_t& bounds, float minX, float minY, float maxX, float maxY, cityStats_t& stats) {
if (maxX - minX <= 1.0f || maxY - minY <= 1.0f) {
return;
}
City_AddWorldBrush(
idVec3(minX, minY, bounds.mins.z),
idVec3(maxX, maxY, bounds.mins.z + 8.0f),
CITY_MAT_MARS_DIRT,
stats);
}
static void City_AddDirtLots(const cityBounds_t& bounds, const idList<float>& roadX, const idList<float>& roadY, cityStats_t& stats) {
const float clearHalf = CITY_ROAD_WIDTH * 0.5f + CITY_SIDEWALK_WIDTH;
float y0 = bounds.mins.y;
for (int y = 0; y <= roadY.Num(); y++) {
const float y1 = (y == roadY.Num()) ? bounds.maxs.y : roadY[y] - clearHalf;
float x0 = bounds.mins.x;
for (int x = 0; x <= roadX.Num(); x++) {
const float x1 = (x == roadX.Num()) ? bounds.maxs.x : roadX[x] - clearHalf;
City_AddDirtLot(bounds, x0, y0, x1, y1, stats);
if (x < roadX.Num()) {
x0 = roadX[x] + clearHalf;
}
}
if (y < roadY.Num()) {
y0 = roadY[y] + clearHalf;
}
}
}
static const char* City_BuildingMaterial(int x, int y) {
static const char* materials[] = {
CITY_MAT_MARS_BUILDING_01,
CITY_MAT_MARS_BUILDING_02
};
return materials[City_Hash(x, y, 17) % (sizeof(materials) / sizeof(materials[0]))];
}
static void City_AddBuilding(float minX, float minY, float maxX, float maxY, float baseZ, int gx, int gy, cityStats_t& stats) {
const int floors = 2 + (City_Hash(gx, gy, 31) % 8);
const float z0 = baseZ + 8.0f;
const float z1 = z0 + 96.0f * floors + City_Random01(gx, gy, 23) * 64.0f;
idVec3 mins(minX, minY, z0);
idVec3 maxs(maxX, maxY, z1);
City_AddBuildingBrush(mins, maxs, City_BuildingMaterial(gx, gy), stats);
City_AddWorldBrush(idVec3(minX - 8.0f, minY - 8.0f, z1), idVec3(maxX + 8.0f, maxY + 8.0f, z1 + 16.0f), CITY_MAT_MARS_DIRT, stats);
stats.buildings++;
}
static void City_AddBlockBuildings(const cityBounds_t& bounds, float minX, float minY, float maxX, float maxY, int blockX, int blockY, cityStats_t& stats) {
minX += CITY_BUILDING_EDGE_SETBACK;
minY += CITY_BUILDING_EDGE_SETBACK;
maxX -= CITY_BUILDING_EDGE_SETBACK;
maxY -= CITY_BUILDING_EDGE_SETBACK;
if (maxX - minX < 128.0f || maxY - minY < 128.0f) {
return;
}
const int lotsX = City_ClampInt((int)((maxX - minX) / CITY_BUILDING_LOT_SIZE), 1, 2);
const int lotsY = City_ClampInt((int)((maxY - minY) / CITY_BUILDING_LOT_SIZE), 1, 2);
const float stepX = (maxX - minX) / (float)lotsX;
const float stepY = (maxY - minY) / (float)lotsY;
for (int y = 0; y < lotsY; y++) {
for (int x = 0; x < lotsX; x++) {
if ((City_Hash(blockX * 17 + x, blockY * 19 + y, 7) % 100) < 22) {
continue;
}
float cellMinX = minX + x * stepX + CITY_BUILDING_ALLEY;
float cellMinY = minY + y * stepY + CITY_BUILDING_ALLEY;
float cellMaxX = minX + (x + 1) * stepX - CITY_BUILDING_ALLEY;
float cellMaxY = minY + (y + 1) * stepY - CITY_BUILDING_ALLEY;
if (cellMaxX - cellMinX < 96.0f || cellMaxY - cellMinY < 96.0f) {
continue;
}
const float shrinkX = City_Random01(blockX * 31 + x, blockY * 37 + y, 11) * 24.0f;
const float shrinkY = City_Random01(blockX * 31 + x, blockY * 37 + y, 13) * 24.0f;
City_AddBuilding(
cellMinX + shrinkX,
cellMinY + shrinkY,
cellMaxX - shrinkX,
cellMaxY - shrinkY,
bounds.mins.z,
blockX * 10 + x,
blockY * 10 + y,
stats);
}
}
}
static void City_AddBuildings(const cityBounds_t& bounds, const idList<float>& roadX, const idList<float>& roadY, cityStats_t& stats) {
const float clearHalf = CITY_ROAD_WIDTH * 0.5f + CITY_SIDEWALK_WIDTH;
float y0 = bounds.mins.y;
for (int y = 0; y <= roadY.Num(); y++) {
const float y1 = (y == roadY.Num()) ? bounds.maxs.y : roadY[y] - clearHalf;
float x0 = bounds.mins.x;
for (int x = 0; x <= roadX.Num(); x++) {
const float x1 = (x == roadX.Num()) ? bounds.maxs.x : roadX[x] - clearHalf;
City_AddBlockBuildings(bounds, x0, y0, x1, y1, x, y, stats);
if (x < roadX.Num()) {
x0 = roadX[x] + clearHalf;
}
}
if (y < roadY.Num()) {
y0 = roadY[y] + clearHalf;
}
}
}
static void City_AddPlayerStart(const cityBounds_t& bounds, cityStats_t& stats) {
City_AddFixedEntity("info_player_start", idVec3(bounds.mins.x + 192.0f, bounds.mins.y + 192.0f, bounds.mins.z + 48.0f), stats);
}
static void City_AddPointLight(cityStats_t& stats) {
idEditorEntity* ent = City_AddFixedEntity("light", CITY_POINT_LIGHT_ORIGIN, stats);
if (ent == NULL) {
return;
}
ent->SetKeyValue("_color", va("%.3f %.3f %.3f", CITY_POINT_LIGHT_COLOR.x, CITY_POINT_LIGHT_COLOR.y, CITY_POINT_LIGHT_COLOR.z));
ent->SetKeyValue("light_radius", va("%i %i %i", (int)CITY_POINT_LIGHT_RADIUS, (int)CITY_POINT_LIGHT_RADIUS, (int)CITY_POINT_LIGHT_RADIUS));
}
} // namespace
void Radiant_GenerateAutomaticCity() {
if (world_entity == NULL) {
Sys_Status("Automatic City Builder needs an open map\n");
Sys_Beep();
return;
}
Sys_BeginWait();
Undo_Start("automatic city");
cityStats_t stats;
stats.brushes = 0;
stats.entities = 0;
stats.buildings = 0;
stats.streets = 0;
idList<float> roadX;
idList<float> roadY;
const cityBounds_t bounds = City_GetTargetBounds();
Select_Deselect();
City_AddRoads(bounds, roadX, roadY, stats);
City_AddDirtLots(bounds, roadX, roadY, stats);
City_AddBuildings(bounds, roadX, roadY, stats);
City_AddPlayerStart(bounds, stats);
City_AddPointLight(stats);
Map_BuildBrushData();
Sys_UpdateWindows(W_ALL);
mapModified = 1;
Undo_End();
Sys_EndWait();
common->Printf("Automatic City Builder: %i streets, %i buildings, %i brushes, %i entities\n", stats.streets, stats.buildings, stats.brushes, stats.entities);
Sys_Status(va("Automatic City Builder: %i streets, %i buildings generated", stats.streets, stats.buildings), 0);
}
+17
View File
@@ -0,0 +1,17 @@
/*
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
This file is part of the IceTech GPL Source Code.
===========================================================================
*/
#ifndef __RADIANT_CITYBUILDER_H__
#define __RADIANT_CITYBUILDER_H__
void Radiant_GenerateAutomaticCity();
#endif
+6
View File
@@ -57,6 +57,7 @@ If you have questions concerning this license or the applicable additional terms
#include "EntKeyFindReplace.h" #include "EntKeyFindReplace.h"
#include "InspectorDialog.h" #include "InspectorDialog.h"
#include "autocaulk.h" #include "autocaulk.h"
#include "CityBuilder.h"
#include <commctrl.h> #include <commctrl.h>
#include "../../sys/win32/rc/common_resource.h" #include "../../sys/win32/rc/common_resource.h"
@@ -883,6 +884,7 @@ BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_COMMAND(ID_SELECT_COMPLETE_ENTITY, OnSelectCompleteEntity) ON_COMMAND(ID_SELECT_COMPLETE_ENTITY, OnSelectCompleteEntity)
ON_COMMAND(ID_PRECISION_CURSOR_CYCLE, OnPrecisionCursorCycle) ON_COMMAND(ID_PRECISION_CURSOR_CYCLE, OnPrecisionCursorCycle)
ON_COMMAND(ID_MATERIALS_GENERATEMATERIALSLIST, OnGenerateMaterialsList) ON_COMMAND(ID_MATERIALS_GENERATEMATERIALSLIST, OnGenerateMaterialsList)
ON_COMMAND(ID_TOOLS_AUTOMATICCITYBUILDER, OnToolsAutomaticCityBuilder)
ON_COMMAND(ID_SELECTION_VIEW_WIREFRAMEON, OnSelectionWireFrameOn) ON_COMMAND(ID_SELECTION_VIEW_WIREFRAMEON, OnSelectionWireFrameOn)
ON_COMMAND(ID_SELECTION_VIEW_WIREFRAMEOFF, OnSelectionWireFrameOff) ON_COMMAND(ID_SELECTION_VIEW_WIREFRAMEOFF, OnSelectionWireFrameOff)
ON_COMMAND(ID_SELECTION_VIEW_VISIBLEON, OnSelectionVisibleOn) ON_COMMAND(ID_SELECTION_VIEW_VISIBLEON, OnSelectionVisibleOn)
@@ -7980,6 +7982,10 @@ void CMainFrame::OnGenerateMaterialsList()
Sys_EndWait(); Sys_EndWait();
} }
void CMainFrame::OnToolsAutomaticCityBuilder() {
Radiant_GenerateAutomaticCity();
}
/* /*
======================================================================================================================= =======================================================================================================================
======================================================================================================================= =======================================================================================================================
+1
View File
@@ -657,6 +657,7 @@ public:
afx_msg void OnNurbEditor(); afx_msg void OnNurbEditor();
afx_msg void OnSelectCompleteEntity(); afx_msg void OnSelectCompleteEntity();
afx_msg void OnGenerateMaterialsList(); afx_msg void OnGenerateMaterialsList();
afx_msg void OnToolsAutomaticCityBuilder();
afx_msg void OnMru(unsigned int nID); afx_msg void OnMru(unsigned int nID);
afx_msg void OnViewNearest(unsigned int nID); afx_msg void OnViewNearest(unsigned int nID);
afx_msg void OnTextureWad(unsigned int nID); afx_msg void OnTextureWad(unsigned int nID);