diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index 1df69013a..6f8f571b9 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -304,7 +304,7 @@ void UpdateSurfaceDataLightMapping( uint32_t* materials, Material& material, dra // bind u_LightTiles if ( r_realtimeLightingRenderer.Get() == Util::ordinal( realtimeLightingRenderer_t::TILED ) ) { - gl_lightMappingShaderMaterial->SetUniform_LightTilesIntBindless( + gl_lightMappingShaderMaterial->SetUniform_LightTilesBindless( GL_BindToTMU( BIND_LIGHTTILES, tr.lighttileRenderImage ) ); } diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 6f8da6a9f..acf247638 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -2098,8 +2098,6 @@ GLShader_lightMapping::GLShader_lightMapping( GLShaderManager *manager ) : u_LightGrid1( this ), u_LightGrid2( this ), u_LightTiles( this ), - u_LightTilesInt( this ), - u_LightsTexture( this ), u_TextureMatrix( this ), u_SpecularExponent( this ), u_ColorModulate( this ), @@ -2147,7 +2145,6 @@ void GLShader_lightMapping::SetShaderProgramUniforms( shaderProgram_t *shaderPro glUniform1i( glGetUniformLocation( shaderProgram->program, "u_EnvironmentMap0" ), BIND_ENVIRONMENTMAP0 ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_EnvironmentMap1" ), BIND_ENVIRONMENTMAP1 ); glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightTiles" ), BIND_LIGHTTILES ); - glUniform1i( glGetUniformLocation( shaderProgram->program, "u_LightTilesInt" ), BIND_LIGHTTILES ); if( !glConfig2.uniformBufferObjectAvailable ) { glUniform1i( glGetUniformLocation( shaderProgram->program, "u_Lights" ), BIND_LIGHTS ); } @@ -2167,7 +2164,7 @@ GLShader_lightMappingMaterial::GLShader_lightMappingMaterial( GLShaderManager* m u_EnvironmentMap1( this ), u_LightGrid1( this ), u_LightGrid2( this ), - u_LightTilesInt( this ), + u_LightTiles( this ), u_TextureMatrix( this ), u_SpecularExponent( this ), u_ColorModulate( this ), @@ -2829,7 +2826,7 @@ GLShader_liquidMaterial::GLShader_liquidMaterial( GLShaderManager* manager ) : u_NormalScale( this ), u_FogDensity( this ), u_FogColor( this ), - u_LightTilesInt( this ), + u_LightTiles( this ), u_SpecularExponent( this ), u_LightGridOrigin( this ), u_LightGridScale( this ), @@ -2906,7 +2903,6 @@ GLShader_lighttile::GLShader_lighttile( GLShaderManager *manager ) : GLShader( "lighttile", ATTR_POSITION | ATTR_TEXCOORD, manager ), u_DepthMap( this ), u_Lights( this ), - u_LightsTexture( this ), u_numLights( this ), u_lightLayer( this ), u_ModelMatrix( this ), diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index a379a3d4a..d0fcf5484 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -2413,22 +2413,6 @@ class u_CloudMap : } }; -class u_LightsTexture : - GLUniformSampler2D { - public: - u_LightsTexture( GLShader* shader ) : - GLUniformSampler2D( shader, "u_LightsTexture" ) { - } - - void SetUniform_LightsTextureBindless( GLuint64 bindlessHandle ) { - this->SetValueBindless( bindlessHandle ); - } - - GLint GetUniformLocation_LightsTexture() { - return this->GetLocation(); - } -}; - class u_LightTiles : GLUniformSampler3D { public: @@ -2445,22 +2429,6 @@ class u_LightTiles : } }; -class u_LightTilesInt : - GLUniformUSampler3D { - public: - u_LightTilesInt( GLShader* shader ) : - GLUniformUSampler3D( shader, "u_LightTilesInt" ) { - } - - void SetUniform_LightTilesIntBindless( GLuint64 bindlessHandle ) { - this->SetValueBindless( bindlessHandle ); - } - - GLint GetUniformLocation_LightTilesInt() { - return this->GetLocation(); - } -}; - class u_LightGrid1 : GLUniformSampler3D { public: @@ -3997,8 +3965,6 @@ class GLShader_lightMapping : public u_LightGrid1, public u_LightGrid2, public u_LightTiles, - public u_LightTilesInt, - public u_LightsTexture, public u_TextureMatrix, public u_SpecularExponent, public u_ColorModulate, @@ -4048,7 +4014,7 @@ class GLShader_lightMappingMaterial : public u_EnvironmentMap1, public u_LightGrid1, public u_LightGrid2, - public u_LightTilesInt, + public u_LightTiles, public u_TextureMatrix, public u_SpecularExponent, public u_ColorModulate, @@ -4602,7 +4568,7 @@ class GLShader_liquidMaterial : public u_NormalScale, public u_FogDensity, public u_FogColor, - public u_LightTilesInt, + public u_LightTiles, public u_SpecularExponent, public u_LightGridOrigin, public u_LightGridScale, @@ -4662,7 +4628,6 @@ class GLShader_lighttile : public GLShader, public u_DepthMap, public u_Lights, - public u_LightsTexture, public u_numLights, public u_lightLayer, public u_ModelMatrix, diff --git a/src/engine/renderer/glsl_source/computeLight_fp.glsl b/src/engine/renderer/glsl_source/computeLight_fp.glsl index dac19c786..36a1d9ed9 100644 --- a/src/engine/renderer/glsl_source/computeLight_fp.glsl +++ b/src/engine/renderer/glsl_source/computeLight_fp.glsl @@ -24,273 +24,253 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define COMPUTELIGHT_GLSL #if !defined(USE_BSP_SURFACE) - #define USE_MODEL_SURFACE + #define USE_MODEL_SURFACE #endif #if !defined(USE_GRID_LIGHTING) - #define USE_LIGHT_MAPPING + #define USE_LIGHT_MAPPING #endif #if defined(USE_REFLECTIVE_SPECULAR) -uniform samplerCube u_EnvironmentMap0; -uniform samplerCube u_EnvironmentMap1; -uniform float u_EnvironmentInterpolation; + uniform samplerCube u_EnvironmentMap0; + uniform samplerCube u_EnvironmentMap1; + uniform float u_EnvironmentInterpolation; #endif // USE_REFLECTIVE_SPECULAR -#if defined(r_realtimeLighting) && r_realtimeLightingRenderer == 1 -#if defined(HAVE_ARB_uniform_buffer_object) -struct light { - vec4 center_radius; - vec4 color_type; - vec4 direction_angle; -}; - -layout(std140) uniform u_Lights { - light lights[ MAX_REF_LIGHTS ]; -}; -#define GetLight(idx, component) lights[idx].component -#else // !HAVE_ARB_uniform_buffer_object -uniform sampler2D u_LightsTexture; -#define idxToTC( idx, w, h ) vec2( floor( ( idx * ( 1.0 / w ) ) + 0.5 ) * ( 1.0 / h ), \ - fract( ( idx + 0.5 ) * (1.0 / w ) ) ) -const struct GetLightOffsets { - int center_radius; - int color_type; - int direction_angle; -} getLightOffsets = GetLightOffsets(0, 1, 2); -#define GetLight(idx, component) texture2D( u_LightsTexture, idxToTC(3 * idx + getLightOffsets.component, 64.0, float( 3 * MAX_REF_LIGHTS / 64 ) ) ) -#endif // HAVE_ARB_uniform_buffer_object - -uniform int u_numLights; -#endif // defined(r_realtimeLighting) && r_realtimeLightingRenderer == 1 - // lighting helper functions #if defined(USE_GRID_LIGHTING) || defined(USE_GRID_DELUXE_MAPPING) -void ReadLightGrid(in vec4 texel, out vec3 ambientColor, out vec3 lightColor) { - float ambientScale = 2.0 * texel.a; - float directedScale = 2.0 - ambientScale; - ambientColor = ambientScale * texel.rgb; - lightColor = directedScale * texel.rgb; -} + void ReadLightGrid( in vec4 texel, out vec3 ambientColor, out vec3 lightColor ) { + float ambientScale = 2.0 * texel.a; + float directedScale = 2.0 - ambientScale; + ambientColor = ambientScale * texel.rgb; + lightColor = directedScale * texel.rgb; + } #endif #if defined(USE_DELUXE_MAPPING) || defined(USE_GRID_DELUXE_MAPPING) || (defined(r_realtimeLighting) && r_realtimeLightingRenderer == 1) -uniform vec2 u_SpecularExponent; + uniform vec2 u_SpecularExponent; #if defined(USE_REFLECTIVE_SPECULAR) void computeDeluxeLight( vec3 lightDir, vec3 normal, vec3 viewDir, vec3 lightColor, - vec4 diffuseColor, vec4 materialColor, - inout vec4 color, in samplerCube u_EnvironmentMap0, in samplerCube u_EnvironmentMap1 ) + vec4 diffuseColor, vec4 materialColor, + inout vec4 color, in samplerCube u_EnvironmentMap0, in samplerCube u_EnvironmentMap1 ) #else // !USE_REFLECTIVE_SPECULAR void computeDeluxeLight( vec3 lightDir, vec3 normal, vec3 viewDir, vec3 lightColor, - vec4 diffuseColor, vec4 materialColor, - inout vec4 color ) + vec4 diffuseColor, vec4 materialColor, + inout vec4 color ) #endif // !USE_REFLECTIVE_SPECULAR { - vec3 H = normalize( lightDir + viewDir ); - -#if defined(USE_PHYSICAL_MAPPING) || defined(r_specularMapping) - float NdotH = clamp( dot( normal, H ), 0.0, 1.0 ); -#endif // USE_PHYSICAL_MAPPING || r_specularMapping - - // clamp( NdotL, 0.0, 1.0 ) is done below - float NdotL = dot( normal, lightDir ); - -#if !defined(USE_BSP_SURFACE) && defined(r_halfLambertLighting) - // http://developer.valvesoftware.com/wiki/Half_Lambert - NdotL = NdotL * 0.5 + 0.5; - NdotL *= NdotL; -#endif - - NdotL = clamp( NdotL, 0.0, 1.0 ); - -#if defined(USE_PHYSICAL_MAPPING) - // Daemon PBR packing defaults to ORM like glTF 2.0 defines - // https://www.khronos.org/blog/art-pipeline-for-gltf - // > ORM texture for Occlusion, Roughness, and Metallic - // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/schema/material.pbrMetallicRoughness.schema.json - // > The metalness values are sampled from the B channel. The roughness values are sampled from the G channel. - // > These values are linear. If other channels are present (R or A), they are ignored for metallic-roughness calculations. - // https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html - // > glTF stores occlusion in the red (R) channel, allowing it to optionally share the same image - // > with the roughness and metallic channels. - float roughness = materialColor.g; - float metalness = materialColor.b; + vec3 H = normalize( lightDir + viewDir ); + + #if defined(USE_PHYSICAL_MAPPING) || defined(r_specularMapping) + float NdotH = clamp( dot( normal, H ), 0.0, 1.0 ); + #endif // USE_PHYSICAL_MAPPING || r_specularMapping + + // clamp( NdotL, 0.0, 1.0 ) is done below + float NdotL = dot( normal, lightDir ); + + #if !defined(USE_BSP_SURFACE) && defined(r_halfLambertLighting) + // http://developer.valvesoftware.com/wiki/Half_Lambert + NdotL = NdotL * 0.5 + 0.5; + NdotL *= NdotL; + #endif + + NdotL = clamp( NdotL, 0.0, 1.0 ); + + #if defined(USE_PHYSICAL_MAPPING) + // Daemon PBR packing defaults to ORM like glTF 2.0 defines + // https://www.khronos.org/blog/art-pipeline-for-gltf + // > ORM texture for Occlusion, Roughness, and Metallic + // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/schema/material.pbrMetallicRoughness.schema.json + // > The metalness values are sampled from the B channel. The roughness values are sampled from the G channel. + // > These values are linear. If other channels are present (R or A), they are ignored for metallic-roughness calculations. + // https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html + // > glTF stores occlusion in the red (R) channel, allowing it to optionally share the same image + // > with the roughness and metallic channels. + float roughness = materialColor.g; + float metalness = materialColor.b; + + float NdotV = clamp( dot( normal, viewDir ), 0.0, 1.0); + float VdotH = clamp( dot( viewDir, H ), 0.0, 1.0); + + float alpha = roughness * roughness; + float k = 0.125 * ( roughness + 1.0 ) * ( roughness + 1.0 ); + + float D = alpha / ( ( NdotH * NdotH ) * (alpha * alpha - 1.0 ) + 1.0 ); + D *= D; + + float FexpNH = pow( 1.0 - NdotH, 5.0 ); + float FexpNV = pow( 1.0 - NdotV, 5.0 ); + vec3 F = mix( vec3( 0.04 ), diffuseColor.rgb, metalness ); + F += ( 1.0 - F ) * FexpNH; + + float G = NdotL / (NdotL * ( 1.0 - k ) + k ); + G *= NdotV / ( NdotV * ( 1.0 - k ) + k ); + + vec3 diffuseBRDF = NdotL * diffuseColor.rgb * ( 1.0 - metalness ); + vec3 specularBRDF = vec3( ( D * F * G ) / max( 4.0 * NdotL * NdotV, 0.0001f ) ); + color.rgb += ( diffuseBRDF + specularBRDF ) * lightColor.rgb * NdotL; + color.a = mix( diffuseColor.a, 1.0, FexpNV ); + #else // !USE_PHYSICAL_MAPPING + + #if defined(USE_REFLECTIVE_SPECULAR) + // not implemented for PBR yet + vec4 envColor0 = textureCube(u_EnvironmentMap0, reflect( -viewDir, normal ) ); + vec4 envColor1 = textureCube(u_EnvironmentMap1, reflect( -viewDir, normal ) ); + + materialColor.rgb *= mix( envColor0, envColor1, u_EnvironmentInterpolation ).rgb; + #endif // USE_REFLECTIVE_SPECULAR + + color.rgb += lightColor.rgb * NdotL * diffuseColor.rgb; + #if defined(r_specularMapping) + // The minimal specular exponent should preferably be nonzero to avoid the undefined pow( 0, 0 ) + color.rgb += lightColor.rgb * materialColor.rgb + * pow( NdotH, u_SpecularExponent.x * materialColor.a + u_SpecularExponent.y ) * r_SpecularScale; + #endif // r_specularMapping + #endif // !USE_PHYSICAL_MAPPING +} +#endif // defined(USE_DELUXE_MAPPING) || defined(USE_GRID_DELUXE_MAPPING) || (defined(r_realtimeLighting) && r_realtimeLightingRenderer == 1) - float NdotV = clamp( dot( normal, viewDir ), 0.0, 1.0); - float VdotH = clamp( dot( viewDir, H ), 0.0, 1.0); +#if !defined(USE_DELUXE_MAPPING) && !defined(USE_GRID_DELUXE_MAPPING) + void computeLight( in vec3 lightColor, vec4 diffuseColor, inout vec4 color ) { + color.rgb += lightColor.rgb * diffuseColor.rgb; + } +#endif // !defined(USE_DELUXE_MAPPING) && !defined(USE_GRID_DELUXE_MAPPING) - float alpha = roughness * roughness; - float k = 0.125 * (roughness + 1.0) * (roughness + 1.0); +#if defined(r_realtimeLighting) && r_realtimeLightingRenderer == 1 - float D = alpha / ((NdotH * NdotH) * (alpha * alpha - 1.0) + 1.0); - D *= D; +struct Light { + vec3 center; + float radius; + vec3 color; + float type; + vec3 direction; + float angle; +}; - float FexpNH = pow(1.0 - NdotH, 5.0); - float FexpNV = pow(1.0 - NdotV, 5.0); - vec3 F = mix(vec3(0.04), diffuseColor.rgb, metalness); - F = F + (1.0 - F) * FexpNH; +layout(std140) uniform u_Lights { + Light lights[MAX_REF_LIGHTS]; +}; - float G = NdotL / (NdotL * (1.0 - k) + k); - G *= NdotV / (NdotV * (1.0 - k) + k); +#define GetLight( idx ) lights[idx] - vec3 diffuseBRDF = NdotL * diffuseColor.rgb * (1.0 - metalness); - vec3 specularBRDF = vec3((D * F * G) / max(4.0 * NdotL * NdotV, 0.0001f)); - color.rgb += (diffuseBRDF + specularBRDF) * lightColor.rgb * NdotL; - color.a = mix(diffuseColor.a, 1.0, FexpNV); -#else // !USE_PHYSICAL_MAPPING +uniform int u_numLights; #if defined(USE_REFLECTIVE_SPECULAR) - // not implemented for PBR yet - vec4 envColor0 = textureCube(u_EnvironmentMap0, reflect(-viewDir, normal)); - vec4 envColor1 = textureCube(u_EnvironmentMap1, reflect(-viewDir, normal)); - - materialColor.rgb *= mix(envColor0, envColor1, u_EnvironmentInterpolation).rgb; -#endif // USE_REFLECTIVE_SPECULAR +void computeDynamicLight( uint idx, vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, + vec4 material, inout vec4 color, in samplerCube u_EnvironmentMap0, in samplerCube u_EnvironmentMap1 ) +#else // !USE_REFLECTIVE_SPECULAR +void computeDynamicLight( uint idx, vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, + vec4 material, inout vec4 color ) +#endif // !USE_REFLECTIVE_SPECULAR +{ + Light light = GetLight( idx ); + vec3 L; + float attenuation; + + if( light.type == 0.0 ) { + // point light + L = light.center.xyz - P; + // 2.57 ~= 8.0 ^ ( 1.0 / 2.2 ), adjusted after overbright changes + float t = 1.0 + 2.57 * length( L ) / light.radius; + // Quadratic attenuation function instead of linear because of overbright changes + attenuation = 1.0 / ( t * t ); + L = normalize( L ); + } else if( light.type == 1.0 ) { + // spot light + L = light.center - P; + // 2.57 ~= 8.0 ^ ( 1.0 / 2.2 ), adjusted after overbright changes + float t = 1.0 + 2.57 * length( L ) / light.radius; + // Quadratic attenuation function instead of linear because of overbright changes + attenuation = 1.0 / ( t * t ); + L = normalize( L ); + + if( dot( L, light.direction ) <= light.angle ) { + attenuation = 0.0; + } + } else if( light.type == 2.0 ) { + // sun (directional) light + L = light.direction; + attenuation = 1.0; + } - color.rgb += lightColor.rgb * NdotL * diffuseColor.rgb; -#if defined(r_specularMapping) - // The minimal specular exponent should preferably be nonzero to avoid the undefined pow(0, 0) - color.rgb += lightColor.rgb * materialColor.rgb * pow( NdotH, u_SpecularExponent.x * materialColor.a + u_SpecularExponent.y) * r_SpecularScale; -#endif // r_specularMapping -#endif // !USE_PHYSICAL_MAPPING + #if defined(USE_REFLECTIVE_SPECULAR) + computeDeluxeLight( L, normal, viewDir, + attenuation * attenuation * light.color, + diffuse, material, color, u_EnvironmentMap0, u_EnvironmentMap1 ); + #else // !USE_REFLECTIVE_SPECULAR + computeDeluxeLight( L, normal, viewDir, + attenuation * attenuation * light.color, + diffuse, material, color ); + #endif // !USE_REFLECTIVE_SPECULAR } -#endif // defined(USE_DELUXE_MAPPING) || defined(USE_GRID_DELUXE_MAPPING) || (defined(r_realtimeLighting) && r_realtimeLightingRenderer == 1) -#if !defined(USE_DELUXE_MAPPING) && !defined(USE_GRID_DELUXE_MAPPING) -void computeLight(in vec3 lightColor, vec4 diffuseColor, inout vec4 color) { - color.rgb += lightColor.rgb * diffuseColor.rgb; -} -#endif // !defined(USE_DELUXE_MAPPING) && !defined(USE_GRID_DELUXE_MAPPING) - -#if defined(r_realtimeLighting) && r_realtimeLightingRenderer == 1 -#if defined(HAVE_EXT_texture_integer) && defined(r_highPrecisionRendering) const int lightsPerLayer = 16; -#define lightTilesSampler_t usampler3D -#define lightTilesUniform u_LightTilesInt + #define idxs_t uvec4 -idxs_t fetchIdxs( in vec3 coords, in lightTilesSampler_t lightTilesUniform ) { - return texture3D( lightTilesUniform, coords ); -} -int nextIdx( inout idxs_t idxs ) { - uvec4 tmp = ( idxs & uvec4( 3 ) ) * uvec4( 0x40, 0x10, 0x04, 0x01 ); - idxs = idxs >> 2; - return int( tmp.x + tmp.y + tmp.z + tmp.w ); -} -#else // !HAVE_EXT_texture_integer || !r_highPrecisionRendering -const int lightsPerLayer = 4; -#define lightTilesSampler_t sampler3D -#define lightTilesUniform u_LightTiles -#define idxs_t vec4 -idxs_t fetchIdxs( in vec3 coords, in lightTilesSampler_t lightTilesUniform ) { - return texture3D( lightTilesUniform, coords ) * 255.0; -} -int nextIdx( inout idxs_t idxs ) { - vec4 tmp = idxs; - idxs = floor(idxs * 0.25); - tmp -= 4.0 * idxs; - return int( dot( tmp, vec4( 64.0, 16.0, 4.0, 1.0 ) ) ); -} -#endif // !HAVE_EXT_texture_integer || !r_highPrecisionRendering -uniform lightTilesSampler_t lightTilesUniform; +uniform usampler3D u_LightTiles; -const int numLayers = MAX_REF_LIGHTS / 256; +const uint numLayers = MAX_REF_LIGHTS / 256; +const vec3 tileScale = vec3( r_tileStep, 1.0 / numLayers ); -#if defined(USE_REFLECTIVE_SPECULAR) -void computeDynamicLight( int idx, vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, - vec4 material, inout vec4 color, in samplerCube u_EnvironmentMap0, in samplerCube u_EnvironmentMap1 ) -#else // !USE_REFLECTIVE_SPECULAR -void computeDynamicLight( int idx, vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, - vec4 material, inout vec4 color ) -#endif // !USE_REFLECTIVE_SPECULAR -{ - vec4 center_radius = GetLight( idx, center_radius ); - vec4 color_type = GetLight( idx, color_type ); - vec3 L; - float attenuation; - - if( color_type.w == 0.0 ) { - // point light - L = center_radius.xyz - P; - // 2.57 ~= 8.0 ^ ( 1.0 / 2.2 ), adjusted after overbright changes - float t = 1.0 + 2.57 * length(L) / center_radius.w; - // Quadratic attenuation function instead of linear because of overbright changes - attenuation = 1.0 / ( t * t ); - L = normalize(L); - } else if( color_type.w == 1.0 ) { - // spot light - vec4 direction_angle = GetLight( idx, direction_angle ); - L = center_radius.xyz - P; - // 2.57 ~= 8.0 ^ ( 1.0 / 2.2 ), adjusted after overbright changes - float t = 1.0 + 2.57 * length(L) / center_radius.w; - // Quadratic attenuation function instead of linear because of overbright changes - attenuation = 1.0 / ( t * t ); - L = normalize( L ); - - if( dot( L, direction_angle.xyz ) <= direction_angle.w ) { - attenuation = 0.0; - } - } else if( color_type.w == 2.0 ) { - // sun (directional) light - L = GetLight( idx, direction_angle ).xyz; - attenuation = 1.0; - } - #if defined(USE_REFLECTIVE_SPECULAR) - computeDeluxeLight( L, normal, viewDir, - attenuation * attenuation * color_type.xyz, - diffuse, material, color, u_EnvironmentMap0, u_EnvironmentMap1 ); - #else // !USE_REFLECTIVE_SPECULAR - computeDeluxeLight( L, normal, viewDir, - attenuation * attenuation * color_type.xyz, - diffuse, material, color ); - #endif // !USE_REFLECTIVE_SPECULAR +idxs_t fetchIdxs( in vec3 coords, in usampler3D u_LightTiles ) { + return texture3D( u_LightTiles, coords ); +} + +// 8 bits per light ID +uint nextIdx( in uint count, in idxs_t idxs ) { + return ( idxs[count / 4] >> ( 8 * ( 4 - ( count % 4 ) ) ) ) & 0xF; } #if defined(USE_REFLECTIVE_SPECULAR) void computeDynamicLights( vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, vec4 material, - inout vec4 color, in lightTilesSampler_t lightTilesUniform, - in samplerCube u_EnvironmentMap0, in samplerCube u_EnvironmentMap1 ) + inout vec4 color, in usampler3D u_LightTiles, + in samplerCube u_EnvironmentMap0, in samplerCube u_EnvironmentMap1 ) #else // !USE_REFLECTIVE_SPECULAR void computeDynamicLights( vec3 P, vec3 normal, vec3 viewDir, vec4 diffuse, vec4 material, - inout vec4 color, in lightTilesSampler_t lightTilesUniform ) + inout vec4 color, in usampler3D u_LightTiles ) #endif // !USE_REFLECTIVE_SPECULAR { - vec2 tile = floor( gl_FragCoord.xy * (1.0 / float( TILE_SIZE ) ) ) + 0.5; - vec3 tileScale = vec3( r_tileStep, 1.0/numLayers ); - -#if defined(r_showLightTiles) - float numLights = 0.0; -#endif - - for( int layer = 0; layer < numLayers; layer++ ) { - idxs_t idxs = fetchIdxs( tileScale * vec3( tile, float( layer ) + 0.5 ), lightTilesUniform ); - for( int i = 0; i < lightsPerLayer; i++ ) { - int idx = numLayers * nextIdx( idxs ) + layer; - - if( idx >= u_numLights ) - { - break; - } + vec2 tile = floor( gl_FragCoord.xy * ( 1.0 / float( TILE_SIZE ) ) ) + 0.5; + + // NOT the amount of lights that can actually be put into each layer of the lighttile texture + uint globalLightsPerLayer = min( ( u_numLights + numLayers - 1 ) / numLayers, 16 ); + + uint lightCount = 0; + for( uint layer = 0; layer < numLayers; layer++ ) { + idxs_t idxs = fetchIdxs( tileScale * vec3( tile, float( layer ) + 0.5 ), u_LightTiles ); + + uint lightOffset = layer * globalLightsPerLayer; + uint layerLightCount = lightOffset < u_numLights ? min( min( u_numLights - lightOffset, globalLightsPerLayer ), lightsPerLayer ) : 0; + for( uint i = 0; i < layerLightCount; i++ ) { + uint idx = nextIdx( lightCount, idxs ); + + if( idx == 0 ) { + break; + } + + /* Light IDs are stored relative to the layer + Subtract 1 because 0 means there's no light */ + idx += ( layer * globalLightsPerLayer ) - 1; - #if defined(USE_REFLECTIVE_SPECULAR) - computeDynamicLight( idx, P, normal, viewDir, diffuse, material, color, u_EnvironmentMap0, u_EnvironmentMap1 ); - #else // !USE_REFLECTIVE_SPECULAR - computeDynamicLight( idx, P, normal, viewDir, diffuse, material, color ); - #endif // !USE_REFLECTIVE_SPECULAR - -#if defined(r_showLightTiles) - numLights++; -#endif + #if defined(USE_REFLECTIVE_SPECULAR) + computeDynamicLight( idx, P, normal, viewDir, diffuse, material, color, u_EnvironmentMap0, u_EnvironmentMap1 ); + #else // !USE_REFLECTIVE_SPECULAR + computeDynamicLight( idx, P, normal, viewDir, diffuse, material, color ); + #endif // !USE_REFLECTIVE_SPECULAR + + lightCount++; + } } - } -#if defined(r_showLightTiles) - if (numLights > 0.0) - { - color = vec4(numLights/(lightsPerLayer*numLayers), numLights/(lightsPerLayer*numLayers), numLights/(lightsPerLayer*numLayers), 1.0); - } -#endif + #if defined(r_showLightTiles) + if ( lightCount > 0.0 ) { + color = vec4( float( lightCount ) / u_numLights, float( lightCount ) / u_numLights, + float( lightCount ) / u_numLights, 1.0 ); + } + #endif } + #endif // defined(r_realtimeLighting) && r_realtimeLightingRenderer == 1 diff --git a/src/engine/renderer/glsl_source/lightMapping_fp.glsl b/src/engine/renderer/glsl_source/lightMapping_fp.glsl index eb7908a4b..ccf146100 100644 --- a/src/engine/renderer/glsl_source/lightMapping_fp.glsl +++ b/src/engine/renderer/glsl_source/lightMapping_fp.glsl @@ -188,10 +188,10 @@ void main() // Blend dynamic lights. #if defined(r_realtimeLighting) && r_realtimeLightingRenderer == 1 #if defined(USE_REFLECTIVE_SPECULAR) - computeDynamicLights(var_Position, normal, viewDir, diffuse, material, color, lightTilesUniform, + computeDynamicLights(var_Position, normal, viewDir, diffuse, material, color, u_LightTiles, u_EnvironmentMap0, u_EnvironmentMap1); #else // !USE_REFLECTIVE_SPECULAR - computeDynamicLights(var_Position, normal, viewDir, diffuse, material, color, lightTilesUniform); + computeDynamicLights(var_Position, normal, viewDir, diffuse, material, color, u_LightTiles); #endif // !USE_REFLECTIVE_SPECULAR #endif diff --git a/src/engine/renderer/glsl_source/lighttile_fp.glsl b/src/engine/renderer/glsl_source/lighttile_fp.glsl index 927ca5bb9..c3cb979d7 100644 --- a/src/engine/renderer/glsl_source/lighttile_fp.glsl +++ b/src/engine/renderer/glsl_source/lighttile_fp.glsl @@ -37,140 +37,121 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IN(smooth) vec2 vPosition; IN(smooth) vec2 vTexCoord; -struct light { - vec3 center; - float radius; - vec3 color; - float type; - vec3 direction; - float angle; +struct Light { + vec3 center; + float radius; + vec3 color; + float type; + vec3 direction; + float angle; }; -#if defined(HAVE_ARB_uniform_buffer_object) layout(std140) uniform u_Lights { - vec4 lightvec[ MAX_REF_LIGHTS * 3 ]; + Light lights[MAX_REF_LIGHTS]; }; -light GetLight(in int idx) { - light result; vec4 component; - idx *= 3; - component = lightvec[idx++]; - result.center = component.xyz; result.radius = component.w; - component = lightvec[idx++]; - result.color = component.xyz; result.type = component.w; - component = lightvec[idx++]; - result.direction = component.xyz; result.angle = component.w; - return result; -} -#else -uniform sampler2D u_Lights; -vec2 idxToTC( in int idx, float w, float h ) { - return vec2( ( float(idx) + 0.5 ) * ( 1.0 / (w * h) ), - ( float(idx) + 0.5 ) * ( 1.0 / w ) ); -} -light GetLight(in int idx) { - light result; vec4 component; - idx *= 3; - component = texture2D( u_Lights, idxToTC(idx++, 64.0, float( 3 * MAX_REF_LIGHTS / 64 ) ) ); - result.center = component.xyz; result.radius = component.w; - component = texture2D( u_Lights, idxToTC(idx++, 64.0, float( 3 * MAX_REF_LIGHTS / 64 ) ) ); - result.color = component.xyz; result.type = component.w; - component = texture2D( u_Lights, idxToTC(idx++, 64.0, float( 3 * MAX_REF_LIGHTS / 64 ) ) ); - result.direction = component.xyz; result.angle = component.w; - return result; + +Light GetLight( in uint idx ) { + return lights[idx]; } -#endif -uniform int u_numLights; +uniform int u_numLights; uniform mat4 u_ModelMatrix; uniform sampler2D u_DepthMap; -uniform int u_lightLayer; +uniform int u_lightLayer; uniform vec3 u_zFar; const int numLayers = MAX_REF_LIGHTS / 256; -#if defined(HAVE_EXT_texture_integer) && defined(r_highPrecisionRendering) +const int lightsPerLayer = 16; + #define idxs_t uvec4 -#define idx_initializer uvec4(3) + DECLARE_OUTPUT(uvec4) -void pushIdxs(in int idx, inout uvec4 idxs ) { - uvec4 bits = uvec4( idx >> 8, idx >> 6, idx >> 4, idx >> 2 ) & uvec4( 0x03 ); - idxs = idxs << 2 | bits; -} -#define exportIdxs(x) outputColor = ( x ) -#else -DECLARE_OUTPUT(vec4) -#define idxs_t vec4 -#define idx_initializer vec4(3.0) -void pushIdxs(in int idx, inout vec4 idxs ) { - vec4 bits = floor( vec4( idx ) * vec4( 1.0/256.0, 1.0/64.0, 1.0/16.0, 1.0/4.0 ) ); - bits.yzw -= 4.0 * bits.xyz; - idxs = idxs * 4.0 + bits; - idxs -= 256.0 * floor( idxs * (1.0/256.0) ); // discard upper bits + +// 8 bits per light ID +void pushIdxs( in uint idx, in uint count, inout uvec4 idxs ) { + idxs[count / 4] <<= 8 * ( count % 4 ); + idxs[count / 4] |= idx & 0xF; } -#define exportIdxs(x) outputColor = ( x ) * (1.0/255.0) -#endif + +#define exportIdxs( x ) outputColor = ( x ) void lightOutsidePlane( in vec4 plane, inout vec3 center, inout float radius ) { - float dist = dot( plane, vec4( center, 1.0 ) ); - if( dist >= radius ) { - radius = 0.0; // light completely outside plane - return; - } - - if( dist >= 0.0 ) { - // light is outside plane, but intersects the volume - center = center - dist * plane.xyz; - radius = sqrt( radius * radius - dist * dist ); - } + float dist = dot( plane, vec4( center, 1.0 ) ); + if( dist >= radius ) { + radius = 0.0; // light completely outside plane + return; + } + + if( dist >= 0.0 ) { + // light is outside plane, but intersects the volume + center -= dist * plane.xyz; + radius = sqrt( radius * radius - dist * dist ); + } } -vec3 ProjToView(vec2 inp) -{ - vec3 p = u_zFar * vec3(inp, -1); - - return p; +vec3 ProjToView( vec2 inp ) { + return u_zFar * vec3( inp, -1 ); } void main() { - vec2 minmax = texture2D( u_DepthMap, 0.5 * vPosition + 0.5 ).xy; - - float minx = vPosition.x - r_tileStep.x; - float maxx = vPosition.x + r_tileStep.x; - float miny = vPosition.y - r_tileStep.y; - float maxy = vPosition.y + r_tileStep.y; - - vec3 bottomleft = ProjToView(vec2(minx, miny)); - vec3 bottomright = ProjToView(vec2(maxx, miny)); - vec3 topright = ProjToView(vec2(maxx, maxy)); - vec3 topleft = ProjToView(vec2(minx, maxy)); - - vec4 plane1 = vec4(normalize(cross(bottomleft, bottomright)), 0); - vec4 plane2 = vec4(normalize(cross(bottomright, topright)), 0); - vec4 plane3 = vec4(normalize(cross(topright, topleft)), 0); - vec4 plane4 = vec4(normalize(cross(topleft, bottomleft)), 0); - - vec4 plane5 = vec4( 0.0, 0.0, 1.0, minmax.y ); - vec4 plane6 = vec4( 0.0, 0.0, -1.0, -minmax.x ); - - idxs_t idxs = idx_initializer; - - for( int i = u_lightLayer; i < u_numLights; i += numLayers ) { - light l = GetLight( i ); - vec3 center = ( u_ModelMatrix * vec4( l.center, 1.0 ) ).xyz; - float radius = max( 2.0 * l.radius, 2.0 * 32.0 ); // Avoid artifacts with weak light sources - - // todo: better checks for spotlights - lightOutsidePlane( plane1, center, radius ); - lightOutsidePlane( plane2, center, radius ); - lightOutsidePlane( plane3, center, radius ); - lightOutsidePlane( plane4, center, radius ); - lightOutsidePlane( plane5, center, radius ); - lightOutsidePlane( plane6, center, radius ); - - if( radius > 0.0 ) { - pushIdxs( i, idxs ); + vec2 minmax = texture2D( u_DepthMap, 0.5 * vPosition + 0.5 ).xy; + + float minx = vPosition.x - r_tileStep.x; + float maxx = vPosition.x + r_tileStep.x; + float miny = vPosition.y - r_tileStep.y; + float maxy = vPosition.y + r_tileStep.y; + + vec3 bottomleft = ProjToView( vec2( minx, miny ) ); + vec3 bottomright = ProjToView( vec2( maxx, miny ) ); + vec3 topright = ProjToView( vec2( maxx, maxy ) ); + vec3 topleft = ProjToView( vec2( minx, maxy ) ); + + vec4 plane1 = vec4( normalize( cross( bottomleft, bottomright ) ), 0 ); + vec4 plane2 = vec4( normalize( cross( bottomright, topright ) ), 0 ); + vec4 plane3 = vec4( normalize( cross( topright, topleft ) ), 0 ); + vec4 plane4 = vec4( normalize( cross( topleft, bottomleft ) ), 0 ); + + vec4 plane5 = vec4( 0.0, 0.0, 1.0, minmax.y ); + vec4 plane6 = vec4( 0.0, 0.0, -1.0, -minmax.x ); + + idxs_t idxs = uvec4( 0, 0, 0, 0 ); + + // NOT the amount of lights that can actually be put into each layer of the lighttile texture + uint globalLightsPerLayer = min( ( u_numLights + numLayers - 1 ) / numLayers, lightsPerLayer ); + uint lightOffset = u_lightLayer * globalLightsPerLayer; + uint layerLightCount = lightOffset < u_numLights ? min( u_numLights - lightOffset, globalLightsPerLayer ) : 0; + + uint lightCount = 0; + + /* Dynamic lights are put into 4 layers of a 3D texture. Since checking if we already added some light is infeasible, + only process 1 / 4 of different lights for each layer, extra lights going into the last layer. This can fail to add some lights + if 1 / 4 of all lights is more than the amount of lights that each layer can hold (16). To fix this, we'd need to either do this on CPU + or use compute shaders with atomics so we can have a variable amount of lights for each tile. */ + for( uint i = 0; i < layerLightCount; i++ ) { + Light l = GetLight( i + lightOffset ); + vec3 center = ( u_ModelMatrix * vec4( l.center, 1.0 ) ).xyz; + float radius = max( 2.0 * l.radius, 2.0 * 32.0 ); // Avoid artifacts with weak light sources + + // todo: better checks for spotlights + lightOutsidePlane( plane1, center, radius ); + lightOutsidePlane( plane2, center, radius ); + lightOutsidePlane( plane3, center, radius ); + lightOutsidePlane( plane4, center, radius ); + lightOutsidePlane( plane5, center, radius ); + lightOutsidePlane( plane6, center, radius ); + + if( radius > 0.0 ) { + /* Light IDs are stored relative to the layer + Add 1 because 0 means there's no light */ + pushIdxs( i + 1, lightCount, idxs ); + lightCount++; + + if( lightCount == lightsPerLayer ) { + break; + } + } } - } - exportIdxs( idxs ); + exportIdxs( idxs ); } diff --git a/src/engine/renderer/glsl_source/material_fp.glsl b/src/engine/renderer/glsl_source/material_fp.glsl index 6f4ac7107..de516e161 100644 --- a/src/engine/renderer/glsl_source/material_fp.glsl +++ b/src/engine/renderer/glsl_source/material_fp.glsl @@ -57,7 +57,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. samplerCube u_EnvironmentMap0 = samplerCube( u_EnvironmentMap0_initial ); samplerCube u_EnvironmentMap1 = samplerCube( u_EnvironmentMap1_initial ); #endif // !USE_REFLECTIVE_SPECULAR -usampler3D u_LightTilesInt = usampler3D( u_LightTilesInt_initial ); +usampler3D u_LightTiles = usampler3D( u_LightTiles_initial ); #endif // !COMPUTELIGHT_GLSL #if defined(FOGQUAKE3_GLSL) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index a5de777d1..abe3faecf 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -2922,13 +2922,7 @@ void RB_RenderPostDepthLightTile() gl_lighttileShader->SetUniform_numLights( backEnd.refdef.numLights ); gl_lighttileShader->SetUniform_zFar( projToViewParams ); - if( glConfig2.uniformBufferObjectAvailable ) { - gl_lighttileShader->SetUniformBlock_Lights( tr.dlightUBO ); - } else { - gl_lighttileShader->SetUniform_LightsTextureBindless( - GL_BindToTMU( 1, tr.dlightImage ) - ); - } + gl_lighttileShader->SetUniformBlock_Lights( tr.dlightUBO ); gl_lighttileShader->SetUniform_DepthMapBindless( GL_BindToTMU( 1, tr.depthtile2RenderImage ) @@ -5408,12 +5402,6 @@ const RenderCommand *SetupLightsCommand::ExecuteSelf( ) const } glUnmapBuffer( bufferTarget ); - if( !glConfig2.uniformBufferObjectAvailable ) { - gl_lighttileShader->SetUniform_LightsTextureBindless( - GL_BindToTMU( 1, tr.dlightImage ) - ); - glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, tr.dlightImage->width, tr.dlightImage->height, GL_RGBA, GL_FLOAT, nullptr ); - } glBindBuffer( bufferTarget, 0 ); } diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 28ecbc626..76ef61f90 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -2476,21 +2476,6 @@ static void R_CreateDepthRenderImage() return; } - if( !glConfig2.uniformBufferObjectAvailable ) - { - int w = 64; - int h = 3 * MAX_REF_LIGHTS / w; - - imageParams_t imageParams = {}; - imageParams.filterType = filterType_t::FT_NEAREST; - imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP; - - imageParams.bits = IF_NOPICMIP; - imageParams.bits |= r_highPrecisionRendering.Get() ? IF_RGBA32F : IF_RGBA16F; - - tr.dlightImage = R_CreateImage("_dlightImage", nullptr, w, h, 4, imageParams ); - } - if ( r_realtimeLightingRenderer.Get() != Util::ordinal( realtimeLightingRenderer_t::TILED ) ) { /* Do not create lightTile images when the tiled renderer is not used. @@ -2530,12 +2515,7 @@ static void R_CreateDepthRenderImage() tr.depthtile2RenderImage = R_CreateImage( "_depthtile2Render", nullptr, w, h, 1, imageParams ); - imageParams.bits = IF_NOPICMIP; - - if ( glConfig2.textureIntegerAvailable && r_highPrecisionRendering.Get() ) - { - imageParams.bits |= IF_RGBA32UI; - } + imageParams.bits = IF_NOPICMIP | IF_RGBA32UI; tr.lighttileRenderImage = R_Create3DImage( "_lighttileRender", nullptr, w, h, 4, imageParams ); } diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 39fd5b81c..de2182764 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2737,7 +2737,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; FBO_t *fbos[ MAX_FBOS ]; GLuint dlightUBO; - image_t *dlightImage; // if the UBO is not available std::vector vbos; std::vector ibos; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index ff43b8e2a..bbc0dbc86 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -42,9 +42,13 @@ static void EnableAvailableFeatures() { if ( r_realtimeLightingRenderer.Get() == Util::ordinal( realtimeLightingRenderer_t::TILED ) ) { - if ( !glConfig2.textureFloatAvailable ) - { - Log::Warn( "Tiled dynamic light renderer disabled because GL_ARB_texture_float is not available."); + if ( !glConfig2.uniformBufferObjectAvailable ) { + Log::Warn( "Tiled dynamic light renderer disabled because GL_ARB_uniform_buffer_object is not available." ); + glConfig2.realtimeLighting = false; + } + + if ( !glConfig2.textureIntegerAvailable ) { + Log::Warn( "Tiled dynamic light renderer disabled because GL_EXT_texture_integer is not available." ); glConfig2.realtimeLighting = false; } @@ -1069,21 +1073,13 @@ void Render_lightMapping( shaderStage_t *pStage ) { if ( backEnd.refdef.numShaderLights > 0 ) { - if( glConfig2.uniformBufferObjectAvailable ) - { - gl_lightMappingShader->SetUniformBlock_Lights( tr.dlightUBO ); - } else - { - gl_lightMappingShader->SetUniform_LightsTextureBindless( - GL_BindToTMU( BIND_LIGHTS, tr.dlightImage ) - ); - } + gl_lightMappingShader->SetUniformBlock_Lights( tr.dlightUBO ); } // bind u_LightTiles if ( r_realtimeLightingRenderer.Get() == Util::ordinal( realtimeLightingRenderer_t::TILED ) ) { - gl_lightMappingShader->SetUniform_LightTilesIntBindless( + gl_lightMappingShader->SetUniform_LightTilesBindless( GL_BindToTMU( BIND_LIGHTTILES, tr.lighttileRenderImage ) ); } diff --git a/src/engine/renderer/tr_vbo.cpp b/src/engine/renderer/tr_vbo.cpp index 74940b755..d798e0658 100644 --- a/src/engine/renderer/tr_vbo.cpp +++ b/src/engine/renderer/tr_vbo.cpp @@ -980,11 +980,6 @@ static void R_InitLightUBO() glBindBuffer( GL_UNIFORM_BUFFER, tr.dlightUBO ); glBufferData( GL_UNIFORM_BUFFER, MAX_REF_LIGHTS * sizeof( shaderLight_t ), nullptr, GL_DYNAMIC_DRAW ); glBindBuffer( GL_UNIFORM_BUFFER, 0 ); - } else { - glGenBuffers( 1, &tr.dlightUBO ); - glBindBuffer( GL_PIXEL_UNPACK_BUFFER, tr.dlightUBO ); - glBufferData( GL_PIXEL_UNPACK_BUFFER, MAX_REF_LIGHTS * sizeof( shaderLight_t ), nullptr, GL_DYNAMIC_DRAW ); - glBindBuffer( GL_PIXEL_UNPACK_BUFFER, 0 ); } } @@ -1112,7 +1107,7 @@ void R_ShutdownVBOs() Com_Free_Aligned( tess.vertsBuffer ); Com_Free_Aligned( tess.indexesBuffer ); - if( glConfig2.uniformBufferObjectAvailable ) { + if( glConfig2.realtimeLighting ) { glDeleteBuffers( 1, &tr.dlightUBO ); tr.dlightUBO = 0; }