diff --git a/src/gl/dynlights/gl_dynlight1.cpp b/src/gl/dynlights/gl_dynlight1.cpp index 361b94618..56db94e4d 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -80,6 +80,11 @@ CUSTOM_CVAR (Bool, gl_lights_additive, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG gl_RecreateAllAttachedLights(); } +CUSTOM_CVAR(Int, gl_light_math, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 0 || self > 2) self = 0; +} + //========================================================================== // // Sets up the parameters to render one dynamic light onto one plane @@ -128,10 +133,28 @@ bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, bo i = 1; } + float worldPos[4] = { (float)pos.X, (float)pos.Z, (float)pos.Y, 1.0f }; + float eyePos[4]; + gl_RenderState.mViewMatrix.multMatrixPoint(worldPos, eyePos); + + if (gl_light_math != 0) + { + // Adjust light slightly to make the range better match plain attenuation + radius *= 1.5; + + // Move light up because flasks/vials have their light source location at/below the floor. + // + // If the point is exactly on the wall plane it might cause some acne as some pixels could + // be in front and some behind. Move light just a tiny bit to avoid this. + eyePos[0] += 0.01f; + eyePos[1] += 5.01f; + eyePos[2] += 0.01f; + } + float *data = &ldata.arrays[i][ldata.arrays[i].Reserve(8)]; - data[0] = pos.X; - data[1] = pos.Z; - data[2] = pos.Y; + data[0] = eyePos[0]; + data[1] = eyePos[1]; + data[2] = eyePos[2]; data[3] = radius; data[4] = r; data[5] = g; diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 83303d61e..61b3e13d7 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -144,6 +144,7 @@ bool FRenderState::ApplyShader() activeShader->muTimer.Set(gl_frameMS * mShaderTimer / 1000.f); activeShader->muAlphaThreshold.Set(mAlphaThreshold); activeShader->muLightIndex.Set(mLightIndex); // will always be -1 for now + activeShader->muLightMath.Set(gl_light_math); activeShader->muClipSplit.Set(mClipSplit); if (mGlowEnabled) diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index 67b9a2d6a..4acfd4bbe 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -246,6 +246,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * muColormapStart.Init(hShader, "uFixedColormapStart"); muColormapRange.Init(hShader, "uFixedColormapRange"); muLightIndex.Init(hShader, "uLightIndex"); + muLightMath.Init(hShader, "uLightMath"); muFogColor.Init(hShader, "uFogColor"); muDynLightColor.Init(hShader, "uDynLightColor"); muObjectColor.Init(hShader, "uObjectColor"); diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index 75e4b4e5e..09b43310d 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -221,6 +221,7 @@ class FShader FUniform1i muFixedColormap; FUniform4f muColormapStart; FUniform4f muColormapRange; + FBufferedUniform1i muLightMath; FBufferedUniform1i muLightIndex; FBufferedUniformPE muFogColor; FBufferedUniform4f muDynLightColor; diff --git a/src/gl/system/gl_cvars.h b/src/gl/system/gl_cvars.h index 0c31f53a8..290f3ea8c 100644 --- a/src/gl/system/gl_cvars.h +++ b/src/gl/system/gl_cvars.h @@ -29,6 +29,7 @@ EXTERN_CVAR (Float, gl_lights_size); EXTERN_CVAR (Bool, gl_lights_additive); EXTERN_CVAR (Bool, gl_light_sprites); EXTERN_CVAR (Bool, gl_light_particles); +EXTERN_CVAR (Int, gl_light_math); EXTERN_CVAR(Int, gl_fogmode) EXTERN_CVAR(Int, gl_lightmode) diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 1e20ebeb2..79f71edf8 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2603,6 +2603,7 @@ GLLIGHTMNU_LIGHTPARTICLES = "Lights affect particles"; GLLIGHTMNU_FORCEADDITIVE = "Force additive lighting"; GLLIGHTMNU_LIGHTINTENSITY = "Light intensity"; GLLIGHTMNU_LIGHTSIZE = "Light size"; +GLLIGHTMNU_LIGHTMATH = "Light quality"; // OpenGL Preferences GLPREFMNU_TITLE = "OPENGL PREFERENCES"; @@ -2700,4 +2701,7 @@ OPTVAL_QUADBUFFERED = "Quad-buffered"; OPTVAL_UNCHARTED2 = "Uncharted 2"; OPTVAL_HEJLDAWSON = "Hejl Dawson"; OPTVAL_REINHARD = "Reinhard"; -OPTVAL_PALETTE = "Palette"; \ No newline at end of file +OPTVAL_PALETTE = "Palette"; +OPTVAL_LOW = "Low"; +OPTVAL_MEDIUM = "Medium"; +OPTVAL_HIGH = "High"; diff --git a/wadsrc/static/menudef.z b/wadsrc/static/menudef.z index 2386b1076..0d080d709 100644 --- a/wadsrc/static/menudef.z +++ b/wadsrc/static/menudef.z @@ -25,6 +25,13 @@ OptionValue "FilterModes" 4, "$OPTVAL_TRILINEAR" } +OptionValue "LightMathModes" +{ + 0, "$OPTVAL_LOW" + 1, "$OPTVAL_MEDIUM" + 2, "$OPTVAL_HIGH" +} + OptionValue "HWGammaModes" { 0, "$OPTVAL_ON" @@ -193,6 +200,7 @@ OptionMenu "GLLightOptions" Option "$GLLIGHTMNU_LIGHTSPRITES", gl_light_sprites, "YesNo" Option "$GLLIGHTMNU_LIGHTPARTICLES", gl_light_particles, "YesNo" Option "$GLLIGHTMNU_FORCEADDITIVE", gl_lights_additive, "YesNo" + Option "$GLLIGHTMNU_LIGHTMATH", gl_light_math, "LightMathModes" Slider "$GLLIGHTMNU_LIGHTINTENSITY", gl_lights_intensity, 0.0, 1.0, 0.1 Slider "$GLLIGHTMNU_LIGHTSIZE", gl_lights_size, 0.0, 2.0, 0.1 } diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index b10c99a17..2a783e00c 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -25,6 +25,88 @@ vec4 Process(vec4 color); vec4 ProcessTexel(); vec4 ProcessLight(vec4 color); +// Smoothed normal used for the face, in eye space. Should be converted to an 'in' variable in the future. +vec3 pixelnormal; + +//=========================================================================== +// +// Calculates the face normal vector for the fragment, in eye space +// +//=========================================================================== + +vec3 calculateFaceNormal() +{ +#if __VERSION__ < 450 + vec3 dFdxPos = dFdx(pixelpos.xyz); + vec3 dFdyPos = dFdy(pixelpos.xyz); +#else + vec3 dFdxPos = dFdxCoarse(pixelpos.xyz); + vec3 dFdyPos = dFdyCoarse(pixelpos.xyz); +#endif + return normalize(cross(dFdxPos,dFdyPos)); +} + +//=========================================================================== +// +// Standard lambertian diffuse light calculation +// +//=========================================================================== + +float diffuseContribution(vec3 eyeLightDirection, vec3 eyeNormal) +{ + return max(dot(eyeNormal, eyeLightDirection), 0.0f); +} + +//=========================================================================== +// +// Blinn specular light calculation +// +//=========================================================================== + +float blinnSpecularContribution(float diffuseContribution, vec3 eyeLightDirection, vec3 eyePosition, vec3 eyeNormal, float glossiness, float specularLevel) +{ + if (diffuseContribution > 0.0f) + { + vec3 viewDir = normalize(-eyePosition); + vec3 halfDir = normalize(eyeLightDirection + viewDir); + float specAngle = max(dot(halfDir, eyeNormal), 0.0f); + float phExp = glossiness * 4.0f; + return specularLevel * pow(specAngle, phExp); + } + else + { + return 0.0f; + } +} + +//=========================================================================== +// +// Calculates the brightness of a dynamic point light +// +//=========================================================================== + +float pointLightAttenuation(vec4 lightpos) +{ + float attenuation = max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; + if (uLightMath == 0) + { + return attenuation; + } + else + { + vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); + float diffuseAmount = diffuseContribution(lightDirection, pixelnormal); + if (uLightMath == 1) + { + return attenuation * diffuseAmount; + } + else + { + float specularAmount = blinnSpecularContribution(diffuseAmount, lightDirection, pixelpos.xyz, pixelnormal, 3.0, 1.2); + return attenuation * (diffuseAmount + specularAmount); + } + } +} //=========================================================================== // @@ -223,7 +305,7 @@ vec4 getLightColor(float fogdist, float fogfactor) vec4 lightpos = lights[i]; vec4 lightcolor = lights[i+1]; - lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; + lightcolor.rgb *= pointLightAttenuation(lightpos); dynlight.rgb += lightcolor.rgb; } // @@ -233,8 +315,8 @@ vec4 getLightColor(float fogdist, float fogfactor) { vec4 lightpos = lights[i]; vec4 lightcolor = lights[i+1]; - - lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; + + lightcolor.rgb *= pointLightAttenuation(lightpos); dynlight.rgb -= lightcolor.rgb; } } @@ -267,6 +349,13 @@ vec4 applyFog(vec4 frag, float fogfactor) void main() { vec4 frag = ProcessTexel(); + +#if defined NUM_UBO_LIGHTS || defined SHADER_STORAGE_LIGHTS + if (uLightMath != 0) // Remove this if pixelnormal is converted to an 'in' variable + { + pixelnormal = calculateFaceNormal(); + } +#endif #ifndef NO_ALPHATEST if (frag.a <= uAlphaThreshold) discard; @@ -292,12 +381,11 @@ void main() } else { - fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz)); + fogdist = max(16.0, length(pixelpos.xyz)); } fogfactor = exp2 (uFogDensity * fogdist); } - frag *= getLightColor(fogdist, fogfactor); #if defined NUM_UBO_LIGHTS || defined SHADER_STORAGE_LIGHTS @@ -316,7 +404,7 @@ void main() vec4 lightpos = lights[i]; vec4 lightcolor = lights[i+1]; - lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; + lightcolor.rgb *= pointLightAttenuation(lightpos); addlight.rgb += lightcolor.rgb; } frag.rgb = clamp(frag.rgb + desaturate(addlight).rgb, 0.0, 1.0); @@ -363,7 +451,7 @@ void main() } else { - fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz)); + fogdist = max(16.0, length(pixelpos.xyz)); } fogfactor = exp2 (uFogDensity * fogdist); diff --git a/wadsrc/static/shaders/glsl/main.vp b/wadsrc/static/shaders/glsl/main.vp index a2c1bac5b..27faafb86 100644 --- a/wadsrc/static/shaders/glsl/main.vp +++ b/wadsrc/static/shaders/glsl/main.vp @@ -43,7 +43,7 @@ void main() vColor = aColor; #ifndef SIMPLE - pixelpos.xyz = worldcoord.xyz; + pixelpos.xyz = eyeCoordPos.xyz; pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w; glowdist.x = -((uGlowTopPlane.w + uGlowTopPlane.x * worldcoord.x + uGlowTopPlane.y * worldcoord.z) * uGlowTopPlane.z) - worldcoord.y; diff --git a/wadsrc/static/shaders/glsl/shaderdefs.i b/wadsrc/static/shaders/glsl/shaderdefs.i index 3701694bc..0f0545b2d 100644 --- a/wadsrc/static/shaders/glsl/shaderdefs.i +++ b/wadsrc/static/shaders/glsl/shaderdefs.i @@ -44,6 +44,7 @@ uniform int uFogEnabled; // dynamic lights uniform int uLightIndex; +uniform int uLightMath; // 0, when using only attenuation, 1 for diffuse light, 2 for blinn specular light // quad drawer stuff #ifdef USE_QUAD_DRAWER