diff --git a/docs/Complete_list_of_command_line_parameters.htm b/docs/Complete_list_of_command_line_parameters.htm index 775d2240..f88b166f 100644 --- a/docs/Complete_list_of_command_line_parameters.htm +++ b/docs/Complete_list_of_command_line_parameters.htm @@ -260,6 +260,7 @@ td.formatted_questions ol { margin-top: 0px; margin-bottom: 0px; }
  • -lomem: Low memory but slower lighting mode
  • -lowquality: Low quality floodlight (appears to currently break floodlight)
  • -minsamplesize N: Sets minimum lightmap resolution in luxels/qu
  • +
  • -multiSun N: Restrict sun and skylights to being emitted from surfaces carrying the shader they were defined in (as opposed to globally)
  • -nobouncestore: Do not store BSP, lightmap and shader files between bounces
  • -nocollapse: Do not collapse identical lightmaps
  • -nodeluxe, -nodeluxemap: Disable deluxemapping
  • diff --git a/docs/shaderManual/q3map-global-directives.html b/docs/shaderManual/q3map-global-directives.html index f9970fc3..d71ae56a 100644 --- a/docs/shaderManual/q3map-global-directives.html +++ b/docs/shaderManual/q3map-global-directives.html @@ -401,6 +401,11 @@ textures/eerie/ironcrosslt2_10000
    sample_color
    Default = 1: sample color of each individual light from skybox images, if they are present. 0: use shader color, set by q3map_lightRGB/q3map_lightImage/_up skybox image/qer_editorImage.
    +
    +

    Design Notes:

    +

    Normally, all suns and skylights are emitted from all sky surfaces in a map. If you wish to restrict them to being emitted from surfaces carrying the exact shader that defined them, e.g. to have different sun/sky lighting in different areas of the map, compile your map with the -multiSun keyword in the light stage.

    +
    +

    q3map_splotchFix

    This is used on lightmapped model shaders if splotched lighting artifacts appear. Any shadows at the ambient/dark level will be flooded from neighbouring luxels. This gets rid of shadow acne, but a surface must be more or less uniformly lit or this looks ugly. Try using q3map_lightmapSampleOffset first before using this as a last resort.

    @@ -428,6 +433,8 @@ textures/eerie/ironcrosslt2_10000

    Sky shaders should probably still have a q3map_surfaceLight or preferred q3map_skylight value. The "sun" gives a strong directional light, but doesn't necessarily give the fill light needed to soften and illuminate shadows. Skies with clouds should probably have a weaker q3map_sun value and a higher q3map_surfaceLight or q3map_skylight value. Heavy clouds diffuse light and weaken shadows. The opposite is true of a cloudless or nearly cloudless sky. In such cases, the "sun" or "moon" will cast stronger shadows that have a greater degree of contrast. This is also why q3map_sunExt is preferred. It gives the designer greater control over shadow contrast with a penumbra effect.

    Design Notes:

    Not certain what color formula you want to use for the sun's light? Try this. Create a light entity. Use the Radiant editor's color selection tools to pick a color. The light's _color key's value will be the normalized RGB formula. Copy it from the value line in the editor (CTRL+c) and paste it into your shader.

    +

    Design Notes:

    +

    Normally, all suns and skylights are emitted from all sky surfaces in a map. If you wish to restrict them to being emitted from surfaces carrying the exact shader that defined them, e.g. to have different sun/sky lighting in different areas of the map, compile your map with the -multiSun keyword in the light stage.

    q3map_surfaceLight value

    diff --git a/tools/quake3/q3map2/help.cpp b/tools/quake3/q3map2/help.cpp index dc045f2b..bee03e91 100644 --- a/tools/quake3/q3map2/help.cpp +++ b/tools/quake3/q3map2/help.cpp @@ -226,6 +226,7 @@ static void HelpLight() { "-lomem", "Low memory but slower lighting mode" }, { "-lowquality", "Low quality floodlight (appears to currently break floodlight)" }, { "-minsamplesize ", "Sets minimum lightmap resolution in luxels/qu" }, + { "-multisun", "Restrict sun and skylights to being emitted from surfaces carrying the shader they were defined in (as opposed to globally)" }, { "-nobouncestore", "Do not store BSP, lightmap and shader files between bounces" }, { "-nocollapse", "Do not collapse identical lightmaps" }, { "-nodeluxe, -nodeluxemap", "Disable deluxemapping" }, diff --git a/tools/quake3/q3map2/light.cpp b/tools/quake3/q3map2/light.cpp index b24b8780..82c87788 100644 --- a/tools/quake3/q3map2/light.cpp +++ b/tools/quake3/q3map2/light.cpp @@ -100,6 +100,7 @@ static void CreateSunLight( sun_t& sun ){ light.falloffTolerance = falloffTolerance; light.filterRadius = sun.filterRadius / sun.numSamples; light.style = noStyles ? LS_NORMAL : sun.style; + light.environmentLightIndex = sun.environmentLightIndex; /* set the light's position out to infinity */ light.origin = direction * ( MAX_WORLD_COORD * 8.0f ); /* MAX_WORLD_COORD * 2.0f */ @@ -234,6 +235,7 @@ static void CreateSkyLights( const skylight_t& skylight, const Vector3& color, f sun.deviance = 0.0f; sun.filterRadius = filterRadius; sun.numSamples = 1; + sun.environmentLightIndex = skylight.environmentLightIndex; sun.style = noStyles ? LS_NORMAL : style; /* setup */ @@ -599,6 +601,16 @@ static void CreateSurfaceLights(){ if ( !si->suns.empty() && !nss ) { auto* si_ = const_cast( si ); /* FIXME: hack! */ Sys_FPrintf( SYS_VRB, "Sun: %s\n", si->shader.c_str() ); + if(multiSun){ + if(si->environmentEmitterIndex == -1){ + // this shader is actually emitting sun/skylight now, so give it an environment emitter index + si_->environmentEmitterIndex = nextEnvironmentLightIndex++; + } + // let the suns know + for( auto sunIt = si_->suns.begin(); sunIt != si_->suns.end(); sunIt++ ){ + sunIt->environmentLightIndex = si_->environmentEmitterIndex; + } + } std::ranges::for_each( si_->suns, CreateSunLight ); si_->suns.clear(); /* FIXME: hack! */ } @@ -606,6 +618,17 @@ static void CreateSurfaceLights(){ /* sky light? */ if ( !si->skylights.empty() ) { Sys_FPrintf( SYS_VRB, "Sky: %s\n", si->shader.c_str() ); + if(multiSun){ + shaderInfo_t* si_ = const_cast( si ); /* FIXME: hack! */ + if(si->environmentEmitterIndex == -1){ + // this shader is actually emitting sun/skylight now, so give it an environment emitter index + si_->environmentEmitterIndex = nextEnvironmentLightIndex++; + } + // let the skies know + for( auto skyIt = si_->skylights.begin(); skyIt != si_->skylights.end(); skyIt++ ){ + skyIt->environmentLightIndex = si_->environmentEmitterIndex; + } + } for( const skylight_t& skylight : si->skylights ) CreateSkyLights( skylight, si->color, si->lightFilterRadius, si->lightStyle, si->skyParmsImageBase ); const_cast( si )->skylights.clear(); /* FIXME: hack! */ @@ -1098,7 +1121,7 @@ int LightContributionToSample( trace_t *trace ){ /* trace */ TraceLine( trace ); trace->forceSubsampling *= add; - if ( !( trace->compileFlags & C_SKY ) || trace->opaque ) { + if ( !( trace->compileFlags & C_SKY ) || trace->opaque || multiSun && light->environmentLightIndex != -1 && light->environmentLightIndex < MULTISUN_MAX && !bit_is_enabled(trace->skyEnvironmentLightIndices,light->environmentLightIndex) ) { trace->color.set( 0 ); trace->directionContribution.set( 0 ); @@ -1394,7 +1417,7 @@ static bool LightContributionToPoint( trace_t *trace ){ if ( trace->testOcclusion && !trace->forceSunlight ) { /* trace */ TraceLine( trace ); - if ( !( trace->compileFlags & C_SKY ) || trace->opaque ) { + if ( !( trace->compileFlags & C_SKY ) || trace->opaque || multiSun && light->environmentLightIndex != -1 && light->environmentLightIndex < MULTISUN_MAX && !bit_is_enabled(trace->skyEnvironmentLightIndices,light->environmentLightIndex) ) { trace->color.set( 0 ); return false; } @@ -2496,6 +2519,10 @@ int LightMain( Args& args ){ Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance ); } } + while ( args.takeArg( "-multisun" ) ) { + multiSun = true; + Sys_Printf( "Multi-sun support activated\n" ); + } while ( args.takeArg( "-deluxe", "-deluxemap" ) ) { deluxemap = true; Sys_Printf( "Generating deluxemaps for average light direction\n" ); diff --git a/tools/quake3/q3map2/light_trace.cpp b/tools/quake3/q3map2/light_trace.cpp index 1ffa80df..ccdd3970 100644 --- a/tools/quake3/q3map2/light_trace.cpp +++ b/tools/quake3/q3map2/light_trace.cpp @@ -1351,6 +1351,9 @@ static bool TraceTriangle( traceInfo_t *ti, traceTriangle_t *tt, trace_t *trace /* don't trace against sky */ if ( si->compileFlags & C_SKY ) { + if(multiSun && trace->light && trace->light->environmentLightIndex != -1 && si->environmentEmitterIndex != -1 && si->environmentEmitterIndex < MULTISUN_MAX){ + bit_enable(trace->skyEnvironmentLightIndices,si->environmentEmitterIndex); + } return false; } @@ -1597,6 +1600,9 @@ void TraceLine( trace_t *trace ){ trace->passSolid = false; trace->opaque = false; trace->compileFlags = 0; + if(multiSun){ + memset(trace->skyEnvironmentLightIndices,0,sizeof(trace->skyEnvironmentLightIndices)); + } trace->numTestNodes = 0; /* early outs */ diff --git a/tools/quake3/q3map2/q3map2.h b/tools/quake3/q3map2/q3map2.h index 9593492c..9c9a1d13 100644 --- a/tools/quake3/q3map2/q3map2.h +++ b/tools/quake3/q3map2/q3map2.h @@ -155,6 +155,9 @@ enum class EBrushType /* light */ +#define MULTISUN_MAX 2048 // TA: multi sun. this is how many separate suns can be drawn separately and only where they should +#define MULTISUN_MAX_BYTES (MULTISUN_MAX/8) // it's a bitmask. 256 bytes in the end. + #define MAX_TRACE_TEST_NODES 256 #define DEFAULT_INHIBIT_RADIUS 1.5f @@ -414,6 +417,7 @@ struct sun_t Vector3 direction, color; float photons, deviance, filterRadius; int numSamples, style; + int environmentLightIndex = -1; }; struct skylight_t @@ -423,6 +427,7 @@ struct skylight_t int horizon_min = 0; int horizon_max = 90; bool sample_color = true; + int environmentLightIndex = -1; }; @@ -579,6 +584,7 @@ struct shaderInfo_t_data std::vector skylights; /* ydnar */ std::vector suns; /* ydnar */ + int environmentEmitterIndex = -1; /* TA: multisun: shaders that end up being used and actually emit sunlight get a unique emitter index */ Vector3 color{ 0 }; /* normalized color */ Color4f averageColor = { 0, 0, 0, 0 }; @@ -1083,6 +1089,8 @@ struct light_t float falloffTolerance; /* ydnar: minimum attenuation threshold */ float filterRadius; /* ydnar: lightmap filter radius in world units, 0 == default */ + + int environmentLightIndex = -1; /* TA: For sun/skylights. Check if particular sky triangle emits a given light */ }; @@ -1106,9 +1114,12 @@ struct trace_t float inhibitRadius; /* sphere in which occluding geometry is ignored */ /* per-light input */ - const light_t *light; + const light_t *light = nullptr; Vector3 end; + /* TA: multisun support */ + byte skyEnvironmentLightIndices[MULTISUN_MAX_BYTES]; + /* calculated input */ Vector3 displacement, direction; float distance; @@ -2026,6 +2037,10 @@ inline const bool exactPointToPolygon = true; inline const float formFactorValueScale = 3.0f; inline const float linearScale = 1.0f / 8000.0f; +/* TA: multisun stuff (ability to have mutliple skyboxes with separate suns/skylights). May not handle _skybox properly */ +inline bool multiSun = false; +inline int nextEnvironmentLightIndex = 0; // each shader environment light (sun/sky) gets a unique index. thus we can check whether a sky surface should be considered as a successful trace + inline std::list lights; inline int numPointLights; inline int numSpotLights;