Implement gl3_colorlight, when set to 0, render lights without color

like the (original) software renderer. defaults to 1, of course
This commit is contained in:
Daniel Gibson 2022-03-26 19:48:11 +01:00
parent 187d19215c
commit cc0eabffed
4 changed files with 108 additions and 3 deletions

View file

@ -93,6 +93,7 @@ cvar_t *r_clear;
cvar_t *gl3_particle_size;
cvar_t *gl3_particle_fade_factor;
cvar_t *gl3_particle_square;
cvar_t *gl3_colorlight;
cvar_t *gl_lefthand;
cvar_t *r_gunfov;
@ -210,6 +211,8 @@ GL3_Register(void)
gl3_particle_size = ri.Cvar_Get("gl3_particle_size", "40", CVAR_ARCHIVE);
gl3_particle_fade_factor = ri.Cvar_Get("gl3_particle_fade_factor", "1.2", CVAR_ARCHIVE);
gl3_particle_square = ri.Cvar_Get("gl3_particle_square", "0", CVAR_ARCHIVE);
// if set to 0, lights (from lightmaps, dynamic lights and on models) are white instead of colored
gl3_colorlight = ri.Cvar_Get("gl3_colorlight", "1", CVAR_ARCHIVE);
// 0: use lots of calls to glBufferData()
// 1: reduce calls to glBufferData() with one big VBO (see GL3_BufferAndDraw3D())
@ -1746,9 +1749,10 @@ GL3_BeginFrame(float camera_separation)
GL3_UpdateUBO3D();
}
if(gl3_particle_square->modified)
if(gl3_particle_square->modified || gl3_colorlight->modified)
{
gl3_particle_square->modified = false;
gl3_colorlight->modified = false;
GL3_RecreateShaders();
}

View file

@ -161,6 +161,12 @@ DrawAliasFrameLerp(dmdl_t *paliashdr, entity_t* entity, vec3_t shadelight)
GL3_UseProgram(gl3state.si3Dalias.shaderProgram);
}
if(gl3_colorlight->value == 0.0f)
{
float avg = 0.333333f * (shadelight[0]+shadelight[1]+shadelight[2]);
shadelight[0] = shadelight[1] = shadelight[2] = avg;
}
/* move should be the delta back to the previous frame * backlerp */
VectorSubtract(entity->oldorigin, entity->origin, delta);
AngleVectors(entity->angles, vectors[0], vectors[1], vectors[2]);

View file

@ -516,6 +516,96 @@ static const char* fragmentSrc3Dlm = MULTILINE_STRING(
}
);
static const char* fragmentSrc3DlmNoColor = MULTILINE_STRING(
// it gets attributes and uniforms from fragmentCommon3D
struct DynLight { // gl3UniDynLight in C
vec3 lightOrigin;
float _pad;
//vec3 lightColor;
//float lightIntensity;
vec4 lightColor; // .a is intensity; this way it also works on OSX...
// (otherwise lightIntensity always contained 1 there)
};
layout (std140) uniform uniLights
{
DynLight dynLights[32];
uint numDynLights;
uint _pad1; uint _pad2; uint _pad3; // FFS, AMD!
};
uniform sampler2D tex;
uniform sampler2D lightmap0;
uniform sampler2D lightmap1;
uniform sampler2D lightmap2;
uniform sampler2D lightmap3;
uniform vec4 lmScales[4];
in vec2 passLMcoord;
in vec3 passWorldCoord;
in vec3 passNormal;
flat in uint passLightFlags;
void main()
{
vec4 texel = texture(tex, passTexCoord);
// apply intensity
texel.rgb *= intensity;
// apply lightmap
vec4 lmTex = texture(lightmap0, passLMcoord) * lmScales[0];
lmTex += texture(lightmap1, passLMcoord) * lmScales[1];
lmTex += texture(lightmap2, passLMcoord) * lmScales[2];
lmTex += texture(lightmap3, passLMcoord) * lmScales[3];
if(passLightFlags != 0u)
{
// TODO: or is hardcoding 32 better?
for(uint i=0u; i<numDynLights; ++i)
{
// I made the following up, it's probably not too cool..
// it basically checks if the light is on the right side of the surface
// and, if it is, sets intensity according to distance between light and pixel on surface
// dyn light number i does not affect this plane, just skip it
if((passLightFlags & (1u << i)) == 0u) continue;
float intens = dynLights[i].lightColor.a;
vec3 lightToPos = dynLights[i].lightOrigin - passWorldCoord;
float distLightToPos = length(lightToPos);
float fact = max(0, intens - distLightToPos - 52);
// move the light source a bit further above the surface
// => helps if the lightsource is so close to the surface (e.g. grenades, rockets)
// that the dot product below would return 0
// (light sources that are below the surface are filtered out by lightFlags)
lightToPos += passNormal*32.0;
// also factor in angle between light and point on surface
fact *= max(0, dot(passNormal, normalize(lightToPos)));
lmTex.rgb += dynLights[i].lightColor.rgb * fact * (1.0/256.0);
}
}
// turn lightcolor into grey for gl3_colorlight 0
lmTex.rgb = vec3(0.333 * (lmTex.r+lmTex.g+lmTex.b));
lmTex.rgb *= overbrightbits;
outColor = lmTex*texel;
outColor.rgb = pow(outColor.rgb, vec3(gamma)); // apply gamma correction to result
outColor.a = 1; // lightmaps aren't used with translucent surfaces
}
);
static const char* fragmentSrc3Dcolor = MULTILINE_STRING(
// it gets attributes and uniforms from fragmentCommon3D
@ -1011,7 +1101,11 @@ static qboolean createShaders(void)
R_Printf(PRINT_ALL, "WARNING: Failed to create shader program for color-only 2D rendering!\n");
return false;
}
if(!initShader3D(&gl3state.si3Dlm, vertexSrc3Dlm, fragmentSrc3Dlm))
const char* lightmappedFrag = (gl3_colorlight->value == 0.0f)
? fragmentSrc3DlmNoColor : fragmentSrc3Dlm;
if(!initShader3D(&gl3state.si3Dlm, vertexSrc3Dlm, lightmappedFrag))
{
R_Printf(PRINT_ALL, "WARNING: Failed to create shader program for textured 3D rendering with lightmap!\n");
return false;
@ -1038,7 +1132,7 @@ static qboolean createShaders(void)
R_Printf(PRINT_ALL, "WARNING: Failed to create shader program for water rendering!\n");
return false;
}
if(!initShader3D(&gl3state.si3DlmFlow, vertexSrc3DlmFlow, fragmentSrc3Dlm))
if(!initShader3D(&gl3state.si3DlmFlow, vertexSrc3DlmFlow, lightmappedFrag))
{
R_Printf(PRINT_ALL, "WARNING: Failed to create shader program for scrolling textured 3D rendering with lightmap!\n");
return false;

View file

@ -515,6 +515,7 @@ extern cvar_t *r_lightlevel;
extern cvar_t *gl3_overbrightbits;
extern cvar_t *gl3_particle_fade_factor;
extern cvar_t *gl3_particle_square;
extern cvar_t *gl3_colorlight;
extern cvar_t *r_modulate;
extern cvar_t *gl_lightmap;