From 72a737d992365d3ecb5a86c11be40d4c24feabe4 Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Sun, 9 May 2021 21:25:25 +0200 Subject: [PATCH] Updated release notes, added angles support for lights --- RELEASE-NOTES.md | 28 ++++++--- base/devtools.cfg | 2 +- .../lighting/ambient_lightgrid_IBL.ps.hlsl | 6 +- .../lighting/ambient_lighting_IBL.ps.hlsl | 6 +- neo/d3xp/Light.cpp | 24 +++++-- neo/renderer/RenderBackend.cpp | 63 +++++++++++++------ neo/renderer/RenderProgs_embedded.h | 12 ++-- neo/renderer/RenderWorld_lightgrid.cpp | 57 ++++++++++------- neo/renderer/RenderWorld_local.h | 2 +- 9 files changed, 132 insertions(+), 68 deletions(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index e7ddc36c..dc36b6a6 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -18,11 +18,12 @@ _______________________________________ 11 May 2021 - RBDOOM-3-BFG 1.3.0 - Download it from the [RBDOOM-3-BFG ModDB Page](https://www.moddb.com/mods/rbdoom-3-bfg) _______________________________ - + # RBDOOM-3-BFG 1.3.0 adds PBR, Baked GI and TrenchBroom Mapping Support The main goal of this 1.3.0 release is enabling modders the ability to make new content using up to date Material & Lighting standards. Adding PBR is a requirement to make the new content look the same in RBDOOM-3-BFG as in Blender 2.9x with Cycles or Eevee and Substance Designer. PBR became the standard material authoring since 2014. Many texture packs for Doom 3 like the Wulfen & Monoxead packs were made before and are heavily outdated. With this release modders can work with modern tools and expect that their content looks as expected. + However the PBR implementation is restricted to standard PBR using the Roughness/Metallic workflow for now. Specialized rendering paths for skin, clothes and vegetation will be in future releases. @@ -41,29 +42,42 @@ PBR allows artists to create textures that are based on real world measured colo *To achieve the typical PBR look from an artistic point of view it also means to that it is necessary to add indirect lighting. Doom 3 and even Doom 3 BFG had no indirect lighting.* +Doom 3 BFG is a big game. Doom 3, Resurrection of Evil and Lost Missions sum up to 47 big single player levels with an average of ~60 - 110 BSP portal areas or let's call them rooms / floors. Each room can have up to 50 shadow casting lights and most of them are point lights. +I needed a good automatic solution that fixes the pitch black areas without destroying the original look and feel of the game. +I also needed to add environment probes for each room so PBR materials can actually reflect the environment. + +So RBDOOM-3-BFG comes with 2 systems to achieve this and both are automatic approaches so everything can be achieved in a reasonable amount of time. +The first system are environment probes which are placed into the center of the rooms. They can also be manually tweaked by adding env_probe entities in the maps. They use L4 spherical harmonics for diffuse reflections and GGX convolved mip maps for specular reflections. +The second system refines this by using a light grid for each room which provides a sort of a localized/improved version of the surrounding light for each corner of the room. + ### Irradiance Volumes aka Light Grids RBDOOM-3-BFG 1.3.0 brings back the Quake 3 light grid but this time the grid points feature spherical harmonics encoded as octahedrons and it can be evaluated per pixel. This means it can be used on any geometry and serves as an irradiance volume. +Unlike Quake 3 this isn't radiosity which is limited to diffuse only reflections. The diffuse reflectivity is built using all kinds of incoming light: diffuse, specular and emissive (sky, light emitting GUIs, VFX). Lightgrids can be baked after loading the map and by typing: ``` -bakeLightGrids [limit] +bakeLightGrids [...] + + limit[num] : max probes per BSP area (default 16384) + bounce[num] : number of bounces or number of light reuse (default 1) + grid( xdim ydim zdim ) : light grid size steps into each direction (default 64 64 128) ``` This will generate a ***.lightgrid*** file next to your .map file and it will also store a light grid atlas for each BSP area under ***env/maps/*** -Limit is 4096 by default and means the maximum number of light grid points in a single light grid. +Limit is 16384 by default and means the maximum number of light grid points in a single light grid. Quake 3 had one light grid that streched over the entire map and distributed lighting every 64 x 64 x 128 units by default. If the maps were too big then q3map2 made the default grid size broader like 80 x 80 x 144, 96 x 96 x 160 and so on until the maximum number of light grid points was reached. The Quake 3 approach wouldn't work with Doom 3 because the maps are too big and it would result in up to 800k probes for some maps or the grid density would very coarse. -RBDOOM-3-BFG uses the bounding size of the BSP portal areas and puts and smaller light grid into those BSP areas. +RBDOOM-3-BFG uses the bounding size of the BSP portal areas and puts smaller light grids into those BSP areas. @@ -84,9 +98,9 @@ This is a way more advanced technique. ### Image Based Lighting and Environment Probes -Environment probes supplement the light grids. While light grids provide diffuse lighting information the signal isn't good enough to provide specular lighting. This is where environment probes are needed. There are less of them +Environment probes supplement the light grids. While light grids provide diffuse lighting information the signal isn't good enough to provide plausible specular light reflections. This is where environment probes are needed. -If an level designer doesn't put any env_probe entities into a map then they are automatically distributed through the map using the BSP area bounds and placed in the center of them. +If a level designer doesn't put any env_probe entities into a map then they are automatically distributed through the map using the BSP area bounds and placed in the center of them. Environment probes can be computed after loading the map and by typing: ``` @@ -104,7 +118,7 @@ For artists this basically means if you increase the roughness in your material If you haven't downloaded the additional baked light data from the [RBDOOM-3-BFG ModDB Page](https://www.moddb.com/mods/rbdoom-3-bfg) and just run RBDOOM-3-BFG.exe with the required DLLs (or you built it yourself) it will use an internal fallback. RBDOOM-3-BFG.exe has one prebaked environment probe that is compiled into the executable. - + It's the light data from the Mars City 1 lobby in the screenshot above. Using this data for the entire game is inacurrate but a better compromise than using a fixed global light direction and some sort of Rim lighting hack like in version 1.2.0. The default irradiance / radiance data gives the entire game a warmer look and it fits for being on Mars all the time. diff --git a/base/devtools.cfg b/base/devtools.cfg index 8376648f..9ce803c1 100644 --- a/base/devtools.cfg +++ b/base/devtools.cfg @@ -5,7 +5,7 @@ bind "M" "spawn moveable_macbethchart" bind "F1" "toggle r_showViewEnvprobes 1 2 3 0" bind "F2" "toggle r_showTris 1 2 3 0" -bind "F3" "toggle r_forceAmbient 0.5 0" +bind "F3" "toggle r_forceAmbient 0.5 1.0 0" bind "F4" "toggle r_skipInteractions" bind "F5" "savegame quick" bind "F6" "toggle r_showLightGrid 1 3 4 0" diff --git a/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl b/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl index 90aea054..431f6270 100644 --- a/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl +++ b/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl @@ -414,7 +414,7 @@ void main( PS_IN fragment, out PS_OUT result ) #endif float specAO = ComputeSpecularAO( vDotN, ao, roughness ); - float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * specAO * ( rpSpecularModifier.xyz * 0.5 ); + float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * specAO * ( rpSpecularModifier.xyz * 1.0 ); #if 1 // Marmoset Horizon Fade trick @@ -424,8 +424,8 @@ void main( PS_IN fragment, out PS_OUT result ) //horiz = clamp( horiz, 0.0, 1.0 ); #endif - half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb ); - //half3 lightColor = ( rpAmbientColor.rgb ); + //half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb ); + half3 lightColor = ( rpAmbientColor.rgb ); //result.color.rgb = diffuseLight; //result.color.rgb = diffuseLight * lightColor; diff --git a/base/renderprogs/builtin/lighting/ambient_lighting_IBL.ps.hlsl b/base/renderprogs/builtin/lighting/ambient_lighting_IBL.ps.hlsl index 5f035fcc..7d4ee584 100644 --- a/base/renderprogs/builtin/lighting/ambient_lighting_IBL.ps.hlsl +++ b/base/renderprogs/builtin/lighting/ambient_lighting_IBL.ps.hlsl @@ -288,7 +288,7 @@ void main( PS_IN fragment, out PS_OUT result ) #endif float specAO = ComputeSpecularAO( vDotN, ao, roughness ); - float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * specAO * ( rpSpecularModifier.xyz * 0.5 ); + float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * specAO * ( rpSpecularModifier.xyz * 1.0 ); #if 1 // Marmoset Horizon Fade trick @@ -298,8 +298,8 @@ void main( PS_IN fragment, out PS_OUT result ) //horiz = clamp( horiz, 0.0, 1.0 ); #endif - half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb ); - //half3 lightColor = ( rpAmbientColor.rgb ); + //half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb ); + half3 lightColor = ( rpAmbientColor.rgb ); //result.color.rgb = diffuseLight; //result.color.rgb = diffuseLight * lightColor; diff --git a/neo/d3xp/Light.cpp b/neo/d3xp/Light.cpp index 5c77580c..b7b5c1a5 100644 --- a/neo/d3xp/Light.cpp +++ b/neo/d3xp/Light.cpp @@ -131,11 +131,25 @@ void idGameEdit::ParseSpawnArgsToRenderLight( const idDict* args, renderLight_t* { if( !args->GetMatrix( "rotation", "1 0 0 0 1 0 0 0 1", mat ) ) { - args->GetFloat( "angle", "0", angles[ 1 ] ); - angles[ 0 ] = 0; - angles[ 1 ] = idMath::AngleNormalize360( angles[ 1 ] ); - angles[ 2 ] = 0; - mat = angles.ToMat3(); + // RB: TrenchBroom interop + // support "angles" like in Quake 3 + + if( args->GetAngles( "angles", "0 0 0", angles ) ) + { + angles[ 0 ] = idMath::AngleNormalize360( angles[ 0 ] ); + angles[ 1 ] = idMath::AngleNormalize360( angles[ 1 ] ); + angles[ 2 ] = idMath::AngleNormalize360( angles[ 2 ] ); + + mat = angles.ToMat3(); + } + else + { + args->GetFloat( "angle", "0", angles[ 1 ] ); + angles[ 0 ] = 0; + angles[ 1 ] = idMath::AngleNormalize360( angles[ 1 ] ); + angles[ 2 ] = 0; + mat = angles.ToMat3(); + } } } diff --git a/neo/renderer/RenderBackend.cpp b/neo/renderer/RenderBackend.cpp index 03859a97..d2f9db67 100644 --- a/neo/renderer/RenderBackend.cpp +++ b/neo/renderer/RenderBackend.cpp @@ -1844,7 +1844,6 @@ void idRenderBackend::RenderInteractions( const drawSurf_t* surfList, const view } // RB end - //const float lightScale = r_useHDR.GetBool() ? r_lightScale.GetFloat() * 0.666f : r_lightScale.GetFloat(); const float lightScale = r_lightScale.GetFloat(); for( int lightStageNum = 0; lightStageNum < lightShader->GetNumStages(); lightStageNum++ ) @@ -2300,32 +2299,56 @@ void idRenderBackend::AmbientPass( const drawSurf_t* const* drawSurfs, int numDr GL_Color( colorWhite ); - //const float lightScale = r_useHDR.GetBool() ? r_lightScale.GetFloat() * 0.666f : r_lightScale.GetFloat(); - const float lightScale = r_lightScale.GetFloat(); - const idVec4 lightColor = colorWhite * lightScale; - - // apply the world-global overbright and the 2x factor for specular - const idVec4 diffuseColor = lightColor; - const idVec4 specularColor = lightColor * 2.0f; - + idVec4 diffuseColor; + idVec4 specularColor; idVec4 ambientColor; - float ambientBoost = 1.0f; - if( !r_usePBR.GetBool() ) + if( viewDef->renderView.rdflags & RDF_IRRADIANCE ) { - ambientBoost += r_useSSAO.GetBool() ? 0.2f : 0.0f; - ambientBoost *= r_useHDR.GetBool() ? 1.1f : 1.0f; + // RB: don't let artist run into a trap when baking multibounce lightgrids + + // use default value of r_lightScale 3 + const float lightScale = 3; + const idVec4 lightColor = colorWhite * lightScale; + + // apply the world-global overbright and the 2x factor for specular + diffuseColor = lightColor; + specularColor = lightColor;// * 2.0f; + + // loose 5% with every bounce like in DDGI + const float energyConservation = 0.95f; + + //ambientColor.Set( energyConservation, energyConservation, energyConservation, 1.0f ); + float a = r_forceAmbient.GetFloat(); + + ambientColor.Set( a, a, a, 1 ); + } + else + { + const float lightScale = r_lightScale.GetFloat(); + const idVec4 lightColor = colorWhite * lightScale; + + // apply the world-global overbright and tune down specular a bit so we have less fresnel overglow + diffuseColor = lightColor; + specularColor = lightColor;// * 0.5f; + + float ambientBoost = 1.0f; + if( !r_usePBR.GetBool() ) + { + ambientBoost += r_useSSAO.GetBool() ? 0.2f : 0.0f; + ambientBoost *= r_useHDR.GetBool() ? 1.1f : 1.0f; + } + + ambientColor.x = r_forceAmbient.GetFloat() * ambientBoost; + ambientColor.y = r_forceAmbient.GetFloat() * ambientBoost; + ambientColor.z = r_forceAmbient.GetFloat() * ambientBoost; + ambientColor.w = 1; } - bool useIBL = r_usePBR.GetBool() && !fillGbuffer; - - ambientColor.x = r_forceAmbient.GetFloat() * ambientBoost; - ambientColor.y = r_forceAmbient.GetFloat() * ambientBoost; - ambientColor.z = r_forceAmbient.GetFloat() * ambientBoost; - ambientColor.w = 1; - renderProgManager.SetRenderParm( RENDERPARM_AMBIENT_COLOR, ambientColor.ToFloatPtr() ); + bool useIBL = r_usePBR.GetBool() && !fillGbuffer; + // setup renderparms assuming we will be drawing trivial surfaces first RB_SetupForFastPathInteractions( diffuseColor, specularColor ); diff --git a/neo/renderer/RenderProgs_embedded.h b/neo/renderer/RenderProgs_embedded.h index 45d7d08d..644f9817 100644 --- a/neo/renderer/RenderProgs_embedded.h +++ b/neo/renderer/RenderProgs_embedded.h @@ -5055,7 +5055,7 @@ static const cgShaderDef_t cg_renderprogs[] = "#endif\n" "\n" " float specAO = ComputeSpecularAO( vDotN, ao, roughness );\n" - " float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * specAO * ( rpSpecularModifier.xyz * 0.5 );\n" + " float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * specAO * ( rpSpecularModifier.xyz * 1.0 );\n" "\n" "#if 1\n" " // Marmoset Horizon Fade trick\n" @@ -5065,8 +5065,8 @@ static const cgShaderDef_t cg_renderprogs[] = " //horiz = clamp( horiz, 0.0, 1.0 );\n" "#endif\n" "\n" - " half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb );\n" - " //half3 lightColor = ( rpAmbientColor.rgb );\n" + " //half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb );\n" + " half3 lightColor = ( rpAmbientColor.rgb );\n" "\n" " //result.color.rgb = diffuseLight;\n" " //result.color.rgb = diffuseLight * lightColor;\n" @@ -5703,7 +5703,7 @@ static const cgShaderDef_t cg_renderprogs[] = "#endif\n" "\n" " float specAO = ComputeSpecularAO( vDotN, ao, roughness );\n" - " float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * specAO * ( rpSpecularModifier.xyz * 0.5 );\n" + " float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * specAO * ( rpSpecularModifier.xyz * 1.0 );\n" "\n" "#if 1\n" " // Marmoset Horizon Fade trick\n" @@ -5713,8 +5713,8 @@ static const cgShaderDef_t cg_renderprogs[] = " //horiz = clamp( horiz, 0.0, 1.0 );\n" "#endif\n" "\n" - " half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb );\n" - " //half3 lightColor = ( rpAmbientColor.rgb );\n" + " //half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb );\n" + " half3 lightColor = ( rpAmbientColor.rgb );\n" "\n" " //result.color.rgb = diffuseLight;\n" " //result.color.rgb = diffuseLight * lightColor;\n" diff --git a/neo/renderer/RenderWorld_lightgrid.cpp b/neo/renderer/RenderWorld_lightgrid.cpp index 239cf94a..ecb15ab9 100644 --- a/neo/renderer/RenderWorld_lightgrid.cpp +++ b/neo/renderer/RenderWorld_lightgrid.cpp @@ -60,7 +60,7 @@ LightGrid::LightGrid() imageBorderSize = LIGHTGRID_IRRADIANCE_BORDER_SIZE; } -void LightGrid::SetupLightGrid( const idBounds& bounds, const char* mapName, const idRenderWorld* world, const idVec3& gridSize, int _area, int numAreas, int maxProbes ) +void LightGrid::SetupLightGrid( const idBounds& bounds, const char* mapName, const idRenderWorld* world, const idVec3& gridSize, int _area, int numAreas, int maxProbes, bool printToConsole ) { //idLib::Printf( "----- SetupLightGrid -----\n" ); @@ -103,10 +103,13 @@ void LightGrid::SetupLightGrid( const idBounds& bounds, const char* mapName, con { lightGridPoints.SetNum( numGridPoints ); - idLib::Printf( "\narea %i of %i (%i x %i x %i) = %i grid points \n", area, numAreas, lightGridBounds[0], lightGridBounds[1], lightGridBounds[2], numGridPoints ); - idLib::Printf( "area %i grid size (%i %i %i)\n", area, ( int )lightGridSize[0], ( int )lightGridSize[1], ( int )lightGridSize[2] ); - idLib::Printf( "area %i grid bounds (%i %i %i)\n", area, ( int )lightGridBounds[0], ( int )lightGridBounds[1], ( int )lightGridBounds[2] ); - //idLib::Printf( "area %i %9u x %" PRIuSIZE " = lightGridSize = (%.2fMB)\n", area, numGridPoints, sizeof( lightGridPoint_t ), ( float )( lightGridPoints.MemoryUsed() ) / ( 1024.0f * 1024.0f ) ); + if( printToConsole ) + { + idLib::Printf( "\narea %i of %i (%i x %i x %i) = %i grid points \n", area, numAreas, lightGridBounds[0], lightGridBounds[1], lightGridBounds[2], numGridPoints ); + idLib::Printf( "area %i grid size (%i %i %i)\n", area, ( int )lightGridSize[0], ( int )lightGridSize[1], ( int )lightGridSize[2] ); + idLib::Printf( "area %i grid bounds (%i %i %i)\n", area, ( int )lightGridBounds[0], ( int )lightGridBounds[1], ( int )lightGridBounds[2] ); + //idLib::Printf( "area %i %9u x %" PRIuSIZE " = lightGridSize = (%.2fMB)\n", area, numGridPoints, sizeof( lightGridPoint_t ), ( float )( lightGridPoints.MemoryUsed() ) / ( 1024.0f * 1024.0f ) ); + } CalculateLightGridPointPositions( world, area ); } @@ -390,7 +393,7 @@ void idRenderWorldLocal::SetupLightGrid() { portalArea_t* area = &portalAreas[i]; - area->lightGrid.SetupLightGrid( area->globalBounds, mapName, this, defaultLightGridSize, i, numPortalAreas, -1 ); + area->lightGrid.SetupLightGrid( area->globalBounds, mapName, this, defaultLightGridSize, i, numPortalAreas, -1, true ); totalGridPoints += area->lightGrid.CountValidGridPoints(); } @@ -1123,22 +1126,40 @@ CONSOLE_COMMAND( bakeLightGrids, "Bake irradiance/vis light grid data", NULL ) int totalProcessedProbes = 0; int totalStart = Sys_Milliseconds(); + // estimate time for bake so the user can quit and adjust parameters if needed for( int bounce = 0; bounce < bounces; bounce++ ) { for( int a = 0; a < tr.primaryWorld->NumAreas(); a++ ) { portalArea_t* area = &tr.primaryWorld->portalAreas[a]; - //int numGridPoints = Min( area->lightGrid.lightGridPoints.Num(), limit ); - //if( numGridPoints == 0 ) + area->lightGrid.SetupLightGrid( area->globalBounds, tr.primaryWorld->mapName, tr.primaryWorld, gridSize, a, tr.primaryWorld->NumAreas(), limit, false ); - //int numGridPoints = area->lightGrid.lightGridPoints.Num(); - //if( numGridPoints == 0 || numGridPoints > limit ) - //{ - // continue; - //} + int numGridPoints = area->lightGrid.CountValidGridPoints(); + if( numGridPoints == 0 ) + { + continue; + } - area->lightGrid.SetupLightGrid( area->globalBounds, tr.primaryWorld->mapName, tr.primaryWorld, gridSize, a, tr.primaryWorld->NumAreas(), limit ); + if( bounce == 0 ) + { + totalProcessedAreas++; + totalProcessedProbes += numGridPoints; + } + } + } + + idLib::Printf( "----------------------------------\n" ); + idLib::Printf( "Processing %i light probes in %i areas for %i bounces\n", totalProcessedProbes, totalProcessedAreas, bounces ); + //common->Printf( "ETA %5.1f minutes\n\n", ( totalEnd - totalStart ) / ( 1000.0f * 60 ) ); + + for( int bounce = 0; bounce < bounces; bounce++ ) + { + for( int a = 0; a < tr.primaryWorld->NumAreas(); a++ ) + { + portalArea_t* area = &tr.primaryWorld->portalAreas[a]; + + area->lightGrid.SetupLightGrid( area->globalBounds, tr.primaryWorld->mapName, tr.primaryWorld, gridSize, a, tr.primaryWorld->NumAreas(), limit, true ); int numGridPoints = area->lightGrid.CountValidGridPoints(); if( numGridPoints == 0 ) @@ -1148,12 +1169,6 @@ CONSOLE_COMMAND( bakeLightGrids, "Bake irradiance/vis light grid data", NULL ) idLib::Printf( "Shooting %i grid probes in area %i...\n", numGridPoints, a ); - if( bounce == 0 ) - { - totalProcessedAreas++; - totalProcessedProbes += numGridPoints; - } - CommandlineProgressBar progressBar( numGridPoints, sysWidth, sysHeight ); progressBar.Start(); @@ -1350,8 +1365,6 @@ CONSOLE_COMMAND( bakeLightGrids, "Bake irradiance/vis light grid data", NULL ) tr.envprobeJobList->Wait(); } - - int atlasWidth = area->lightGrid.lightGridBounds[0] * area->lightGrid.lightGridBounds[2] * LIGHTGRID_IRRADIANCE_SIZE; int atlasHeight = area->lightGrid.lightGridBounds[1] * LIGHTGRID_IRRADIANCE_SIZE; diff --git a/neo/renderer/RenderWorld_local.h b/neo/renderer/RenderWorld_local.h index 50f1ce1d..9277066e 100644 --- a/neo/renderer/RenderWorld_local.h +++ b/neo/renderer/RenderWorld_local.h @@ -86,7 +86,7 @@ public: LightGrid(); // setup light grid for given world bounds - void SetupLightGrid( const idBounds& bounds, const char* baseName, const idRenderWorld* world, const idVec3& gridSize, int _area, int totalAreas, int maxProbes ); + void SetupLightGrid( const idBounds& bounds, const char* baseName, const idRenderWorld* world, const idVec3& gridSize, int _area, int totalAreas, int maxProbes, bool printToConsole ); void GetBaseGridCoord( const idVec3& origin, int gridCoord[3] );