Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
Urthar

GZDoom Hardware Shader

Recommended Posts

So I've been messing around with a hardware shader to recreate the Quake sky effect, but I've run into a problem with these black lines at the edges of the texture:



This is a JPEG of the base texture, the white is actually zero alpha in the PNG:



And this is the shader I wrote:

uniform float timer;

vec4 Process(vec4 color)
{
// get uv coordinates
vec2 uppersky = gl_TexCoord[0].st;
vec2 lowersky = gl_TexCoord[0].st;

// scroll upper sky
uppersky.x += timer * 0.1;
uppersky.y += timer * 0.1;

// uppersky is left half of texture
uppersky.x = (uppersky.x - floor(uppersky.x)) / 2.0;
uppersky.y = (uppersky.y - floor(uppersky.y));

// scroll lowersky
lowersky.x += timer * 0.2;
lowersky.y += timer * 0.2;

// lowersky is right half of texture
lowersky.x = ((lowersky.x - floor(lowersky.x)) + 1.0) / 2.0;
lowersky.y = (lowersky.y - floor(lowersky.y));

// get texel for updated uv coordinates
vec4 lowerskyTexel = getTexel(lowersky);
vec4 upperskyTexel = getTexel(uppersky);

// Draw either the lowersky, or the uppersky
if(lowerskyTexel.a > 0)
return lowerskyTexel * color;
else
return upperskyTexel * color;
}

Any ideas on how to get rid of the black lines?

Share this post


Link to post

You have to account for texture filtering so both halves need some space to wrap around.

My suggestion would be to make the texture twice as wide with both halves repeating once and then only use the middle parts of both halves.

Share this post


Link to post

Yeah anisotropic filtering seemed to be the main culprit. The effect disappered when I switched it off:



With 'max' filtering, I got additional horizontal black lines, and a nasty alpha blend:



Thanks for the quick advice, I'll try tiling the texure within a border, and see if I can get a more robust result.

Share this post


Link to post

I put a 32 pixel wide border around each sky, creating a 384x192 texture, but still encountered some artifacts:



No filtering and Linear filtering worked ok:



No filtering with Nearest and Linear mip produced some artifacts:



Likewise Bilinear and Trilinear filtering:



Anisotropic produced increasing artifacts at higher levels, this image is at 16:



The HQ Resize option, seemed to work fine with Scale4x, but HQ4x produced minor alpha blending artifacts.

Share this post


Link to post
fabian said:

Cool, how does it look in motion?


The scrolling itself works fine. I made a little 256 radius hemipshere and placed a Skybox Viewpoint in it to mimic Quake's distortion effect.

Share this post


Link to post
Urthar said:

I put a 32 pixel wide border around each sky, creating a 384x192 texture, but still encountered some artifacts:

You could try to tile the original textures into the borders (and change the shader to not touch the borders. Or something like that.

Share this post


Link to post
Urthar said:

No filtering and Linear filtering worked ok:


damn this looks cool. These are stock quake textures? I should really give that game another chance

Share this post


Link to post
Urthar said:

I put a 32 pixel wide border around each sky, creating a 384x192 texture, but still encountered some artifacts:


Are you sure you properly changed the texture coordinate calculations for the altered texture? You have to make sure that yo never get to the borders in the x-direction because that's where the transparent pixels get accessed creating these artifacts.

Share this post


Link to post

Yeah, updated the shader:

uniform float timer;

vec4 Process(vec4 color)
{
// get uv coordinates
vec2 uppersky = gl_TexCoord[0].st;
vec2 lowersky = gl_TexCoord[0].st;

// scroll upper sky
uppersky.x += timer * 0.05;
uppersky.y += timer * 0.05;

// uppersky is left half of texture
uppersky.x = ((uppersky.x - floor(uppersky.x)) / 3.0) + (1.0 / 12.0);
uppersky.y = ((uppersky.y - floor(uppersky.y)) / 1.5) + (1.0 / 6.0);

// scroll lowersky
lowersky.x += timer * 0.1;
lowersky.y += timer * 0.1;

// lowersky is right half of texture
lowersky.x = ((lowersky.x - floor(lowersky.x)) / 3.0) + (7.0 / 12.0);
lowersky.y = ((lowersky.y - floor(lowersky.y)) / 1.5) + (1.0 / 6.0);

// get texel for updated uv coordinates
vec4 lowerskyTexel = getTexel(lowersky);
vec4 upperskyTexel = getTexel(uppersky);

// Draw either the lowersky, or the uppersky
if(lowerskyTexel.a > 0)
return lowerskyTexel * color;
else
return upperskyTexel * color;
}


The tiling itself basically works fine. I'll try a straight up 512x256 variant next and see if powers of 2 makes the difference.

Share this post


Link to post

I have no means to do quick tests but I believe that you somehow need to get the coordinate back into the [0..1] range after adding the timer.

You should also blend the colors if the alpha at the end is neither 0 nor 1 so that filtered edges of the upper texture get displayed correctly (use the 'mix' function for that.)

Share this post


Link to post
boris said:

You could try to tile the original textures into the borders (and change the shader to not touch the borders. Or something like that.


Yeah, that's basically what I did.

Ribbiks said:

damn this looks cool. These are stock quake textures? I should really give that game another chance


They are the stock textures converted to 32bit PNGs, with a few resizes to match q1tex.wad. GZDoom seems fine with non powers of 2 though, so I may switch back to the original texture sizes.

Share this post


Link to post
Urthar said:

GZDoom seems fine with non powers of 2 though.


All GL 2.x+ hardware can deal with arbitrary texture sizes, and anything older is no longer supported by the engine, so yes, it's fine to use any texture size you like.

Share this post


Link to post

Replacing the IF THEN statement with;

return color * mix(upperskyTexel, lowerskyTexel, lowerskyTexel.a);

didn't change any behaviour.

I noticed the texels themselves look ok, the black lines seem resolution dependant, at 1920x1080 they're barely visible single pixel wide lines.

Share this post


Link to post

That doesn't surprise me, that only affects the edges of the upper layer. Your real issue here is that at some point your texture coordinates reach the edges, you have to ensure they stay within the part of the texture that's ok to use.

Can you put it all together into a small demo project so I can check it myself?

Share this post


Link to post

Sure, I'll send you a PM with the link.

In the mean time, I'll try using a very low but non-zero alpha and see if I can force the PNG to store the background sky colour instead of black.

Share this post


Link to post

Looks a bit like what happens when you have a T-junction (to use the Quake term), e.g. geometry such as a rectangle on top and two squares underneath it and the polygon for the rectangle on top does not include the vertex shared between the two squares (when drawn), hence fragment drawing can produce gaps along that large edge. I think Nvidia cards are better at handling that situation than other brands.

Share this post


Link to post

With proper tiling and a 32 pixel border around each actual texture it should look something like this:



But you don't want to use the full texture, but only those parts:



So you'll have to change your shader to keep the texture coordinates inside the squares.

Share this post


Link to post

That's pretty much what I did Boris. (I ended up with a 64 pixel offset, but it's basically the same.)



Tried a 512x256 version with non-zero alpha. Good news is the alpha blending artifacts vanished, bad news is I have blue lines instead of black, so powers of 2 didn't make any difference.

Share this post


Link to post

This is a bit odd. On the second layer it was clearly visible that the black artifacts are not at the texture border but right in the middle, at texure coordinate 0.5.

Share this post


Link to post

That might be just to do with how I constructed the 512x256 (and the 384x192 had a similar offset)

Share this post


Link to post

Can the Hardware Shader access more than one texture at a time?

I don't really know, I just copied Boris's original SILVER4 shader and hacked it to get what I wanted. Speaking of which here's the updated shader I used for the 512x256.

uniform float timer;

vec4 Process(vec4 color)
{
// get uv coordinates
vec2 uppersky = gl_TexCoord[0].st;
vec2 lowersky = gl_TexCoord[0].st;

// scroll upper sky
uppersky.xy += timer * 0.05;

// uppersky is right half of texture
uppersky.x = ((uppersky.x - floor(uppersky.x)) * 0.25) + 0.625;
uppersky.y = ((uppersky.y - floor(uppersky.y)) * 0.5) + 0.25;

// scroll lowersky
lowersky.xy += timer * 0.1;

// lowersky is left half of texture
lowersky.x = ((lowersky.x - floor(lowersky.x)) * 0.25) + 0.125;
lowersky.y = ((lowersky.y - floor(lowersky.y)) * 0.5) + 0.25;

// get texel for updated uv coordinates
vec4 lowerskyTexel = getTexel(lowersky);
vec4 upperskyTexel = getTexel(uppersky);

// Mix lower and upper sky
return color * mix(upperskyTexel, lowerskyTexel, lowerskyTexel.a);
}

Share this post


Link to post
Urthar said:

Can the Hardware Shader access more than one texture at a time?



No, I have been working on that stuff but it got stalled due to lack of time.

Share this post


Link to post

It's a bit weird. I played around a bit, and even if I stay well away from any borders I still get black seams. Not what I was expecting.

[edit] I'm using a 384x192 texture, and the seam on the x-axis is every 384 pixels.

Share this post


Link to post

The only thing in here I can suspect is the (x-floor(x)) stuff. Who knows if it fails for certain values...?

Share this post


Link to post
andrewj said:

I think the shader is fine and the problem is how the engine handles geometry.



How that? A wall is a totally ordinary triangle fan. Absolutely nothing special about it. If this was geometry related the effect should look different.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×