mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2024-11-10 06:31:48 +00:00
depth fade fixes and improvements
- renamed r_softSprites to r_depthFade the term's more descriptive and it helps that UE4 uses it - fixed the GL3 fragment shader halving the depth bias - fixed the D3D11 pixel shader only fetching depth sample 0 not fixed for GL3 yet, see the code comments for that - added support for more blend states - added the q3map_cnq3_depthFade general shader directive
This commit is contained in:
parent
a59875200c
commit
718b966414
11 changed files with 264 additions and 105 deletions
|
@ -13,12 +13,12 @@ add: r_backend <GL2|GL3|D3D11> (default: D3D11 on Windows, GL3 otherwise) select
|
|||
-----------------------|--------|--------|--------------------|
|
||||
MSAA | GL 3.0 | always | always |
|
||||
MSAA centroid sampling | never | always | always |
|
||||
depth sprites | never | always | always |
|
||||
depth fade | never | always | always |
|
||||
alpha to coverage AA | never | always | always |
|
||||
dithering | never | always | always |
|
||||
GPU mip-map generation | never | GL 4.3 | feature level 11.0 |
|
||||
|
||||
add: r_softSprite <0|1> (default: 1) enables depth sprites (soft particles)
|
||||
add: r_depthFade <0|1> (default: 1) enables depth fade rendering
|
||||
this helps explosions, smoke, blood, etc. not having "sharp edges" when intersecting geometry
|
||||
|
||||
add: r_alphaToCoverage <0|1> (default: 1) enables alpha to coverage anti-aliasing
|
||||
|
@ -100,6 +100,15 @@ add: r_transpSort <0|1> (default: 0) to select the transparency sorting mode
|
|||
quite inconsistent based on the view angles and surface dimensions
|
||||
example: dropped items in the cpm18r acid with cg_simpleItems 1
|
||||
|
||||
add: global shader directive q3map_cnq3_depthFade <scale> <bias> enables depth fade rendering
|
||||
scale is the depth range over wich to fade the currently rendered surface
|
||||
bias is a value added to the currently rendered surface's depth, positive goes towards the camera
|
||||
whether this is enabled is decided by r_depthFade (must be 1) and r_backend (can't be GL2)
|
||||
depth writes must be disabled in all stages (no shader stage can use the depthWrite directive)
|
||||
the blend mode (blendFunc) must be the same for all stages and must be one of:
|
||||
(one, one) (src_alpha, one) (one_minus_src_alpha, one) (dst_color, zero) (zero, src_color)
|
||||
(src_alpha, one_minus_src_alpha) (one, one_minus_src_alpha)
|
||||
|
||||
add: r_mapBrightness now works on q3map2's external lightmap atlas images
|
||||
|
||||
add: the renderer can now batch surfaces with different (but sufficiently similar) shaders
|
||||
|
|
|
@ -39,6 +39,7 @@ struct VOut
|
|||
float4 position : SV_Position;
|
||||
float4 color : COLOR0;
|
||||
float2 texCoords : TEXCOORD0;
|
||||
float2 proj2232 : TEXCOORD1;
|
||||
float depthVS : DEPTHVS;
|
||||
float clipDist : SV_ClipDistance0;
|
||||
};
|
||||
|
@ -51,6 +52,7 @@ VOut vs_main(VIn input)
|
|||
output.position = mul(projectionMatrix, positionVS);
|
||||
output.color = input.color;
|
||||
output.texCoords = input.texCoords;
|
||||
output.proj2232 = float2(-projectionMatrix[2][2], projectionMatrix[2][3]);
|
||||
output.depthVS = -positionVS.z;
|
||||
output.clipDist = dot(positionVS, clipPlane);
|
||||
|
||||
|
@ -60,13 +62,11 @@ VOut vs_main(VIn input)
|
|||
cbuffer PixelShaderBuffer
|
||||
{
|
||||
uint alphaTest;
|
||||
float proj22;
|
||||
float proj32;
|
||||
float additive;
|
||||
float distance;
|
||||
float offset;
|
||||
uint dummy0;
|
||||
uint dummy1;
|
||||
float dummy;
|
||||
float4 colorScale;
|
||||
float4 colorBias;
|
||||
};
|
||||
|
||||
Texture2D texture0 : register(t0);
|
||||
|
@ -74,7 +74,20 @@ SamplerState sampler0 : register(s0);
|
|||
|
||||
Texture2DMS<float2> textureDepth;
|
||||
|
||||
float LinearDepth(float zwDepth)
|
||||
/*
|
||||
f = far clip plane distance
|
||||
n = near clip plane distance
|
||||
exp = exponential depth value (as stored in the Z-buffer)
|
||||
|
||||
2 * f * n B
|
||||
linear(exp) = ----------------------- = -------
|
||||
(f + n) - exp * (f - n) exp - A
|
||||
|
||||
f + n -2 * f * n
|
||||
with A = ----- and B = ----------
|
||||
f - n f - n
|
||||
*/
|
||||
float LinearDepth(float zwDepth, float proj22, float proj32)
|
||||
{
|
||||
return proj32 / (zwDepth - proj22);
|
||||
}
|
||||
|
@ -88,7 +101,7 @@ float Contrast(float d, float power)
|
|||
return aboveHalf ? (1.0 - r) : r;
|
||||
}
|
||||
|
||||
float4 ps_main(VOut input) : SV_TARGET
|
||||
float4 ps_main(VOut input, uint sampleIndex : SV_SampleIndex) : SV_TARGET
|
||||
{
|
||||
float4 r = input.color * texture0.Sample(sampler0, input.texCoords);
|
||||
if((alphaTest == 1 && r.a == 0.0) ||
|
||||
|
@ -96,12 +109,11 @@ float4 ps_main(VOut input) : SV_TARGET
|
|||
(alphaTest == 3 && r.a < 0.5))
|
||||
discard;
|
||||
|
||||
float depthS = LinearDepth(textureDepth.Load(input.position.xy, 0).x);
|
||||
float zwDepth = textureDepth.Load(input.position.xy, sampleIndex).x;
|
||||
float depthS = LinearDepth(zwDepth, input.proj2232.x, input.proj2232.y);
|
||||
float depthP = input.depthVS - offset;
|
||||
float scale = Contrast((depthS - depthP) * distance, 2.0);
|
||||
float scaleColor = max(scale, 1.0 - additive);
|
||||
float scaleAlpha = max(scale, additive);
|
||||
float4 r2 = float4(r.rgb * scaleColor, r.a * scaleAlpha);
|
||||
float4 r2 = lerp(r * colorScale + colorBias, r, scale);
|
||||
|
||||
return r2;
|
||||
}
|
||||
|
|
|
@ -187,7 +187,7 @@ static qbool AreShadersStillBatchable( const shader_t* a, const shader_t* b )
|
|||
a->polygonOffset != b->polygonOffset ||
|
||||
a->imgflags != b->imgflags ||
|
||||
a->numStages != b->numStages ||
|
||||
a->softSprite != b->softSprite )
|
||||
a->dfType != b->dfType )
|
||||
return qfalse;
|
||||
|
||||
for ( int i = 0; i < a->numStages; ++i ) {
|
||||
|
@ -258,10 +258,10 @@ static void RB_RenderDrawSurfList( const drawSurf_t* drawSurfs, int numDrawSurfs
|
|||
const shader_t* shaderPrev = shader;
|
||||
int entityNum;
|
||||
R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum );
|
||||
const qbool softSpriteChange = shader->softSprite != tess.softSprite;
|
||||
const qbool depthFadeChange = shader->dfType != tess.depthFade;
|
||||
|
||||
// detect and batch surfaces across different (but sufficiently similar) shaders
|
||||
if ( !softSpriteChange &&
|
||||
if ( !depthFadeChange &&
|
||||
oldEntityNum == ENTITYNUM_WORLD &&
|
||||
entityNum == ENTITYNUM_WORLD &&
|
||||
AreShadersStillBatchable( shaderPrev, shader ) ) {
|
||||
|
@ -298,11 +298,11 @@ static void RB_RenderDrawSurfList( const drawSurf_t* drawSurfs, int numDrawSurfs
|
|||
// modern code just billboards in cgame and submits raw polys, all of which are
|
||||
// ENTITYNUM_WORLD and thus automatically take the "same sort" fast path
|
||||
|
||||
if ( !shader->entityMergable || ((sort ^ drawSurf->sort) & ~QSORT_ENTITYNUM_MASK) || softSpriteChange ) {
|
||||
if ( !shader->entityMergable || ((sort ^ drawSurf->sort) & ~QSORT_ENTITYNUM_MASK) || depthFadeChange ) {
|
||||
if (shaderPrev)
|
||||
RB_EndSurface();
|
||||
RB_BeginSurface( shader, fogNum );
|
||||
tess.softSprite = shader->softSprite;
|
||||
tess.depthFade = shader->dfType;
|
||||
}
|
||||
|
||||
sort = drawSurf->sort;
|
||||
|
|
|
@ -176,22 +176,21 @@ struct GenericPSData
|
|||
float dummy;
|
||||
};
|
||||
|
||||
struct SoftSpriteVSData
|
||||
struct DepthFadeVSData
|
||||
{
|
||||
float modelViewMatrix[16];
|
||||
float projectionMatrix[16];
|
||||
float clipPlane[4];
|
||||
};
|
||||
|
||||
struct SoftSpritePSData
|
||||
struct DepthFadePSData
|
||||
{
|
||||
uint32_t alphaTest; // AlphaTest enum
|
||||
float proj22;
|
||||
float proj32;
|
||||
float additive;
|
||||
float distance;
|
||||
float offset;
|
||||
uint32_t dummy[2];
|
||||
float dummy;
|
||||
float scale[4];
|
||||
float bias[4];
|
||||
};
|
||||
|
||||
struct DynamicLightVSData
|
||||
|
@ -691,17 +690,16 @@ static void UploadPendingShaderData()
|
|||
}
|
||||
else if(pid == PID_SOFT_SPRITE)
|
||||
{
|
||||
SoftSpriteVSData vsData;
|
||||
SoftSpritePSData psData;
|
||||
DepthFadeVSData vsData;
|
||||
DepthFadePSData psData;
|
||||
memcpy(vsData.modelViewMatrix, d3d.modelViewMatrix, sizeof(vsData.modelViewMatrix));
|
||||
memcpy(vsData.projectionMatrix, d3d.projectionMatrix, sizeof(vsData.projectionMatrix));
|
||||
memcpy(vsData.clipPlane, d3d.clipPlane, sizeof(vsData.clipPlane));
|
||||
psData.alphaTest = d3d.alphaTest;
|
||||
psData.proj22 = -vsData.projectionMatrix[2 * 4 + 2];
|
||||
psData.proj32 = vsData.projectionMatrix[3 * 4 + 2];
|
||||
psData.additive = tess.shader->softSprite == SST_ADDITIVE ? 1.0f : 0.0f;
|
||||
psData.distance = tess.shader->softSpriteDistance;
|
||||
psData.offset = tess.shader->softSpriteOffset;
|
||||
memcpy(psData.scale, r_depthFadeScale[tess.shader->dfType], sizeof(psData.scale));
|
||||
memcpy(psData.bias, r_depthFadeBias[tess.shader->dfType], sizeof(psData.bias));
|
||||
psData.distance = tess.shader->dfInvDist;
|
||||
psData.offset = tess.shader->dfBias;
|
||||
ResetShaderData(pipeline->vertexBuffer, &vsData, sizeof(vsData));
|
||||
ResetShaderData(pipeline->pixelBuffer, &psData, sizeof(psData));
|
||||
}
|
||||
|
@ -1585,14 +1583,14 @@ static qbool GAL_Init()
|
|||
|
||||
ZeroMemory(&vertexShaderBufferDesc, sizeof(vertexShaderBufferDesc));
|
||||
vertexShaderBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
vertexShaderBufferDesc.ByteWidth = sizeof(SoftSpriteVSData);
|
||||
vertexShaderBufferDesc.ByteWidth = sizeof(DepthFadeVSData);
|
||||
vertexShaderBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
vertexShaderBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
D3D11_CreateBuffer(&vertexShaderBufferDesc, NULL, &d3d.pipelines[PID_SOFT_SPRITE].vertexBuffer, "soft sprite vertex shader buffer");
|
||||
|
||||
ZeroMemory(&pixelShaderBufferDesc, sizeof(pixelShaderBufferDesc));
|
||||
pixelShaderBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
pixelShaderBufferDesc.ByteWidth = sizeof(SoftSpritePSData);
|
||||
pixelShaderBufferDesc.ByteWidth = sizeof(DepthFadePSData);
|
||||
pixelShaderBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
pixelShaderBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
D3D11_CreateBuffer(&pixelShaderBufferDesc, NULL, &d3d.pipelines[PID_SOFT_SPRITE].pixelBuffer, "soft sprite pixel shader buffer");
|
||||
|
@ -1693,7 +1691,7 @@ static qbool GAL_Init()
|
|||
glInfo.displayFrequency = 0;
|
||||
glInfo.maxAnisotropy = D3D11_REQ_MAXANISOTROPY; // @NOTE: D3D10_REQ_MAXANISOTROPY == D3D11_REQ_MAXANISOTROPY
|
||||
glInfo.maxTextureSize = MAX_GPU_TEXTURE_SIZE;
|
||||
glInfo.softSpriteSupport = r_softSprites->integer == 1;
|
||||
glInfo.depthFadeSupport = r_depthFade->integer == 1;
|
||||
glInfo.mipGenSupport = mipGenOK;
|
||||
glInfo.alphaToCoverageSupport = alphaToCoverageOK;
|
||||
|
||||
|
@ -2368,7 +2366,7 @@ static void DrawDynamicLight()
|
|||
DrawIndexed(tess.dlNumIndexes);
|
||||
}
|
||||
|
||||
static void DrawSoftSprite()
|
||||
static void DrawDepthFade()
|
||||
{
|
||||
AppendVertexData(&d3d.indexBuffer, tess.indexes, tess.numIndexes);
|
||||
if(d3d.splitBufferOffsets)
|
||||
|
@ -2421,7 +2419,7 @@ static void GAL_Draw(drawType_t type)
|
|||
else if(type == DT_SOFT_SPRITE)
|
||||
{
|
||||
ApplyPipeline(PID_SOFT_SPRITE);
|
||||
DrawSoftSprite();
|
||||
DrawDepthFade();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1422,7 +1422,7 @@ static void InitGLInfo()
|
|||
else
|
||||
glInfo.maxAnisotropy = 0;
|
||||
|
||||
glInfo.softSpriteSupport = qfalse;
|
||||
glInfo.depthFadeSupport = qfalse;
|
||||
glInfo.mipGenSupport = qfalse;
|
||||
glInfo.alphaToCoverageSupport = qfalse;
|
||||
}
|
||||
|
|
|
@ -172,8 +172,9 @@ enum SoftSpriteUniform
|
|||
SU_PROJECTION,
|
||||
SU_CLIP_PLANE,
|
||||
SU_ALPHA_TEST,
|
||||
SU_PROJ22_32,
|
||||
SU_ADD_DIST_OFFSET,
|
||||
SU_DIST_OFFSET,
|
||||
SU_COLOR_SCALE,
|
||||
SU_COLOR_BIAS,
|
||||
SU_COUNT
|
||||
};
|
||||
|
||||
|
@ -236,6 +237,10 @@ struct OpenGL3
|
|||
AlphaTest alphaTest;
|
||||
qbool dlOpaque;
|
||||
float dlIntensity;
|
||||
float depthFadeScale[4];
|
||||
float depthFadeBias[4];
|
||||
float depthFadeDist;
|
||||
float depthFadeOffset;
|
||||
|
||||
ArrayBuffer arrayBuffers[VB_COUNT];
|
||||
ArrayBuffer indexBuffer;
|
||||
|
@ -476,6 +481,7 @@ static const char* sprite_vs =
|
|||
"out vec2 texCoords1FS;\n"
|
||||
"out vec4 colorFS;\n"
|
||||
"out float depthVS;\n"
|
||||
"out vec2 proj22_32;\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
|
@ -485,6 +491,7 @@ static const char* sprite_vs =
|
|||
" texCoords1FS = texCoords1;\n"
|
||||
" colorFS = color;\n"
|
||||
" depthVS = -positionVS.z;\n"
|
||||
" proj22_32 = vec2(-projection[2][2], projection[3][2]);\n"
|
||||
"}\n";
|
||||
|
||||
static const char* sprite_fs =
|
||||
|
@ -492,17 +499,18 @@ static const char* sprite_fs =
|
|||
"uniform sampler2D texture2; // depth texture\n"
|
||||
"\n"
|
||||
"uniform uint alphaTest;\n"
|
||||
"uniform vec2 proj22_32;\n"
|
||||
"uniform vec3 addDistOffset;\n"
|
||||
"#define proj22 proj22_32.x\n"
|
||||
"#define proj32 proj22_32.y\n"
|
||||
"#define additive addDistOffset.x\n"
|
||||
"#define distance addDistOffset.y\n"
|
||||
"#define offset addDistOffset.z\n"
|
||||
"uniform vec2 distOffset;\n"
|
||||
"uniform vec4 colorScale;\n"
|
||||
"uniform vec4 colorBias;\n"
|
||||
"#define distance distOffset.x\n"
|
||||
"#define offset distOffset.y\n"
|
||||
"\n"
|
||||
"in vec2 texCoords1FS;\n"
|
||||
"in vec4 colorFS;\n"
|
||||
"in float depthVS;\n"
|
||||
"in vec2 proj22_32;\n"
|
||||
"#define proj22 proj22_32.x\n"
|
||||
"#define proj32 proj22_32.y\n"
|
||||
"\n"
|
||||
"out vec4 fragColor;\n"
|
||||
"\n"
|
||||
|
@ -530,11 +538,9 @@ static const char* sprite_fs =
|
|||
"\n"
|
||||
" float depthSRaw = texelFetch(texture2, ivec2(gl_FragCoord.xy), 0).r;\n"
|
||||
" float depthS = LinearDepth(depthSRaw * 2.0 - 1.0);\n"
|
||||
" float depthP = depthVS - offset * 0.5;\n"
|
||||
" float depthP = depthVS - offset;\n"
|
||||
" float scale = Contrast((depthS - depthP) * distance, 2.0);\n"
|
||||
" float scaleColor = max(scale, 1.0 - additive);\n"
|
||||
" float scaleAlpha = max(scale, additive);\n"
|
||||
" vec4 r2 = vec4(r.rgb * scaleColor, r.a * scaleAlpha);\n"
|
||||
" vec4 r2 = mix(r * colorScale + colorBias, r, scale);\n"
|
||||
" fragColor = r2;\n"
|
||||
"}\n";
|
||||
|
||||
|
@ -1134,6 +1140,12 @@ static void ApplyPipeline(PipelineId pipelineId)
|
|||
|
||||
if(pipelineId == PID_SOFT_SPRITE && gl.fbMSEnabled)
|
||||
{
|
||||
// This is not how it should be done and will counter the benefits of MSAA.
|
||||
// To do this right, we need to bind the FBO's depth attachment to the shader and for that,
|
||||
// we need multi-sampled textures as FBO attachments instead of multi-sampled render buffers.
|
||||
// We also need the shader to use gl_SampleID, which changes our minimum requirements.
|
||||
// Because of all these changes and lack of testing time,
|
||||
// I'll do the necessary changes after the 1.52 release to avoid problems.
|
||||
FBO_ResolveDepth();
|
||||
FBO_Bind();
|
||||
}
|
||||
|
@ -1918,8 +1930,9 @@ static void Init()
|
|||
gl.pipelines[PID_SOFT_SPRITE].uniformNames[SU_PROJECTION] = "projection";
|
||||
gl.pipelines[PID_SOFT_SPRITE].uniformNames[SU_CLIP_PLANE] = "clipPlane";
|
||||
gl.pipelines[PID_SOFT_SPRITE].uniformNames[SU_ALPHA_TEST] = "alphaTest";
|
||||
gl.pipelines[PID_SOFT_SPRITE].uniformNames[SU_PROJ22_32] = "proj22_32";
|
||||
gl.pipelines[PID_SOFT_SPRITE].uniformNames[SU_ADD_DIST_OFFSET] = "addDistOffset";
|
||||
gl.pipelines[PID_SOFT_SPRITE].uniformNames[SU_DIST_OFFSET] = "distOffset";
|
||||
gl.pipelines[PID_SOFT_SPRITE].uniformNames[SU_COLOR_SCALE] = "colorScale";
|
||||
gl.pipelines[PID_SOFT_SPRITE].uniformNames[SU_COLOR_BIAS] = "colorBias";
|
||||
|
||||
gl.pipelines[PID_POST_PROCESS].uniformNames[PU_BRIGHT_GAMMA_GREY] = "brightGammaGrey";
|
||||
|
||||
|
@ -1967,7 +1980,7 @@ static void Init()
|
|||
gl.errorMode = EM_FATAL;
|
||||
}
|
||||
|
||||
glInfo.softSpriteSupport = r_softSprites->integer == 1;
|
||||
glInfo.depthFadeSupport = r_depthFade->integer == 1;
|
||||
|
||||
gl.pipelineId = PID_COUNT;
|
||||
ApplyPipeline(PID_GENERIC);
|
||||
|
@ -2008,7 +2021,7 @@ static void InitGLInfo()
|
|||
glInfo.maxAnisotropy = 0;
|
||||
}
|
||||
|
||||
glInfo.softSpriteSupport = qfalse;
|
||||
glInfo.depthFadeSupport = qfalse;
|
||||
glInfo.mipGenSupport = qfalse;
|
||||
glInfo.alphaToCoverageSupport = qfalse;
|
||||
}
|
||||
|
@ -2269,14 +2282,13 @@ static void DrawDynamicLight()
|
|||
DrawElements(tess.dlNumIndexes);
|
||||
}
|
||||
|
||||
static void DrawSoftSprite()
|
||||
static void DrawDepthFade()
|
||||
{
|
||||
Pipeline* const pipeline = &gl.pipelines[PID_SOFT_SPRITE];
|
||||
|
||||
if(pipeline->uniformsDirty[SU_PROJECTION])
|
||||
{
|
||||
glUniformMatrix4fv(pipeline->uniformLocations[SU_PROJECTION], 1, GL_FALSE, gl.projectionMatrix);
|
||||
glUniform2f(pipeline->uniformLocations[SU_PROJ22_32], -gl.projectionMatrix[2 * 4 + 2], gl.projectionMatrix[3 * 4 + 2]);
|
||||
}
|
||||
if(pipeline->uniformsDirty[SU_MODELVIEW])
|
||||
{
|
||||
|
@ -2286,10 +2298,26 @@ static void DrawSoftSprite()
|
|||
{
|
||||
glUniform4fv(pipeline->uniformLocations[SU_CLIP_PLANE], 1, gl.clipPlane);
|
||||
}
|
||||
glUniform3f(pipeline->uniformLocations[SU_ADD_DIST_OFFSET],
|
||||
tess.shader->softSprite == SST_ADDITIVE ? 1.0f : 0.0f,
|
||||
tess.shader->softSpriteDistance,
|
||||
tess.shader->softSpriteOffset);
|
||||
if(pipeline->uniformsDirty[SU_COLOR_SCALE] ||
|
||||
memcmp(gl.depthFadeScale, r_depthFadeScale[tess.shader->dfType], sizeof(gl.depthFadeScale)) != 0)
|
||||
{
|
||||
glUniform4fv(pipeline->uniformLocations[SU_COLOR_SCALE], 1, r_depthFadeScale[tess.shader->dfType]);
|
||||
memcpy(gl.depthFadeScale, r_depthFadeScale[tess.shader->dfType], sizeof(gl.depthFadeScale));
|
||||
}
|
||||
if(pipeline->uniformsDirty[SU_COLOR_BIAS] ||
|
||||
memcmp(gl.depthFadeBias, r_depthFadeBias[tess.shader->dfType], sizeof(gl.depthFadeBias)) != 0)
|
||||
{
|
||||
glUniform4fv(pipeline->uniformLocations[SU_COLOR_BIAS], 1, r_depthFadeBias[tess.shader->dfType]);
|
||||
memcpy(gl.depthFadeBias, r_depthFadeBias[tess.shader->dfType], sizeof(gl.depthFadeBias));
|
||||
}
|
||||
if(pipeline->uniformsDirty[SU_DIST_OFFSET] ||
|
||||
tess.shader->dfInvDist != gl.depthFadeDist ||
|
||||
tess.shader->dfBias != gl.depthFadeOffset)
|
||||
{
|
||||
glUniform2f(pipeline->uniformLocations[SU_DIST_OFFSET], tess.shader->dfInvDist, tess.shader->dfBias);
|
||||
gl.depthFadeDist = tess.shader->dfInvDist;
|
||||
gl.depthFadeOffset = tess.shader->dfBias;
|
||||
}
|
||||
|
||||
UploadVertexArray(VB_POSITION, tess.xyz);
|
||||
|
||||
|
@ -2334,7 +2362,7 @@ static void GAL_Draw(drawType_t type)
|
|||
else if(type == DT_SOFT_SPRITE)
|
||||
{
|
||||
ApplyPipeline(PID_SOFT_SPRITE);
|
||||
DrawSoftSprite();
|
||||
DrawDepthFade();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,9 +140,9 @@ S_COLOR_VAL " T2 " S_COLOR_HELP "= Tent 2 (1/3 2/3, same as the CPU version)
|
|||
"While " S_COLOR_VAL "1.0 " S_COLOR_HELP "will match the game's original look,\n" \
|
||||
"higher values will better preserve contrast."
|
||||
|
||||
#define help_r_softSprites \
|
||||
"enables depth sprites\n" \
|
||||
"With it, sprites like blood, smoke, etc don't 'cut' through geometry sharply."
|
||||
#define help_r_depthFade \
|
||||
"enables depth fade rendering\n" \
|
||||
"With it, surfaces like blood, smoke, etc don't 'cut' through geometry sharply."
|
||||
|
||||
#define help_r_gpuMipGen \
|
||||
"enables GPU mip-map generation\n" \
|
||||
|
|
|
@ -64,7 +64,7 @@ cvar_t *r_lightmapGreyscale;
|
|||
cvar_t *r_novis;
|
||||
cvar_t *r_nocull;
|
||||
cvar_t *r_nocurves;
|
||||
cvar_t *r_softSprites;
|
||||
cvar_t *r_depthFade;
|
||||
cvar_t *r_gpuMipGen;
|
||||
cvar_t *r_alphaToCoverage;
|
||||
cvar_t *r_dither;
|
||||
|
@ -319,7 +319,7 @@ void GfxInfo_f( void )
|
|||
ri.Printf( PRINT_ALL, "Renderer: %s\n", glConfig.renderer_string );
|
||||
if ( glConfig.version_string[0] != '\0' )
|
||||
ri.Printf( PRINT_ALL, "OpenGL version: %s\n", glConfig.version_string );
|
||||
ri.Printf( PRINT_ALL, "Soft sprites : %s\n", glInfo.softSpriteSupport ? "ON" : "OFF" );
|
||||
ri.Printf( PRINT_ALL, "Depth fade : %s\n", glInfo.depthFadeSupport ? "ON" : "OFF" );
|
||||
ri.Printf( PRINT_ALL, "Alpha to coverage : %s\n", glInfo.alphaToCoverageSupport ? "ON" : "OFF" );
|
||||
ri.Printf( PRINT_ALL, "GPU mip-map generation: %s\n", glInfo.mipGenSupport ? "ON" : "OFF" );
|
||||
gal.PrintInfo();
|
||||
|
@ -382,7 +382,7 @@ static const cvarTableItem_t r_cvars[] =
|
|||
{ &r_fullbright, "r_fullbright", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_fullbright },
|
||||
{ &r_lightmap, "r_lightmap", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_lightmap },
|
||||
{ &r_lightmapGreyscale, "r_lightmapGreyscale", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "0", "1", "how monochrome the lightmap looks" },
|
||||
{ &r_softSprites, "r_softSprites", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_softSprites },
|
||||
{ &r_depthFade, "r_depthFade", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_depthFade },
|
||||
{ &r_gpuMipGen, "r_gpuMipGen", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_gpuMipGen },
|
||||
{ &r_alphaToCoverage, "r_alphaToCoverage", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_alphaToCoverage },
|
||||
{ &r_dither, "r_dither", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_dither },
|
||||
|
|
|
@ -357,10 +357,17 @@ typedef struct {
|
|||
} fogParms_t;
|
||||
|
||||
typedef enum {
|
||||
SST_NONE, // disabled
|
||||
SST_BLEND, // blend pass -> modulate alpha
|
||||
SST_ADDITIVE // additive pass -> modulate color
|
||||
} softSpriteType_t;
|
||||
DFT_NONE, // disabled
|
||||
DFT_BLEND, // std alpha blend -> fade color = (R G B 0)
|
||||
DFT_ADD, // additive -> fade color = (0 0 0 A)
|
||||
DFT_MULT, // multiplicative -> fade color = (1 1 1 A)
|
||||
DFT_PMA, // pre-mult alpha -> fade color = (0 0 0 0)
|
||||
DFT_TBD, // to be determined, i.e. fix up later
|
||||
DFT_COUNT
|
||||
} depthFadeType_t;
|
||||
|
||||
extern const float r_depthFadeScale[DFT_COUNT][4];
|
||||
extern const float r_depthFadeBias [DFT_COUNT][4];
|
||||
|
||||
|
||||
struct shader_t {
|
||||
|
@ -411,9 +418,10 @@ struct shader_t {
|
|||
vec2_t lmScale;
|
||||
vec2_t lmBias;
|
||||
|
||||
softSpriteType_t softSprite;
|
||||
float softSpriteDistance;
|
||||
float softSpriteOffset;
|
||||
// depth fade rendering settings
|
||||
depthFadeType_t dfType;
|
||||
float dfInvDist;
|
||||
float dfBias;
|
||||
|
||||
shader_t* next;
|
||||
};
|
||||
|
@ -1006,7 +1014,7 @@ extern cvar_t *r_transpSort; // transparency sorting mode
|
|||
extern cvar_t *r_lightmap; // render lightmaps only
|
||||
extern cvar_t *r_lightmapGreyscale; // how monochrome the lightmap looks
|
||||
extern cvar_t *r_fullbright; // avoid lightmap pass
|
||||
extern cvar_t *r_softSprites; // draws certain surfaces as depth particles
|
||||
extern cvar_t *r_depthFade; // fades marked shaders based on depth
|
||||
extern cvar_t *r_gpuMipGen; // uses GPU-side mip-map generation
|
||||
extern cvar_t *r_alphaToCoverage; // enables A2C on alpha-tested surfaces
|
||||
extern cvar_t *r_dither; // enables dithering
|
||||
|
@ -1256,7 +1264,7 @@ struct shaderCommands_t
|
|||
const shaderStage_t** xstages;
|
||||
|
||||
// when > 0, only soft sprites are allowed in this batch
|
||||
softSpriteType_t softSprite;
|
||||
depthFadeType_t depthFade;
|
||||
|
||||
// when qtrue, RB_EndSurface doesn't need to compute deforms, colors, texture coordinates
|
||||
qbool deformsPreApplied;
|
||||
|
@ -1629,7 +1637,7 @@ struct glinfo_t {
|
|||
// used by renderer
|
||||
int maxTextureSize;
|
||||
int maxAnisotropy;
|
||||
qbool softSpriteSupport;
|
||||
qbool depthFadeSupport;
|
||||
qbool mipGenSupport;
|
||||
qbool alphaToCoverageSupport;
|
||||
};
|
||||
|
|
|
@ -45,7 +45,7 @@ void RB_BeginSurface( const shader_t* shader, int fogNum )
|
|||
tess.shader = shader;
|
||||
tess.fogNum = fogNum;
|
||||
tess.xstages = (const shaderStage_t**)shader->stages;
|
||||
tess.softSprite = SST_NONE;
|
||||
tess.depthFade = DFT_NONE;
|
||||
tess.deformsPreApplied = qfalse;
|
||||
|
||||
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
|
||||
|
@ -121,7 +121,7 @@ static void RB_DrawDynamicLight()
|
|||
|
||||
static void RB_DrawGeneric()
|
||||
{
|
||||
if (tess.softSprite == SST_NONE && tess.fogNum && tess.shader->fogPass) {
|
||||
if (tess.depthFade == DFT_NONE && tess.fogNum && tess.shader->fogPass) {
|
||||
tess.drawFog = qtrue;
|
||||
|
||||
unsigned int fogStateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
|
||||
|
@ -142,7 +142,7 @@ static void RB_DrawGeneric()
|
|||
backEnd.pc[RB_BATCHES]++;
|
||||
backEnd.pc[RB_VERTICES] += tess.numVertexes;
|
||||
backEnd.pc[RB_INDICES] += tess.numIndexes;
|
||||
gal.Draw(tess.softSprite != SST_NONE ? DT_SOFT_SPRITE : DT_GENERIC);
|
||||
gal.Draw(tess.depthFade != DFT_NONE ? DT_SOFT_SPRITE : DT_GENERIC);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,6 +23,26 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
// tr_shader.c -- this file deals with the parsing and definition of shaders
|
||||
|
||||
const float r_depthFadeScale[DFT_COUNT][4] =
|
||||
{
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f }, // DFT_NONE
|
||||
{ 1.0f, 1.0f, 1.0f, 0.0f }, // DFT_BLEND
|
||||
{ 0.0f, 0.0f, 0.0f, 1.0f }, // DFT_ADD
|
||||
{ 0.0f, 0.0f, 0.0f, 1.0f }, // DFT_MULT
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f }, // DFT_PMA
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f } // DFT_TBD
|
||||
};
|
||||
|
||||
const float r_depthFadeBias[DFT_COUNT][4] =
|
||||
{
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f }, // DFT_NONE
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f }, // DFT_BLEND
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f }, // DFT_ADD
|
||||
{ 1.0f, 1.0f, 1.0f, 0.0f }, // DFT_MULT
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f }, // DFT_PMA
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f } // DFT_TBD
|
||||
};
|
||||
|
||||
static char* s_shaderText = 0;
|
||||
|
||||
// the shader is parsed into these global variables, then copied into
|
||||
|
@ -1265,6 +1285,36 @@ static void ParseSurfaceParm( const char** text )
|
|||
}
|
||||
|
||||
|
||||
// q3map_cnq3_depthFade <scale> <bias>
|
||||
|
||||
static void ParseDepthFade( const char** text )
|
||||
{
|
||||
const char* token = COM_ParseExt( text, qfalse );
|
||||
float scale;
|
||||
if ( token[0] == '\0' || sscanf( token, "%f", &scale ) != 1 || scale <= 0.0f ) {
|
||||
ri.Printf( PRINT_WARNING,
|
||||
"WARNING: invalid/missing depth fade scale argument '%s' in shader '%s'! "
|
||||
"Ignoring the directive completely.\n",
|
||||
token, shader.name );
|
||||
return;
|
||||
}
|
||||
|
||||
token = COM_ParseExt( text, qfalse );
|
||||
float bias;
|
||||
if ( token[0] == '\0' || sscanf( token, "%f", &bias ) != 1 ) {
|
||||
ri.Printf( PRINT_WARNING,
|
||||
"WARNING: invalid/missing depth fade bias argument '%s' in shader '%s'! "
|
||||
"Ignoring the directive completely.\n",
|
||||
token, shader.name );
|
||||
return;
|
||||
}
|
||||
|
||||
shader.dfType = DFT_TBD;
|
||||
shader.dfInvDist = 1.0f / scale;
|
||||
shader.dfBias = bias;
|
||||
}
|
||||
|
||||
|
||||
// the current text pointer is at the explicit text definition of the shader.
|
||||
// parse it into the global shader variable. later functions will optimize it.
|
||||
|
||||
|
@ -1330,6 +1380,10 @@ static qbool ParseShader( const char** text )
|
|||
shader.clampTime = atof(token);
|
||||
}
|
||||
}
|
||||
else if ( !Q_stricmp( token, "q3map_cnq3_depthFade" ) ) {
|
||||
ParseDepthFade( text );
|
||||
continue;
|
||||
}
|
||||
// skip stuff that only the q3map needs
|
||||
else if ( !Q_stricmpn( token, "q3map", 5 ) ) {
|
||||
SkipRestOfLine( text );
|
||||
|
@ -1866,15 +1920,17 @@ static void VertexLightingCollapse( void ) {
|
|||
}
|
||||
|
||||
|
||||
static qbool IsAdditiveBlend()
|
||||
static qbool IsAdditiveBlendDepthFade()
|
||||
{
|
||||
for (int i = 0; i < shader.numStages; ++i) {
|
||||
if (!stages[i].active)
|
||||
continue;
|
||||
|
||||
const int bits = stages[i].stateBits;
|
||||
if ((bits & GLS_SRCBLEND_BITS) != GLS_SRCBLEND_ONE ||
|
||||
(bits & GLS_DSTBLEND_BITS) != GLS_DSTBLEND_ONE ||
|
||||
const unsigned int bits = stages[i].stateBits;
|
||||
const unsigned int src = bits & GLS_SRCBLEND_BITS;
|
||||
const unsigned int dst = bits & GLS_DSTBLEND_BITS;
|
||||
if ((src != GLS_SRCBLEND_ONE && src != GLS_SRCBLEND_SRC_ALPHA && src != GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA) ||
|
||||
dst != GLS_DSTBLEND_ONE ||
|
||||
(bits & GLS_DEPTHMASK_TRUE) != 0)
|
||||
return qfalse;
|
||||
}
|
||||
|
@ -1883,15 +1939,17 @@ static qbool IsAdditiveBlend()
|
|||
}
|
||||
|
||||
|
||||
static qbool IsNormalBlend()
|
||||
static qbool IsNormalBlendDepthFade()
|
||||
{
|
||||
for (int i = 0; i < shader.numStages; ++i) {
|
||||
if (!stages[i].active)
|
||||
continue;
|
||||
|
||||
const int bits = stages[i].stateBits;
|
||||
if ((bits & GLS_SRCBLEND_BITS) != GLS_SRCBLEND_SRC_ALPHA ||
|
||||
(bits & GLS_DSTBLEND_BITS) != GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ||
|
||||
const unsigned int bits = stages[i].stateBits;
|
||||
const unsigned int src = bits & GLS_SRCBLEND_BITS;
|
||||
const unsigned int dst = bits & GLS_DSTBLEND_BITS;
|
||||
if (src != GLS_SRCBLEND_SRC_ALPHA ||
|
||||
dst != GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ||
|
||||
(bits & GLS_DEPTHMASK_TRUE) != 0)
|
||||
return qfalse;
|
||||
}
|
||||
|
@ -1900,7 +1958,46 @@ static qbool IsNormalBlend()
|
|||
}
|
||||
|
||||
|
||||
static void ProcessSoftSprite()
|
||||
static qbool IsMultiplicativeBlendDepthFade()
|
||||
{
|
||||
for (int i = 0; i < shader.numStages; ++i) {
|
||||
if (!stages[i].active)
|
||||
continue;
|
||||
|
||||
const unsigned int bits = stages[i].stateBits;
|
||||
const unsigned int src = bits & GLS_SRCBLEND_BITS;
|
||||
const unsigned int dst = bits & GLS_DSTBLEND_BITS;
|
||||
const qbool multA = src == GLS_SRCBLEND_DST_COLOR && dst == GLS_DSTBLEND_ZERO;
|
||||
const qbool multB = src == GLS_SRCBLEND_ZERO && dst == GLS_DSTBLEND_SRC_COLOR;
|
||||
if ((!multA && !multB) ||
|
||||
(bits & GLS_DEPTHMASK_TRUE) != 0)
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
|
||||
static qbool IsPreMultAlphaBlendDepthFade()
|
||||
{
|
||||
for (int i = 0; i < shader.numStages; ++i) {
|
||||
if (!stages[i].active)
|
||||
continue;
|
||||
|
||||
const unsigned int bits = stages[i].stateBits;
|
||||
const unsigned int src = bits & GLS_SRCBLEND_BITS;
|
||||
const unsigned int dst = bits & GLS_DSTBLEND_BITS;
|
||||
if (src != GLS_SRCBLEND_ONE ||
|
||||
dst != GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ||
|
||||
(bits & GLS_DEPTHMASK_TRUE) != 0)
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
|
||||
static void ProcessDepthFade()
|
||||
{
|
||||
struct ssShader {
|
||||
const char* name;
|
||||
|
@ -1935,9 +2032,10 @@ static void ProcessSoftSprite()
|
|||
{ "shotgunSmokePuffNPM", 8.0f }
|
||||
};
|
||||
|
||||
shader.softSprite = SST_NONE;
|
||||
const qbool shaderEnabled = shader.dfType == DFT_TBD;
|
||||
shader.dfType = DFT_NONE;
|
||||
|
||||
if (!glInfo.softSpriteSupport)
|
||||
if (!glInfo.depthFadeSupport)
|
||||
return;
|
||||
|
||||
if (shader.sort <= SS_OPAQUE)
|
||||
|
@ -1952,22 +2050,28 @@ static void ProcessSoftSprite()
|
|||
if (activeStages <= 0)
|
||||
return;
|
||||
|
||||
if (!shaderEnabled) {
|
||||
qbool found = qfalse;
|
||||
for (int i = 0; i < ARRAY_LEN(ssShaders); ++i) {
|
||||
if (!Q_stricmp(shader.name, ssShaders[i].name)) {
|
||||
shader.softSpriteDistance = 1.0f / ssShaders[i].distance;
|
||||
shader.softSpriteOffset = ssShaders[i].offset;
|
||||
shader.dfInvDist = 1.0f / ssShaders[i].distance;
|
||||
shader.dfBias = ssShaders[i].offset;
|
||||
found = qtrue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsAdditiveBlend())
|
||||
shader.softSprite = SST_ADDITIVE;
|
||||
else if (IsNormalBlend())
|
||||
shader.softSprite = SST_BLEND;
|
||||
if (IsAdditiveBlendDepthFade())
|
||||
shader.dfType = DFT_ADD;
|
||||
else if (IsNormalBlendDepthFade())
|
||||
shader.dfType = DFT_BLEND;
|
||||
else if (IsMultiplicativeBlendDepthFade())
|
||||
shader.dfType = DFT_MULT;
|
||||
else if (IsPreMultAlphaBlendDepthFade())
|
||||
shader.dfType = DFT_PMA;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2192,7 +2296,7 @@ static shader_t* FinishShader()
|
|||
shader.sort = SS_FOG;
|
||||
}
|
||||
|
||||
ProcessSoftSprite();
|
||||
ProcessDepthFade();
|
||||
|
||||
return GeneratePermanentShader();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue