Daemon icon indicating copy to clipboard operation
Daemon copied to clipboard

WIP: some steps to implement alphaGen portal

Open illwieckz opened this issue 1 year ago • 15 comments

I don't claim it is working, but we need this to make it work.

We can notice the current code computes the distance to portal in fragment shader, but ioq3 does it in vertex shader, and it's probably faster to do it once per vertex than once per pixel, but this is a good start.

I'm not sure the existing GLSL code is correct, but the GLSL code will not run without those patches anyway.

The ioq3 code also does the range compute in the generic shader and at some point we may want to do the same as there may be other needs for doing blend operations according to distance, but yet again, we can look small and do small steps after small steps.

illwieckz avatar Jan 08 '24 14:01 illwieckz

When I apply https://github.com/DaemonEngine/Daemon/pull/1019/ I see the portal map being blended with distance, though it is upside down and it is not blended over the portal but over itself, but this is promising.

At least the “fade with distance” compute is right or not totally wrong.

illwieckz avatar Jan 08 '24 15:01 illwieckz

When I apply #1019 I see the portal map being blended with distance, though it is upside down and it is not blended over the portal but over itself, but this is promising.

I think I've identified the issue there, hopefully should be fixed soon.

VReaperV avatar Jan 08 '24 19:01 VReaperV

I believe this is because of how we render portals now. The portal surfaces themselves are not rendered with the other surfaces, but alphagen portal uses Render_portal() which seems to be a really old function. I assume that's a relic of the fixed function pipeline where it had to be drawn in multiple passes. We can just pass the alphagen parameters and texture to the shader now and blend it there.

VReaperV avatar Jan 28 '24 15:01 VReaperV

Yeah, ioq3 apply alphaGen portal directly in generic_fp.glsl.

illwieckz avatar Jan 28 '24 17:01 illwieckz

We should too, we can use gl_FragDepth with a uniform passing in the alphagen value. Might need to get the linear depth since I assume that's what alphagen portal is supposed to use.

VReaperV avatar Jan 29 '24 14:01 VReaperV

You might need to add Tess_Begin() and rb_surfaceTable() or equivalent. I think the reason we're getting incorrect rendering here might be because the portals are rendered as follows:

  1. PreparePortalCommand
  2. DrawViewCommand
  3. FinalisePortalCommand

That last one does a Tess_Begin(), rb_surfaceTable() and a Tess_End(), while Render_portal() just does Tess_DrawElements(), which would then have incorrect data (presumably Render_portal() would be called after FinalisePortalCommand).

VReaperV avatar Feb 06 '24 12:02 VReaperV

Current state is:

  • image is displayed properly,
  • fading works, but fading to black instead of fading to portal render,
  • fading is done in reverse: image is seen when close and disappears when moving back, while the image should not be rendered when close and start appearing when moving back.

illwieckz avatar Jun 23 '24 15:06 illwieckz

  • fading works, but fading to black instead of fading to portal render,

Not sure what that means.

  • fading is done in reverse: image is seen when close and disappears when moving back, while the image should not be rendered when close and start appearing when moving back.

Isn't that the crrect behaviour? I'm pretty sure trem works like that too (it also just makes sense, what's the point of a portal that you can't really see?).

VReaperV avatar Jun 23 '24 16:06 VReaperV

You should see the portal surface (the scene from the camera) when close, but the fallback image when far, with the fallback image fading from transparent to opaque while increasing the distance. The idea is that the portal is only rendered when close with an image rendered instead when far.

illwieckz avatar Jun 23 '24 17:06 illwieckz

Oh, so it's just backwards, right? I think just changing color.rgb *= 1.0 - clamp(len, 0.0, 1.0); to color.rgb *= clamp(len, 0.0, 1.0); should fix it.

VReaperV avatar Jun 24 '24 15:06 VReaperV

OK, now two things are missing:

  • Once out of range, the surface turns full black instead of just rendering the image.
  • there is no blending to a portal surface, but to black.

illwieckz avatar Jun 24 '24 16:06 illwieckz

I also noticed that while it fades in the right direction, it doesn't really fade to black.

Example of test scene: map nova, viewpos 9459 3037 -21 59 3.

illwieckz avatar Jun 24 '24 16:06 illwieckz

I also noticed that while it fades in the right direction, it doesn't really fade to black.

It should be fading to an image though, rather than black?

VReaperV avatar Jun 24 '24 16:06 VReaperV

Incorrect might be because alpha channel is not set and/or because of the blend functions.

VReaperV avatar Jun 24 '24 16:06 VReaperV

It should be fading to an image though, rather than black?

It should be fading to the image from the distant camera.

I assume fading to black is expected when blending is not working yet.

illwieckz avatar Jun 24 '24 16:06 illwieckz

Blending is fixed now.

I also noticed that while it fades in the right direction, it doesn't really fade to black.

Example of test scene: map nova, viewpos 9459 3037 -21 59 3.

What you're seeing on nova is because the game doesn't render the portal at all from this position.

VReaperV avatar Jul 06 '24 10:07 VReaperV

This also happens on 0.54.1, so at least it's not a regression (or not a recent one).

VReaperV avatar Jul 06 '24 10:07 VReaperV

Blending is fixed now.

Excellent!

What you're seeing on nova is because the game doesn't render the portal at all from this position.

Yes. The expected behavior of such surface is that when the view position is out of range, the surface always renders the textures, so what should be disabled is not the whole material, but only the portal rendering, with the texture being displayed.

illwieckz avatar Jul 06 '24 20:07 illwieckz

Doing this “fixes” it:

diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp
index 061baee51..f19166508 100644
--- a/src/engine/renderer/tr_main.cpp
+++ b/src/engine/renderer/tr_main.cpp
@@ -1587,7 +1587,7 @@ static bool SurfBoxIsOffscreen(const drawSurf_t *drawSurf, screenRect_t& surfRec
 
 	if (shortest > (shader->portalRange * shader->portalRange))
 	{
-		return true;
+//		return true;
 	}
 
 	return false;
@@ -1741,7 +1741,7 @@ static bool SurfIsOffscreen( const drawSurf_t *drawSurf, screenRect_t& surfRect
 
 	if ( shortest > ( tess.surfaceShader->portalRange * tess.surfaceShader->portalRange ) )
 	{
-		return true;
+//		return true;
 	}
 
 	return false;

But this is wrong, it defeats the portalRange, meaning the portals are always rendered. What we need is to never disable the surface when out of range, but to disable the portal rendering when out of range.

illwieckz avatar Jul 06 '24 20:07 illwieckz

I tried doing this:

--- a/src/engine/renderer/tr_main.cpp
+++ b/src/engine/renderer/tr_main.cpp
@@ -1585,10 +1585,7 @@ static bool SurfBoxIsOffscreen(const drawSurf_t *drawSurf, screenRect_t& surfRec
 		return false;
 	}
 
-	if (shortest > (shader->portalRange * shader->portalRange))
-	{
-		return true;
-	}
+	shader->isPortalOutOfRange |= shortest > (shader->portalRange * shader->portalRange);
 
 	return false;
 }
@@ -1739,10 +1736,7 @@ static bool SurfIsOffscreen( const drawSurf_t *drawSurf, screenRect_t& surfRect
 		return false;
 	}
 
-	if ( shortest > ( tess.surfaceShader->portalRange * tess.surfaceShader->portalRange ) )
-	{
-		return true;
-	}
+	shader->isPortalOutOfRange |= shortest > ( tess.surfaceShader->portalRange * tess.surfaceShader->portalRange );
 
 	return false;
 }

Now I'm looking for a place to do:

if ( shader->isPortalOutOfRange  )
{
 	return;
}

To avoid rendering the related portal surface when out of range, but without disabling the surface itself.

illwieckz avatar Jul 06 '24 21:07 illwieckz

Now I'm looking for a place to do:

if ( shader->isPortalOutOfRange  )
{
 	return;
}

To avoid rendering the related portal surface when out of range, but without disabling the surface itself.

Perhaps in an else block here? https://github.com/DaemonEngine/Daemon/blob/e522be8b10f3c31a5218337a420d01c42795bf31/src/engine/renderer/tr_main.cpp#L2094-L2101

VReaperV avatar Jul 07 '24 20:07 VReaperV

This works now: unvanquished_2024-07-30_020034_000 unvanquished_2024-07-30_020040_000 unvanquished_2024-07-30_020049_000 unvanquished_2024-07-30_020054_000

VReaperV avatar Jul 29 '24 23:07 VReaperV

LGTM

slipher avatar Aug 01 '24 19:08 slipher