Perspective division fun (ATI R200 specific?)

I’ve recently stumbled upon an extension document that contains some bits and pieces about a pedestrian approach to perspective correct texture mapping.

If we get screen coordinate inputs then in order to perspectively
correct data (eg texture), the input data currently has to be
specified in one of the following manners

  1. Specify all the data normally
    eg.
    glTexture2T(s, t);
    and the coordinates as
    glVertex4T(xw, yw, z*w, w);
    or
  2. Divide each data by w
    eg.
    glTexture4T(s/w, t/w, r/w, q/w);
    and the coordinates as
    glVertex3T(x, y, z);

I’ve been using approach number one for quite some time (for my emulation stuff).
I’ve got identity matrices on modelview, projection and texture stacks, nothing that could get in the way really. I submit 4d vertices with explicit w and xyz components premulted by w. This w value is determined by the needs of the texture unit rather than anything else, as incoming vertices are already projected to screen coordinates. Submitted texture coords are plain 2d actually, but for making this comparison I’ve extended them to 4d with z=0.0, w=1.0.

The results of this method look like this:

Approach number two looks a lot cleaner, is friendlier towards multitexturing (which can have different w per texture) and would really help avoiding z artifacts in multipass rendering (exact same z -> no fighting).
I’m also atm not concerned about color interpolation and the like, just the textures. So I implemented it. The only difference is this snippet, carried out per vertex:

float w=1.0f/oow;    //one over w. like in 1/w

dest->cx*=w;	dest->cy*=w;	dest->cz*=w;	dest->cw*=w;
dest->tx0*=w;	dest->ty0*=w;	dest->tz0*=w;	dest->tw0*=w;

This ends up producing vertices where coordinate w is always 1.0.

Hah, works well in theory, but here’s the result:

This is an extreme example, most of the time it almost works. But I really don’t know how to improve that.

Looks like I’m losing too precision somewhere …
Well, at least in theory the parameters ending up in the texture sampler should be exactly the same.

So, what can I do?

Sorry, img tags are disabled here. Edit is hosed up (would lose most of the post), so here are the links again:
Correct image

Broken image

[This message has been edited by zeckensack (edited 12-04-2002).]

Ahem. Missing info here:
Renderer: Radeon 8500 DDR x86/MMX/3DNow!/SSE
Version: 1.3.3413 Win9x Release

Which means it’s the official 9069 driver set (aka Catalyst 2.4), shipping default settings, Windows 98SE.

Ho humm …

im sure u know this but ill post anyways (perhaps i didnt understand) youre trying to do persective corrected texturemapping?

there is a hint GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST (or somethig)
on new nvidia drivers u CANT turn it off, im not sure about the radeon

Yes, I’ve tried the hint, but it doesn’t change anything.

However, I’ve already made some progress. The 1/w values I get are anywhere between 1/65535 and 1.
Apparently the lower end of that range is too small when passed inside a texture coord (again, later down the pipeline both methods should for all means and purposes be identical).

I’ve experimented with scaling all my coordinates with a constant value. Ie all geometry components including w and all texture coordinate components, also including w. I ended up with pretty good results at a scale factor of 256.

It looks the same, as dictated by theory. GL divides geo coords by w automatically, as it does to tex coords. The texture sampling texel/pixel ratio is controlled by a combination of geometry w and texture coord w. Ugh.
Anyway, looks like a precision issue and my original problem may be regarded as fixed.

I’m still curios why this precision issue even crops up.

Anyone care to explain why these two aren’t equivalent?
1)//good
texcoords(4,4,0,1);
vertex(25.6,0,0,256);

2)//bad
texcoords(4/256,4/256,0,1/256);
vertex(0.1,0,0,1);

(floating point notation has been skipped for brevity but is of course present in my ‘problem code’)

[This message has been edited by zeckensack (edited 12-04-2002).]

[This message has been edited by zeckensack (edited 12-04-2002).]

'cauz the vertices are transformed first and then the division is done?

my 2 €-cent

rapso->greets();

Originally posted by rapso:
[b]'cauz the vertices are transformed first and then the division is done?

my 2 €-cent

rapso->greets();[/b]
Nope. There’s no such thing as transformation in that setup. Modelview, projection and texture matrices are all set to identity

[This message has been edited by zeckensack (edited 12-05-2002).]

>>>>>>
Anyone care to explain why these two aren’t equivalent?
1)//good
texcoords(4,4,0,1);
vertex(25.6,0,0,256);

2)//bad
texcoords(4/256,4/256,0,1/256);
vertex(0.1,0,0,1);
<<<<<

texcoord(4, 4, 0, 1/256);
vertex(0.1,0,0,1);

is equivalent. Are you sure you are properly calculating w? Or maybe your q coordinated is screwed up somewhere.

V-man

Originally posted by V-man:
texcoord(4, 4, 0, 1/256);
vertex(0.1,0,0,1);

is equivalent. Are you sure you are properly calculating w? Or maybe your q coordinated is screwed up somewhere.

V-man[/b]
No offense, but you’re wrong.

Any two vertices of the form
texcoords(sa,ta,ra,qa)
vertex(xa,ya,za,wa)
(where a is any number, w, 1/w, q, 1/q, pi, 17 or …)
are equivalent down to texture mipmap selection and filtering.
Ie you can arbitrarily scale scale one component of either coords or texcoords, as long as you then scale all other components by the same value, the screen space result is the same. In theory at least.

It just so happens that I approach the limits of numerical precision with small values. Vertex positions are still fine, but texture lookup starts to break. Which is strange, given the ‘floatish’ nature of texcoords.

This has been tried with basic GL functions and with ATI_fragment_shader (glSampleMapATI(blablabla,GL_SWIZZLE_STQ_DQ_ATI,blabla); ). Same results.

[This message has been edited by zeckensack (edited 12-06-2002).]

Zeckensack,

As long as “a” is the same for each vertex of a primitive, “a” can be anything you like. In fact you could have:

texcoord(sb, tb, rb, qb);
vertex(xa, ya, za, wa);

Where “b” can be any number too.

If “a” or “b” varies over a primitive, it will change how the interpolation works.

Thanks -
Cass

Thanks for the input cass.

I’m aware that differing resultant q and/or w will change interpolation. My take on the issue is that q/w is relevant for texture filtering params and w controls colors and fog coord and the like.

In fact I want different q/w (the slash means ‘division’ here, not ‘or’) over primitives, that’s how perspective correct texture mapping works after all.

The issue at hand was getting away from varying w and constant q=1.0f (which due to finite precision perspective divide leads to varying x,y,z when multipassing with different q) to constant w=1.0f and varying q.

I’ll try what you said about seperate scale factors of vertex and texture coordinates.