mirror of
https://github.com/dhewm/dhewm3.git
synced 2025-03-22 10:41:08 +00:00
Integrate (working!) soft particle shader, clean up that code a bit
turned out the whole problem with soft particles what that the vertex shader used vertex.attrib[8] instead of vertex.texcoord (and with nvidia drivers those are equivalent) I integrated the shader source into the c++ code so I don't have to ship glprogs/soft_particles.vfp
This commit is contained in:
parent
a407a6060f
commit
3c887d5af5
5 changed files with 127 additions and 31 deletions
|
@ -239,6 +239,10 @@ idCVar r_screenshotPngCompression("r_screenshotPngCompression", "3", CVAR_RENDER
|
|||
idCVar r_windowResizable("r_windowResizable", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Allow resizing (and maximizing) the window (needs SDL2; with 2.0.5 or newer it's applied immediately)" );
|
||||
idCVar r_vidRestartAlwaysFull( "r_vidRestartAlwaysFull", 0, CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Always do a full vid_restart (ignore 'partial' argument), e.g. when changing window size" );
|
||||
|
||||
// DG: for soft particles (ported from TDM)
|
||||
idCVar r_skipDepthCapture( "r_skipDepthCapture", "0", CVAR_RENDERER | CVAR_BOOL, "skip depth capture" ); // #3877
|
||||
idCVar r_useSoftParticles( "r_useSoftParticles", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "soften particle transitions when player walks through them or they cross solid geometry" );
|
||||
|
||||
idCVar r_glDebugContext( "r_glDebugContext", "0", CVAR_RENDERER | CVAR_BOOL, "Enable OpenGL Debug context - requires vid_restart, needs SDL2" );
|
||||
|
||||
// define qgl functions
|
||||
|
|
|
@ -346,12 +346,96 @@ static progDef_t progs[MAX_GLPROGS] = {
|
|||
{ GL_FRAGMENT_PROGRAM_ARB, FPROG_GLASSWARP, "arbFP_glasswarp.txt" },
|
||||
|
||||
// SteveL #3878: Particle softening applied by the engine
|
||||
{ GL_VERTEX_PROGRAM_ARB, VPROG_SOFT_PARTICLE, "soft_particle.vfp" }, // TODO: can we specify this in C++?
|
||||
{ GL_FRAGMENT_PROGRAM_ARB, FPROG_SOFT_PARTICLE, "soft_particle.vfp" },
|
||||
{ GL_VERTEX_PROGRAM_ARB, VPROG_SOFT_PARTICLE, "soft_particle.vp" },
|
||||
{ GL_FRAGMENT_PROGRAM_ARB, FPROG_SOFT_PARTICLE, "soft_particle.fp" },
|
||||
|
||||
// additional programs can be dynamically specified in materials
|
||||
};
|
||||
|
||||
// DG: the following two shaders are taken from TheDarkMod 2.04 (glprogs/soft_particle.vfp)
|
||||
// (C) 2005-2016 Broken Glass Studios (The Dark Mod Team) and the individual authors
|
||||
// released under a revised BSD license and GPLv3
|
||||
const char* softpartVShader = "!!ARBvp1.0 \n"
|
||||
"OPTION ARB_position_invariant; \n"
|
||||
"# NOTE: unlike the TDM shader, the following lines use .texcoord and .color \n"
|
||||
"# instead of .attrib[8] and .attrib[3], to make it work with non-nvidia drivers \n"
|
||||
"MOV result.texcoord, vertex.texcoord; \n"
|
||||
"MOV result.color, vertex.color; \n"
|
||||
"END \n";
|
||||
|
||||
const char* softpartFShader = "!!ARBfp1.0 \n"
|
||||
"# == Fragment Program == \n"
|
||||
"# taken from The Dark Mod 2.04, adjusted for dhewm3 \n"
|
||||
"# (C) 2005-2016 Broken Glass Studios (The Dark Mod Team) \n"
|
||||
"# \n"
|
||||
"# Input textures \n"
|
||||
"# texture[0] particle diffusemap \n"
|
||||
"# texture[1] _currentDepth \n"
|
||||
"# \n"
|
||||
"# Constants set by the engine: \n"
|
||||
"# program.env[22] is reciprocal of _currentDepth size. Lets us convert a screen position to a texcoord in _currentDepth \n"
|
||||
"# { 1.0f / depthtex.width, 1.0f / depthtex.height, float(depthtex.width)/int(depthtex.width), \n"
|
||||
"# float(depthtex.height)/int(depthtex.height) } \n"
|
||||
"# program.env[23] is the particle radius, given as { radius, 1/(fadeRange), 1/radius } \n"
|
||||
"# fadeRange is the particle diameter for alpha blends (like smoke), but the particle radius for additive \n"
|
||||
"# blends (light glares), because additive effects work differently. Fog is half as apparent when a wall \n"
|
||||
"# is in the middle of it. Light glares lose no visibility when they have something to reflect off. \n"
|
||||
"# program.env[24] is the color channel mask. Particles with additive blend need their RGB channels modified to blend them out. \n"
|
||||
"# Particles with an alpha blend need their alpha channel modified. \n"
|
||||
"# \n"
|
||||
"# Hard-coded constants \n"
|
||||
"# depth_consts allows us to recover the original depth in Doom units of anything in the depth \n"
|
||||
"# buffer. Doom3's and thus TDM's projection matrix differs slightly from the classic projection matrix as \n"
|
||||
"# it implements a \"nearly-infinite\" zFar. The matrix is hard-coded in the engine, so we use hard-coded \n"
|
||||
"# constants here for efficiency. depth_consts is derived from the numbers in that matrix. \n"
|
||||
"# \n"
|
||||
"# next line: prevent dhewm3 from injecting gamma in shader code into this shader, \n"
|
||||
"# because that looks bad when rendered with additive blending (gets too bright) \n"
|
||||
"# nodhewm3gammahack \n"
|
||||
"\n"
|
||||
"PARAM depth_consts = { 0.33333333, -0.33316667, 0.0, 0.0 }; \n"
|
||||
"PARAM particle_radius = program.env[23]; \n"
|
||||
"TEMP tmp, scene_depth, particle_depth, near_fade, fade; \n"
|
||||
"\n"
|
||||
"# Map the fragment to a texcoord on our depth image, and sample to find scene_depth \n"
|
||||
"MUL tmp.xy, fragment.position, program.env[22]; \n"
|
||||
"TEX scene_depth, tmp, texture[1], 2D; \n"
|
||||
"MIN scene_depth, scene_depth, 0.9994; # Required by TDM projection matrix. Equates to max recoverable \n"
|
||||
" # depth of 30k units, which is enough. 0.9995 is infinite depth. \n"
|
||||
" # This is needed only if there is caulk sky on show (which writes \n"
|
||||
" # no depth, so leaves 1 in the depth texture). \n"
|
||||
"\n"
|
||||
"# Recover original depth in doom units \n"
|
||||
"MAD tmp, scene_depth, depth_consts.x, depth_consts.y; \n"
|
||||
"RCP scene_depth, tmp.x; \n"
|
||||
"\n"
|
||||
"# Convert particle depth to doom units too \n"
|
||||
"MAD tmp, fragment.position.z, depth_consts.x, depth_consts.y; \n"
|
||||
"RCP particle_depth, tmp.x; \n"
|
||||
"\n"
|
||||
"# Scale the depth difference by the particle diameter to calc an alpha \n"
|
||||
"# value based on how much of the 3d volume represented by the particle \n"
|
||||
"# is in front of the solid scene \n"
|
||||
"ADD tmp, -scene_depth, particle_depth; # NB depth is negative. 0 at the eye, -100 at 100 units into the screen. \n"
|
||||
"ADD tmp, tmp, particle_radius.x; # Add the radius so a depth difference of particle radius now equals 0 \n"
|
||||
"MUL_SAT fade, tmp, particle_radius.y; # divide by the particle radius or diameter and clamp \n"
|
||||
"\n"
|
||||
"# Also fade if the particle is too close to our eye position, so it doesn't 'pop' in and out of view \n"
|
||||
"# Start a linear fade at particle_radius distance from the particle. \n"
|
||||
"MUL_SAT near_fade, particle_depth, -particle_radius.z; \n"
|
||||
"\n"
|
||||
"# Calculate final fade and apply the channel mask \n"
|
||||
"MUL fade, near_fade, fade; \n"
|
||||
"ADD_SAT fade, fade, program.env[24]; # saturate the channels that don't want modifying \n"
|
||||
"\n"
|
||||
"# Set the color. Multiply by vertex/fragment color as that's how the particle system fades particles in and out \n"
|
||||
"TEMP oColor; \n"
|
||||
"TEX oColor, fragment.texcoord, texture[0], 2D; \n"
|
||||
"MUL oColor, oColor, fade; \n"
|
||||
"MUL result.color, oColor, fragment.color; \n"
|
||||
"\n"
|
||||
"END \n";
|
||||
|
||||
/*
|
||||
=================
|
||||
R_LoadARBProgram
|
||||
|
@ -395,27 +479,37 @@ static ID_INLINE bool isARBidentifierChar( int c ) {
|
|||
void R_LoadARBProgram( int progIndex ) {
|
||||
int ofs;
|
||||
int err;
|
||||
idStr fullPath = "glprogs/";
|
||||
fullPath += progs[progIndex].name;
|
||||
char *fileBuffer;
|
||||
char *buffer;
|
||||
char *start = NULL, *end;
|
||||
|
||||
common->Printf( "%s", fullPath.c_str() );
|
||||
if ( progs[progIndex].ident == VPROG_SOFT_PARTICLE || progs[progIndex].ident == FPROG_SOFT_PARTICLE ) {
|
||||
// these shaders are loaded directly from a string
|
||||
common->Printf( "<internal> %s", progs[progIndex].name );
|
||||
const char* srcstr = (progs[progIndex].ident == VPROG_SOFT_PARTICLE) ? softpartVShader : softpartFShader;
|
||||
|
||||
// load the program even if we don't support it, so
|
||||
// fs_copyfiles can generate cross-platform data dumps
|
||||
fileSystem->ReadFile( fullPath.c_str(), (void **)&fileBuffer, NULL );
|
||||
if ( !fileBuffer ) {
|
||||
common->Printf( ": File not found\n" );
|
||||
return;
|
||||
// copy to stack memory
|
||||
buffer = (char *)_alloca( strlen( srcstr ) + 1 );
|
||||
strcpy( buffer, srcstr );
|
||||
} else {
|
||||
idStr fullPath = "glprogs/";
|
||||
fullPath += progs[progIndex].name;
|
||||
char *fileBuffer;
|
||||
common->Printf( "%s", fullPath.c_str() );
|
||||
|
||||
// load the program even if we don't support it, so
|
||||
// fs_copyfiles can generate cross-platform data dumps
|
||||
fileSystem->ReadFile( fullPath.c_str(), (void **)&fileBuffer, NULL );
|
||||
if ( !fileBuffer ) {
|
||||
common->Printf( ": File not found\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// copy to stack memory and free
|
||||
buffer = (char *)_alloca( strlen( fileBuffer ) + 1 );
|
||||
strcpy( buffer, fileBuffer );
|
||||
fileSystem->FreeFile( fileBuffer );
|
||||
}
|
||||
|
||||
// copy to stack memory and free
|
||||
buffer = (char *)_alloca( strlen( fileBuffer ) + 1 );
|
||||
strcpy( buffer, fileBuffer );
|
||||
fileSystem->FreeFile( fileBuffer );
|
||||
|
||||
if ( !glConfig.isInitialized ) {
|
||||
return;
|
||||
}
|
||||
|
@ -465,7 +559,7 @@ void R_LoadARBProgram( int progIndex ) {
|
|||
// note that strlen("dhewm3tmpres") == strlen("result.color")
|
||||
const char* tmpres = "TEMP dhewm3tmpres; # injected by dhewm3 for gamma correction\n";
|
||||
|
||||
// Note: program.env[4].xyz = r_brightness; program.env[4].w = 1.0/r_gamma
|
||||
// Note: program.env[21].xyz = r_brightness; program.env[21].w = 1.0/r_gamma
|
||||
// outColor.rgb = pow(dhewm3tmpres.rgb*r_brightness, vec3(1.0/r_gamma))
|
||||
// outColor.a = dhewm3tmpres.a;
|
||||
const char* extraLines =
|
||||
|
|
|
@ -34,8 +34,6 @@ If you have questions concerning this license or the applicable additional terms
|
|||
extern idCVar r_useCarmacksReverse;
|
||||
extern idCVar r_useStencilOpSeparate;
|
||||
|
||||
idCVar r_skipDepthCapture( "r_skipDepthCapture", "0", CVAR_RENDERER | CVAR_BOOL, "skip depth capture" ); // #3877
|
||||
|
||||
/*
|
||||
=====================
|
||||
RB_BakeTextureMatrixIntoTexgen
|
||||
|
@ -952,13 +950,14 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
|||
qglEnableClientState( GL_COLOR_ARRAY );
|
||||
}
|
||||
|
||||
|
||||
//GL_State( pStage->drawStateBits | GLS_DEPTHFUNC_ALWAYS ); // Disable depth clipping. The fragment program will
|
||||
// handle it to allow overdraw.
|
||||
#if 0 // debug stuff: render particles opaque so debug colors written in the shader are properly visible
|
||||
int dsbits = pStage->drawStateBits | GLS_DEPTHFUNC_ALWAYS;
|
||||
dsbits &= ~(GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS);
|
||||
//dsbits |= GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO; both values are 0, so this would be a noop
|
||||
GL_State( dsbits );
|
||||
#endif
|
||||
GL_State( pStage->drawStateBits | GLS_DEPTHFUNC_ALWAYS ); // Disable depth clipping. The fragment program will
|
||||
// handle it to allow overdraw.
|
||||
|
||||
qglBindProgramARB( GL_VERTEX_PROGRAM_ARB, VPROG_SOFT_PARTICLE );
|
||||
qglEnable( GL_VERTEX_PROGRAM_ARB );
|
||||
|
@ -972,6 +971,7 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
|||
qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, FPROG_SOFT_PARTICLE );
|
||||
qglEnable( GL_FRAGMENT_PROGRAM_ARB );
|
||||
|
||||
#if 0 // debug stuff
|
||||
// Set up parameters for fragment program
|
||||
const char* srcblendstr = "???";
|
||||
if ( src_blend >= 0 && src_blend <= 9 ) {
|
||||
|
@ -1006,14 +1006,15 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
|||
#undef MY_CASE
|
||||
}
|
||||
|
||||
//printf("XX mat: %s, src_blend = %s dest_blend = %s radius = %g\n", shader->GetName(), srcblendstr, dstblend, surf->particle_radius);
|
||||
printf("XX mat: %s, src_blend = %s dest_blend = %s radius = %g\n", shader->GetName(), srcblendstr, dstblend, surf->particle_radius);
|
||||
#endif
|
||||
|
||||
// program.env[5] is the particle radius, given as { radius, 1/(faderange), 1/radius }
|
||||
// program.env[23] is the particle radius, given as { radius, 1/(faderange), 1/radius }
|
||||
float fadeRange = 1.0f;
|
||||
// fadeRange is the particle diameter for alpha blends (like smoke), but the particle radius for additive
|
||||
// blends (light glares), because additive effects work differently. Fog is half as apparent when a wall
|
||||
// is in the middle of it. Light glares lose no visibility when they have something to reflect off. See
|
||||
// issue #3878 for diagram
|
||||
// The Dark Mod issue #3878 for diagram
|
||||
if ( src_blend == GLS_SRCBLEND_SRC_ALPHA ) // an alpha blend material
|
||||
{
|
||||
fadeRange = surf->particle_radius * 2.0f;
|
||||
|
@ -1031,7 +1032,7 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
|||
};
|
||||
qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_PARTICLE_RADIUS, parm );
|
||||
|
||||
// program.env[6] is the color channel mask. It gets added to the fade multiplier, so adding 1
|
||||
// program.env[24] is the color channel mask. It gets added to the fade multiplier, so adding 1
|
||||
// to a channel will make sure it doesn't get faded at all. Particles with additive blend
|
||||
// need their RGB channels modifying to blend them out. Particles with an alpha blend need
|
||||
// their alpha channel modifying.
|
||||
|
@ -1045,8 +1046,6 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
|||
parm[0] = parm[1] = parm[2] = 0.0f; // Fade the rgb channels but
|
||||
parm[3] = 1.0f; // leave the alpha channel at full strength
|
||||
}
|
||||
//parm[0] = parm[1] = parm[2] = 1.0f; // XXX hack
|
||||
//parm[3] = 1.0f; // XXX hack
|
||||
qglProgramEnvParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, PP_PARTICLE_COLCHAN_MASK, parm );
|
||||
|
||||
// draw it
|
||||
|
|
|
@ -40,8 +40,6 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
static const float CHECK_BOUNDS_EPSILON = 1.0f;
|
||||
|
||||
static idCVar r_useSoftParticles( "r_useSoftParticles", "1", CVAR_RENDERER | CVAR_BOOL, "soften particle transitions when player walks through them or they cross solid geometry" );
|
||||
|
||||
/*
|
||||
===========================================================================================
|
||||
|
||||
|
|
|
@ -985,6 +985,7 @@ extern idCVar r_debugRenderToTexture;
|
|||
|
||||
extern idCVar r_glDebugContext; // DG: use debug context to call logging callbacks on GL errors
|
||||
extern idCVar r_skipDepthCapture; // DG: disable capturing depth buffer, used for soft particles
|
||||
extern idCVar r_useSoftParticles;
|
||||
|
||||
/*
|
||||
====================================================================
|
||||
|
|
Loading…
Reference in a new issue