Author Topic: z fighting  (Read 17778 times)

0 Members and 1 Guest are viewing this topic.

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: z fighting
« Reply #20 on: March 21, 2012 »
Something I am interested in in the code you linked though is the mipmapping.

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: z fighting
« Reply #21 on: March 22, 2012 »
Something I am interested in in the code you linked though is the mipmapping.
To select a mipmap you need to calculate the distance of two texels in the horizontal and vertical direction.
The actual direction (horizontal, vertical or any other) doesn't really matter for the distance but since you're calculating deltau, deltav along the scanline anyway, it makes sense to use it.
But any 3d-artist will try to create uv-sets with as low distortion as possible anyway, so u & v will usually be almost perpendicular.
This means that the delta along the vertical direction is simply (deltav, -deltau).
So a reasonable approximation for an isotropic mipmap is
Code: [Select]
level = min( log2( abs(deltau) ), log2( abs(deltav) ) );For anisotropic mipmaps you "just" have to check which of the two directions actually corresponds to u and which to v.
Challenge Trophies Won:

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: z fighting
« Reply #22 on: March 22, 2012 »
A bit of a problem I see with just using the scanline deltas is thinking about a road with buildings along it, the road surface texture will be more compressed on the vertical while the face of the buildings will be more compressed on the horizontal so the level of mipmapping would differ for each.

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: z fighting
« Reply #23 on: March 22, 2012 »
A bit of a problem I see with just using the scanline deltas is thinking about a road with buildings along it, the road surface texture will be more compressed on the vertical while the face of the buildings will be more compressed on the horizontal so the level of mipmapping would differ for each.
Yes, that's true (and indeed a problem) but can't be helped with isotropic mipmaps (each mipmap is half the size in width *and* height), so you have to pick the map which fits best.
The only way around it are anisotropic mipmaps and here it makes perfectly sense to analyse the scalings individually.

Challenge Trophies Won:

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: z fighting
« Reply #24 on: March 22, 2012 »
I  maybe didn't explain that well, I know you get the smearing in these cases but what I was meaning was that in the case of the road and building, the 2 surfaces should be mipmapped to the same level but if you only use the scanline deltas you would get different levels for the road surface and the building face.

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: z fighting
« Reply #25 on: March 22, 2012 »
Sorry, but I'm still not getting the road and building thing...
Challenge Trophies Won:

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: z fighting
« Reply #26 on: March 22, 2012 »
ok, consider a textured floor, as the camera is raised/lowered the scanline deltas at a particular distance will remain the same but the vertical deltas will vary as the camera moves, if you base your mipmap selection on the scanline deltas then the mipmapping won't change. With the wall, if the camera moves sideways towards or away from the wall the vertical deltas will remain the same but the horizontal deltas will vary and will cause the mipmapping at a particular distance to change level.

I think if you only depend on the scanline deltas then the mipmapping will behave differently on vertical and horizontal surfaces.

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: z fighting
« Reply #27 on: March 22, 2012 »
But the textured floor has different deltas for each scanline anyway (so potentially a different mipmap in each line).
That's why it's the perfect example for anisotropic mipmaps and trilinear filtering.
Of course the assumption of orthogonal deltas doesn't really work here (and generally doesn't for steep viewing angles).
Still you have to pick one of your (isotropic) mipmaps and it can only fit one or the other direction.
So why shouldn't we prefer the horizontal case?
Challenge Trophies Won:

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: z fighting
« Reply #28 on: March 22, 2012 »
Say you have a square tunnel with the camera looking straight through it, it's all using the same texture at the same scale. Take a slice at 1 particular depth to give just a square outline of pixels.

on the floor and ceiling of the slice the scanline deltas are constant, if the camera is moved left/right/up/down the deltas don't change and the mipmapping remains constant.

on the walls however, if the camera is moved left/right the scanline deltas do change and so will the mipmapping.

Only using the scanline deltas will result in different behaviour of the mipmapping depending if it's on a wall or a floor.

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: z fighting
« Reply #29 on: March 22, 2012 »
Yes, you are perfectly right: You need to look at both gradients (eg. horizontal and vertical).
However, depending on the orientation of the polygon, one gradient will have a significantly bigger step-size than the other one.
(That's for steep angles when both gradients are not approx. orthonormal)
So which mipmap do you take? The larger, the smaller, one in the middle?
You can only match both gradients with anisotropic mipmaps (aka ripmaps).
That's fine if you can pick a single ripmap for the whole triangle but awful lot of extra trouble when constantly recalculating linear deltas in a perspective corrected texture mapper.

One approach to handle this properly would be to split your triangle in the screen-space into eg. 8x8 blocks and interpolate uv bilinearly (instead of subdividing each scanline separately as you woul'd with the usual perspective correction approach).

edit: Oh, I just realized I already suggested that 3 years ago :)
« Last Edit: March 22, 2012 by hellfire »
Challenge Trophies Won:

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: z fighting
« Reply #30 on: March 23, 2012 »
Haha, yep. I've just dug out the old comp to get some of that stuff off it and I'm looking at the ripmapping I'd been messing around with before.
Using some of your ideas from mipmapping I'm getting somewhere with the ripmapping, re calculating everything per pixel atm.

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: z fighting
« Reply #31 on: March 23, 2012 »
I think I've got it woking quite well with the ripmaps now. This has to be done to find the map for each pixel atm.
Code: [Select]
//get most significant deltas
float h_du=fabs(scan.du*zz);
float h_dv=fabs(scan.dv*zz);
float v_du=fabs((edge.du)-scan.du*edge.dx)*zz;
float v_dv=fabs((edge.dv)-scan.dv*edge.dx)*zz;
if (v_du>h_du)h_du=v_du;
if (v_dv>h_dv)h_dv=v_dv;

//log2 of deltas
int ulog=(((*(int*)&h_du)>>23)-136);
int vlog=(((*(int*)&h_dv)>>23)-136);
if (ulog<0)ulog=0;
if (vlog<0)vlog=0;

//search for ripmap
int ripu=ulog,ripv=vlog;
image_struct *t2=tex;
while((ripv>0)&&(t2->ripmap_v!=0)){t2=t2->ripmap_v;ripv-=1;}
while((ripu>0)&&(t2->ripmap_u!=0)){t2=t2->ripmap_u;ripu-=1;}

//adjust values for shifting u and v values
vlog-=ripv;
ulog-=ripu;
I've not looked into optimizing much yet but I'm thinking using some indexing for looking up the map would help and also wondering if I can calculate the indices at each vertex and then interpolate them.
Thanks for some insight into this.

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: z fighting
« Reply #32 on: March 23, 2012 »
Code: [Select]
//get most significant deltas
if (v_du>h_du)h_du=v_du;
if (v_dv>h_dv)h_dv=v_dv;
It's a little bit more complicated than just picking the maximum.

Imaging a textured square without any rotation:
The horizontal uv-delta is for example (2.0, 0.0)
And the vertical delta is (0.0, 2.0).
So you'd use the 2nd mipmap level.

And if you rotate the square by 45 degree:
horizontal delta: (1.41, 1.41)
vertical delta: (-1.41, 1.41)
Here you'd use the 1st mipmap level...
Challenge Trophies Won:

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: z fighting
« Reply #33 on: March 23, 2012 »
Yep, I'm still trying to figure out how to deal with that.
As it is though there are some visible bugs but it's a huge improvement.

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: z fighting
« Reply #34 on: March 24, 2012 »
I just revisited my mipmap code (still from the last millenium) and used a dummy texture to visualize the different mipmap levels:

(using the minimum deltau,deltav for the horizontal and vertical gradients per pixel)

I think it's quite possible to figure out where a mip-level change will happen and subdivide the scanline accordingly so you're using just a single map in the inner-loop of the poly-filler.
At the moment I'm not quite sure about trilinear filtering, though.
I always thought it's just blending linearly between two mipmap levels but looking at the picture it should filter between a 2x2 set of maps...

« Last Edit: March 25, 2012 by hellfire »
Challenge Trophies Won:

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: z fighting
« Reply #35 on: March 26, 2012 »
do you mean 2x2 over the whole poly or per pixel?

A problem I'd thought of before was when trying to take samples from 2 ripmaps, I can get u and v with the fraction for bilinear filtering on both but I'd have 2 different weights for blending those results together.