Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/engine/renderer/glsl_source/lighttile_fp.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ void main() {
or use compute shaders with atomics so we can have a variable amount of lights for each tile. */
for( uint i = uint( u_lightLayer ); i < uint( u_numLights ); i += uint( NUM_LIGHT_LAYERS ) ) {
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

Expand Down
128 changes: 125 additions & 3 deletions src/engine/renderer/tr_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ static Cvar::Cvar<bool> r_clear( "r_clear", "Clear screen before painting over i
Cvar::Cvar<bool> r_drawSky( "r_drawSky", "Draw the sky (clear the sky if disabled)", Cvar::NONE, true );
static Cvar::Cvar<int> r_showEntityBounds(
"r_showEntityBounds", "show bboxes used for culling (1: wireframe; 2: translucent solid)", Cvar::CHEAT, 0);
static Cvar::Cvar<bool> r_showDynamicLights(
"r_showDynamicLights", "visualize dynamic lights with tetrahedrons", Cvar::CHEAT, false );

void GL_Bind( image_t *image )
{
Expand Down Expand Up @@ -1301,7 +1303,7 @@ static void RenderDepthTiles()
{
RB_PrepareForSamplingDepthMap();
}

TransitionMSAAToMain( GL_DEPTH_BUFFER_BIT );

// 1st step
Expand All @@ -1317,7 +1319,7 @@ static void RenderDepthTiles()

gl_depthtile1Shader->SetUniform_zFar( zParams );
gl_depthtile1Shader->SetUniform_DepthMapBindless(
GL_BindToTMU( 0, tr.currentDepthImage )
GL_BindToTMU( 0, tr.currentDepthImage )
);

matrix_t ortho;
Expand Down Expand Up @@ -1727,7 +1729,7 @@ void RB_CameraPostFX() {
gl_cameraEffectsShader->SetUniform_Tonemap( tonemap );

gl_cameraEffectsShader->SetUniform_CurrentMapBindless(
GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] )
GL_BindToTMU( 0, tr.currentRenderImage[backEnd.currentMainFBO] )
);

if ( r_FXAA.Get() && gl_fxaaShader )
Expand Down Expand Up @@ -2312,6 +2314,125 @@ static void RB_RenderDebugUtils()
Tess_End();
}

if ( r_showDynamicLights.Get() && backEnd.refdef.numLights > 0 )
{
gl_genericShader->SetVertexSkinning( false );
gl_genericShader->SetVertexAnimation( false );
gl_genericShader->SetTCGenEnvironment( false );
gl_genericShader->SetTCGenLightmap( false );
gl_genericShader->SetDepthFade( false );
gl_genericShader->SetDeform( 0 );
gl_genericShader->BindProgram();

GL_State( GLS_DEFAULT );
GL_Cull( cullType_t::CT_TWO_SIDED );

// set uniforms
gl_genericShader->SetUniform_AlphaTest( GLS_ATEST_NONE );
SetUniform_ColorModulateColorGen( gl_genericShader, colorGen_t::CGEN_VERTEX,
alphaGen_t::AGEN_VERTEX );
SetUniform_Color( gl_genericShader, Color::Black );
gl_genericShader->SetUniform_ColorMapBindless( GL_BindToTMU( 0, tr.whiteImage ) );
gl_genericShader->SetUniform_TextureMatrix( matrixIdentity );

// set up the transformation matrix
backEnd.orientation = backEnd.viewParms.world;
GL_LoadModelViewMatrix( backEnd.orientation.modelViewMatrix );
gl_genericShader->SetUniform_ModelViewProjectionMatrix(
glState.modelViewProjectionMatrix[ glState.stackIndex ] );

Tess_Begin( Tess_StageIteratorDebug, nullptr, true, -1, 0 );
GL_CheckErrors();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oddly placed GL_CheckErrors.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is admittedly cargo culted:

Tess_Begin( Tess_StageIteratorDebug, nullptr, true, -1 );
GL_CheckErrors();

As a convention should I check for errors elsewhere?


const refLight_t *lights = backEnd.refdef.lights;
for ( int i = 0; i < backEnd.refdef.numLights; ++i )
{
const refLight_t &light = lights[ i ];
// We can't really visualize directional lights since they don't
// have an origin or a radius.
if ( light.rlType >= refLightType_t::RL_DIRECTIONAL )
{
continue;
}

vec3_t baseOrigin;
VectorCopy( light.origin, baseOrigin );

if ( light.radius <= 0.0f )
{
Log::Warn( "Light with index %d has no radius", i );
}

auto addArrow = [ & ]( const vec3_t dirInput, const Color::Color &arrowColor )
{
vec3_t dir;
VectorCopy( dirInput, dir );
if ( VectorNormalize( dir ) == 0.0f )
{
VectorSet( dir, 0.0f, 0.0f, 1.0f );
}
// idk why we need to negate here, but the arrow points the wrong way otherwise.
VectorNegate( dir, dir );

vec3_t tip;
VectorMA( baseOrigin, light.radius, dir, tip );

vec3_t tmp;
vec3_t tmp2;
vec3_t tmp3;
PerpendicularVector( tmp, dir );
VectorScale( tmp, light.radius * 0.2f, tmp2 );
VectorMA( tmp2, light.radius * 0.3f, dir, tmp2 );

vec4_t tetraVerts[ 4 ];
for ( int k = 0; k < 3; k++ )
{
RotatePointAroundVector( tmp3, dir, tmp2, k * 120.0f );
VectorAdd( tmp3, baseOrigin, tmp3 );
VectorCopy( tmp3, tetraVerts[ k ] );
tetraVerts[ k ][ 3 ] = 1.0f;
}

VectorCopy( baseOrigin, tetraVerts[ 3 ] );
tetraVerts[ 3 ][ 3 ] = 1.0f;
Tess_AddTetrahedron( tetraVerts, arrowColor );

VectorCopy( tip, tetraVerts[ 3 ] );
tetraVerts[ 3 ][ 3 ] = 1.0f;

Tess_AddTetrahedron( tetraVerts, arrowColor );
};

Color::Color color;
switch ( light.rlType )
{
case refLightType_t::RL_PROJ:
color = Color::LtGrey;
addArrow( light.projTarget, color );
break;
default:
color = Color::MdGrey;
{
static const vec3_t kOmniDirs[ 6 ] = {
{ 1.0f, 0.0f, 0.0f },
{ -1.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, -1.0f, 0.0f },
{ 0.0f, 0.0f, 1.0f },
{ 0.0f, 0.0f, -1.0f}
};
for ( int dirIndex = 0; dirIndex < 6; ++dirIndex )
{
addArrow( kOmniDirs[ dirIndex ], color );
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 12 tetrahedrons seems too busy to me. Maybe we could just draw a wireframe cube?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept tetrahedrons so I could show the direction of the light for projected lights and show that omni lights go in all directions. I also cargo culted the lightgrid code here.

I've found it helpful to debug dynamic light in my testing as is.

}
}
break;
}
}

Tess_End();
}

if ( r_showBspNodes->integer )
{
if ( ( backEnd.refdef.rdflags & ( RDF_NOWORLDMODEL ) ) || !tr.world )
Expand Down Expand Up @@ -3486,6 +3607,7 @@ const RenderCommand *SetupLightsCommand::ExecuteSelf() const
default:
break;
}
VectorNormalize( buffer[i].direction );
}

glUnmapBuffer( bufferTarget );
Expand Down
96 changes: 95 additions & 1 deletion src/engine/renderer/tr_scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ static void RE_RenderCubeProbeFace( const refdef_t* originalRefdef ) {
Log::Warn( "Cube probe face out of range! (%i/%i)", probeID, tr.cubeProbes.size() );
return;
}

refdef_t refdef{};
const int faceID = globalID % 6;

Expand Down Expand Up @@ -487,6 +487,91 @@ static void RE_RenderCubeProbeFace( const refdef_t* originalRefdef ) {

}

// Debug spot light (projected) injection
static Cvar::Cvar<bool> r_debugProjLight( "r_debugProjLight", "inject a directional sun light each frame", Cvar::CHEAT, false );
static Cvar::Range<Cvar::Cvar<float>> r_debugProjLightYaw( "r_debugProjLightYaw", "debug projected yaw in degrees", Cvar::NONE, 45.0f, -360.0f, 360.0f );
static Cvar::Range<Cvar::Cvar<float>> r_debugProjLightPitch( "r_debugProjLightPitch", "debug projected pitch in degrees", Cvar::NONE, -60.0f, -89.0f, 89.0f );
static Cvar::Cvar<float> r_debugProjLightRadius( "r_debugProjLightRadius", "debug projected radius (size)", Cvar::NONE, 100.0f );
static Cvar::Range<Cvar::Cvar<float>> r_debugProjLightR( "r_debugProjLightR", "debug projected color R", Cvar::NONE, 1.0f, 0.0f, 1.0f );
static Cvar::Range<Cvar::Cvar<float>> r_debugProjLightG( "r_debugProjLightG", "debug projected color G", Cvar::NONE, 1.0f, 0.0f, 1.0f );
static Cvar::Range<Cvar::Cvar<float>> r_debugProjLightB( "r_debugProjLightB", "debug projected color B", Cvar::NONE, 1.0f, 0.0f, 1.0f );
static Cvar::Cvar<float> r_debugProjLightOriginX( "r_debugProjLightOriginX", "debug projected origin X", Cvar::NONE, 0.0f );
static Cvar::Cvar<float> r_debugProjLightOriginY( "r_debugProjLightOriginY", "debug projected origin Y", Cvar::NONE, 0.0f );
static Cvar::Cvar<float> r_debugProjLightOriginZ( "r_debugProjLightOriginZ", "debug projected origin Z", Cvar::NONE, 0.0f );
static Cvar::Cvar<float> r_debugProjLightAngle( "r_debugProjLightAngle", "debug projected angle",
Cvar::NONE, 60.0f );

static void AddDebugProjectedLight()
{
if ( r_numLights >= MAX_REF_LIGHTS )
{
return;
}
refLight_t *light = &backEndData[ tr.smpFrame ]->lights[ r_numLights++ ];
*light = {};
light->rlType = refLightType_t::RL_PROJ;
// Compute direction from yaw/pitch cvars (in degrees)
float yaw = DEG2RAD( r_debugProjLightYaw.Get() );
float pitch = DEG2RAD( r_debugProjLightPitch.Get() );
// Right-handed: X forward, Y left, Z up. Direction vector components:
light->projTarget[ 0 ] = cosf( pitch ) * cosf( yaw );
light->projTarget[ 1 ] = cosf( pitch ) * sinf( yaw );
light->projTarget[ 2 ] = sinf( pitch );

vec3_t dir;
VectorCopy( light->projTarget, dir );
VectorNormalize( dir );

PerpendicularVector( light->projUp, dir );

float upLen = VectorLength( light->projUp );
float tgtLen = VectorLength( light->projTarget );

VectorScale( light->projUp, tanf( DEG2RAD( r_debugProjLightAngle.Get() ) ) / upLen / tgtLen,
light->projUp );

// Set properties
light->color[ 0 ] = r_debugProjLightR.Get();
light->color[ 1 ] = r_debugProjLightG.Get();
light->color[ 2 ] = r_debugProjLightB.Get();
light->radius = r_debugProjLightRadius.Get();
light->origin[ 0 ] = r_debugProjLightOriginX.Get();
light->origin[ 1 ] = r_debugProjLightOriginY.Get();
light->origin[ 2 ] = r_debugProjLightOriginZ.Get();
}

// Debug sun light (directional) injection
Cvar::Cvar<bool> r_debugSun( "r_debugSun", "inject a directional sun light each frame", Cvar::CHEAT, false );
Cvar::Range<Cvar::Cvar<float>> r_debugSunYaw( "r_debugSunYaw", "debug sun yaw in degrees", Cvar::NONE, 45.0f, -360.0f, 360.0f );
Cvar::Range<Cvar::Cvar<float>> r_debugSunPitch( "r_debugSunPitch", "debug sun pitch in degrees", Cvar::NONE, -60.0f, -89.0f, 89.0f );
Cvar::Range<Cvar::Cvar<float>> r_debugSunR( "r_debugSunR", "debug sun color R", Cvar::NONE, 1.0f, 0.0f, 10.0f );
Cvar::Range<Cvar::Cvar<float>> r_debugSunG( "r_debugSunG", "debug sun color G", Cvar::NONE, 1.0f, 0.0f, 10.0f );
Cvar::Range<Cvar::Cvar<float>> r_debugSunB( "r_debugSunB", "debug sun color B", Cvar::NONE, 1.0f, 0.0f, 10.0f );

static void AddDebugSunLight()
{
if ( r_numLights >= MAX_REF_LIGHTS )
{
return;
}
refLight_t *sun = &backEndData[ tr.smpFrame ]->lights[ r_numLights++ ];
*sun = {};
sun->rlType = refLightType_t::RL_DIRECTIONAL;
// Compute direction from yaw/pitch cvars (in degrees)
float yaw = DEG2RAD( r_debugSunYaw.Get() );
float pitch = DEG2RAD( r_debugSunPitch.Get() );
// Right-handed: X forward, Y left, Z up. Direction vector components:
sun->projTarget[ 0 ] = cosf( pitch ) * cosf( yaw );
sun->projTarget[ 1 ] = cosf( pitch ) * sinf( yaw );
sun->projTarget[ 2 ] = sinf( pitch );
VectorNormalize( sun->projTarget );
sun->color[ 0 ] = r_debugSunR.Get();
sun->color[ 1 ] = r_debugSunG.Get();
sun->color[ 2 ] = r_debugSunB.Get();
// Max radius to ensure it is always included.
sun->radius = std::numeric_limits<float>::max();
}

/*
@@@@@@@@@@@@@@@@@@@@@
RE_RenderScene
Expand Down Expand Up @@ -562,6 +647,15 @@ void RE_RenderScene( const refdef_t *fd )
}
}

if ( r_debugProjLight.Get() )
{
AddDebugProjectedLight();
}
if ( r_debugSun.Get() )
{
AddDebugSunLight();
}

// derived info
if ( r_forceRendererTime.Get() >= 0 ) {
tr.refdef.floatTime = float( double( r_forceRendererTime.Get() ) * 0.001 );
Expand Down
Loading