Dark Bit Factory & Gravity

PROGRAMMING => General coding questions => Topic started by: Stonemonkey on August 22, 2007

Title: Filtering method I've been trying.
Post by: Stonemonkey on August 22, 2007
Since this has made such a big difference to the quality of my renders I thought I'd describe how it works, it's not particularly complicated or difficult but can be a little expensive as it uses 4 texture lookups for each pixel filled.

The attatched image shows the difference in close up, perhaps not the best way to show it off as it can get a bit blurred when the texel-pixel ratio is so low.

Normally (without this) when calculating U and V then converting to integer you get you get coordinates that point to a particular texel on your texture map and you fill your pixel with that (maybe with some shading)  but the boundaries between the texels can show up and can result in steps on what should be straight lines on the textured surface.

To get round this the method I've come up with is quite simple, multiply the U and V values by 256.0 before interpolation (I use floats for interpolation so shifting is no use for me).
When it comes to filling a pixel and it's passed the z test I do the perspective correction and convert the values to integers, these values are now 256.0 times what they should be for looking up the texture (they have an extra 8 bits of accuracy each) so:

Code: [Select]
blend_u=texture_u and &hff
blend_v=texture_v and &hff
texture_u=(texture_u shr 8) And (texture->wwidth-1)
texture_v=(texture_v shr 8) And (texture->height-1)

blend_u and blend v now contain the fractional part of how far between the texels your coords are pointing and texture_u and texture_v contain top left texel of the 4 texels they point to.

Now it's just a matter of reading the 4 texels:

Code: [Select]
argb0=texture( texture_u , texture_v )
argb1=texture( (texture_u+1) And (texture->wwidth-1) , texture_v )
argb2=texture( texture_u , (texture_v+1) And (texture->height-1) )
argb3=texture( (texture_u+1) And (texture->wwidth-1) , (texture_v+1) And (texture->height-1) )

taking care to deal with the texture wrapping.

and blending (using a blend like alpha) those 4 colours using the blend values you took from the low 8 bits of the U/V values, first blending the top two colours (argb0 and argb1) together using blend_u and the bottom two colours (argb2 and argb3) together also using blend_u and finally blend the results of those 2 blends together using blend_v giving you your final colour ready for shading and writing to the colour buffer.

It works best when the pixel-texel ration is close to 1, too far either way it'll become pixelly again or blurry so some sort of mipmapping is also needed although atm mine still needs some work.
Title: Re: Filtering method I've been trying.
Post by: Stonemonkey on August 22, 2007
And for anyone interested, here's what I've come up with for fullscreen antialiasing, it takes a buffer 1.5*1.5 times the size of the display and shrinks it down. A lot less pixels to fill than 2*AA (just over half) but still an improvement on not using anything.

Code: [Select]
void shrink_by_3_to_2(int *source_i,int *target_i)
{
image_struct *source=(image_struct*)source_i;
image_struct *target=(image_struct*)target_i;
int *src=(int*)source->argb,w=source->wwidth;
int *dst=(int*)target->argb;
unsigned int a0,a1,a2,a3,a4,a5,a6,a7,a8;
int xcount;
int ycount=target->height;
while(ycount>0)
{
xcount=target->wwidth;
while(xcount>0)
{

a0=*src<<2;
a1=*(src+1)<<1;
a2=*(src+2)<<2;
a3=*(src+w)<<1;
a4=*(src+w+1);
a5=*(src+w+2)<<1;
a6=*(src+(w<<1))<<2;
a7=*(src+(w<<1)+1)<<1;
a8=*(src+(w<<1)+2)<<2;

*dst=(((((a0&0x3fc03fc)+(a1&0x1fe01fe)+(a3&0x1fe01fe)+(a4&0xff00ff))*28)&0xff00ff00)|
                      ((((a0&0x003fc00)+(a1&0x001fe00)+(a3&0x001fe00)+(a4&0x00ff00))*28)&0x00ff0000))>>8;

*(dst+1)=(((((a2&0x3fc03fc)+(a1&0x1fe01fe)+(a5&0x1fe01fe)+(a4&0xff00ff))*28)&0xff00ff00)|
               ((((a2&0x003fc00)+(a1&0x001fe00)+(a5&0x001fe00)+(a4&0x00ff00))*28)&0x00ff0000))>>8;

*(dst+target->wwidth)=(((((a6&0x3fc03fc)+(a7&0x1fe01fe)+(a3&0x1fe01fe)+(a4&0xff00ff))*28)&0xff00ff00)|
        ((((a6&0x003fc00)+(a7&0x001fe00)+(a3&0x001fe00)+(a4&0x00ff00))*28)&0x00ff0000))>>8;

*(dst+target->wwidth+1)=(((((a8&0x3fc03fc)+(a7&0x1fe01fe)+(a5&0x1fe01fe)+(a4&0xff00ff))*28)&0xff00ff00)|
            ((((a8&0x003fc00)+(a7&0x001fe00)+(a5&0x001fe00)+(a4&0x00ff00))*28)&0x00ff0000))>>8;

src+=3;
dst+=2;
xcount-=2;
}
src+=w<<1;
dst+=target->wwidth;
ycount-=2;
}
}
Title: Re: Filtering method I've been trying.
Post by: Jim on August 23, 2007
 :goodpost:
Massive karma points for sharing that code. :)

Jim
Title: Re: Filtering method I've been trying.
Post by: Rbz on August 23, 2007
Really good  :goodpost:
k++
Title: Re: Filtering method I've been trying.
Post by: Stonemonkey on August 23, 2007
Thanks, I was really surprised at how simple the filtering is. I've not tried this yet but here's a link showing how the blending could be done using something like the way I already do my shading but a bit more:

http://www.stereopsis.com/doubleblend.html
Title: Re: Filtering method I've been trying.
Post by: ninogenio on August 23, 2007
very cool fryer!

is this similar to gausian and alpha blurring on the texture map cause here is a link i used in the past and it seems to do similar but with only 3 texture lookups.

http://www.codeproject.com/vb/net/GausianBlur.asp
Title: Re: Filtering method I've been trying.
Post by: Stonemonkey on August 23, 2007
Not exactly nino but thanks for that, if the texture coordinates land exactly on the texel the blurring is such that it would have no effect, the higher the fractional part (closer to 1) the more the blurring is biased towards the colour of the next texel.

More like taking a texture and making another texture 256*256 times bigger and interpolating all the colours in between the texels from the original.

Another use although very similar would be for scaled/rotated sprites, I think that would look very good done with this.
Title: Re: Filtering method I've been trying.
Post by: ninogenio on August 23, 2007
ahh  :inspired: i get it!

cool cheers for the explanation/tutorial mate.
Title: Re: Filtering method I've been trying.
Post by: Stonemonkey on August 23, 2007
Quote
More like taking a texture and making another texture 256*256 times bigger and interpolating all the colours in between the texels from the original.

Except that each texel doesn't take up 256k
Title: Re: Filtering method I've been trying.
Post by: Tetra on August 25, 2007
great explination, thanks for sharing Fryer :)
Title: Re: Filtering method I've been trying.
Post by: ferris on September 04, 2007
Haha nice :)

K++