Skip to content

Do not assume shaders without a stage is fog#1806

Merged
illwieckz merged 1 commit intomasterfrom
illwieckz/no-stage-shaders
Sep 25, 2025
Merged

Do not assume shaders without a stage is fog#1806
illwieckz merged 1 commit intomasterfrom
illwieckz/no-stage-shaders

Conversation

@illwieckz
Copy link
Copy Markdown
Member

  • tr_shader: do not ignore shaders without a stage, it's a valid use case for a transparent surface
  • tr_shader: do not assume shaders without a stage is fog

It makes possible to do this:

// The transparent texture that is also transparent in editor too.
// It should not be listed and selectable in editor. It can be used
// on model surfaces to hide them.
gfx/shared_colors/transparent
{
	qer_editorImage textures/shared_colors_src/transparent_d
	qer_trans 0

	surfaceparm nolightmap
	surfaceparm nomarks
	surfaceparm trans
}


gfx/shared_colors/transparent_nonsolid
{
	qer_editorImage textures/shared_colors_src/transparent_d
	qer_trans 0

	surfaceparm nolightmap
	surfaceparm nomarks
	surfaceparm nonsolid
	surfaceparm trans
}

- Do not assume shaders without a stage is fog.
- Do not ignore shaders without a stage, it's a valid use case for a transparent surface.
- Mark shaders without a stage as BLEND0.
@illwieckz
Copy link
Copy Markdown
Member Author

@slipher do you know if that can be rewritten without a stage? What that depthWrite keyword does here?

textures/common/portal
{
	qer_editorImage textures/common_src/portal_p

	surfaceparm nolightmap

	portal

	{
		map textures/shared_colors_src/transparent_d
		blendfunc GL_ONE GL_ONE_MINUS_SRC_ALPHA
		depthWrite
	}
}

@slipher
Copy link
Copy Markdown
Member

slipher commented Sep 16, 2025

@slipher do you know if that can be rewritten without a stage? What that depthWrite keyword does here?

That stage does do something: the depthWrite makes the surface "opaque" in the sense that nothing behind it is visible. So if used by itself this shader stage would create a hall of mirrors effect. (What portals do if r_clear and r_materialSystem are both off and the portal is not rendered.) But you could write the stage without using a transparent image, for example:

{
    map $white
    blendfunc GL_ZERO GL_ONE
    depthWrite
}

Similarly you could make an opaque black stage without actually needing a black image for example:

{
    map $white
    blendfunc GL_ZERO GL_ZERO
    // probably needs some more keywords to make sure it is writing depth and considered opaque
}

or alternatively

{
    map $white
    rgbgen const (0 0 0)
}

@illwieckz
Copy link
Copy Markdown
Member Author

illwieckz commented Sep 16, 2025

But you could write the stage without using a transparent image, for example:

{
    map $white
    blendfunc GL_ZERO GL_ONE
    depthWrite
}

OK, that's good enough. Thanks.

@illwieckz
Copy link
Copy Markdown
Member Author

Can it be done with $black instead?

@illwieckz
Copy link
Copy Markdown
Member Author

Can it be done with $black instead?

Well, it seems to behave the same.

@slipher
Copy link
Copy Markdown
Member

slipher commented Sep 16, 2025

If I'm not mistaken, the first commit would change the sort type from SS_FOG to SS_OPAQUE for an empty shader. SS_OPAQUE seems more wrong if anything, so I don't think this commit brings any benefit.

The second commit LGTM.

@illwieckz
Copy link
Copy Markdown
Member Author

With this branch the transparent shader is listed this way:

]/listShaders *transparent
--------------------------------------------------------------------------- 
num   regFlags shaderSort     stageType              stageNumber:shaderName 
--------------------------------------------------------------------------- 
2077  _____    OPAQUE         n/a                    -:gfx/shared_colors/transparent 
--------------------------------------------------------------------------- 
2078 total shaders, 0 total stages, largest shader has 0 stages 
--------------------------------------------------------------------------- 

Yes it's listed as OPAQUE, but there is no stage. Should we make it something else, like BLEND0?

What would be the drawback of being opaque while not having any stage? Is there some code that would not render behind or so?

@illwieckz
Copy link
Copy Markdown
Member Author

illwieckz commented Sep 16, 2025

So what I did is that such shader are now BLEND0, like they were when I used an explicit transparent image.

Before (master):

]/listShaders *transparent                
--------------------------------------------------------------------------- 
num   regFlags shaderSort     stageType              stageNumber:shaderName 
--------------------------------------------------------------------------- 
2077  _____    BLEND0         COLLAPSE_DIFFUSEMAP    0:gfx/shared_colors/transparent 
--------------------------------------------------------------------------- 
2078 total shaders, 1 total stages, largest shader has 1 stages 
--------------------------------------------------------------------------- 

After (this branch):

]/listShaders *transparent                
--------------------------------------------------------------------------- 
num   regFlags shaderSort     stageType              stageNumber:shaderName 
--------------------------------------------------------------------------- 
2077  _____    BLEND0         n/a                    -:gfx/shared_colors/transparent 
--------------------------------------------------------------------------- 
2078 total shaders, 0 total stages, largest shader has 0 stages 
--------------------------------------------------------------------------- 

{
// fogonly shaders don't have any stage passes
if ( numStages == 0 && !shader.isSky )
if ( shader.isFog && !shader.isSky )
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.

I think you could just remove this whole if statement and remove isFog. In the place where isFog is set, it already puts SS_FOG.

Copy link
Copy Markdown
Member Author

@illwieckz illwieckz Sep 17, 2025

Choose a reason for hiding this comment

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

Also fog shaders are supposed to have surfaceparm fog, so shader.contentFlags & CONTENTS_FOG.

@illwieckz
Copy link
Copy Markdown
Member Author

illwieckz commented Sep 17, 2025

Actually, there is a shader keyword that does what that PR first did before I set BLEND0: forceOpaque.

It made sure the shader was not disabled if there was no stage, and then the sorting was keeping the OPAQUE default I guess.

Is is used in no shader of no game I have grepped, it only exists in XreaL renderers like Dæmon and etlegacy renderer2.

@illwieckz
Copy link
Copy Markdown
Member Author

The forceOpaque shader keyword in some XreaL (the game PoC) shaders:

textures/common/caulk
{
	qer_editorimage textures/common/caulk.tga
	qer_trans 0.5
	
	noshadows
	forceOpaque			// will still seal levels
}
textures/skies/kat_q4dm3
{
//Grey variant of the CanyonFog_Sky
	qer_editorimage	gfx/env/kat_q4dm3_forward.tga
	noFragment
	forceOpaque
	noimpact
	noshadows
	{
		blend			blend			// so transparent windows can draw on top of it
		cameraCubeMap		gfx/env/kat_q4dm3
		texgen			skybox
	}
}

I don't know what it is for. But we don't need that to keep the shader when there is no stage, and we better set BLEND0.

@illwieckz illwieckz force-pushed the illwieckz/no-stage-shaders branch 2 times, most recently from 16cef91 to c3e37e0 Compare September 17, 2025 21:38
@slipher
Copy link
Copy Markdown
Member

slipher commented Sep 19, 2025

LGTM

@illwieckz illwieckz merged commit 87551a0 into master Sep 25, 2025
9 checks passed
@illwieckz illwieckz deleted the illwieckz/no-stage-shaders branch September 25, 2025 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants