Large clipping plane corrupts Direct3D? (w/ screenshot)

Started by
36 comments, last by CGameProgrammer 20 years, 1 month ago
quote:Original post by Ysaneya
I didn''t see any corruption on my Radeon 9700. I flied to a few stars, they appeared as tesselated spheres, and never saw any problem even after staying up to 1 minute in front of them.

Actually, and this is telling, I had to fly (with ''9'' speed) around the galaxy for a little bit before settling down somewhere and seeing the errors. Merely staying somewhere and letting it run doesn''t do any harm, but then again, the vertices are not being created every frame, they''re only created when the detail level changes (or they become too far away to see). Try another run-through... I''d be surprised if a 9700 had much different results than my 9600.

quote:Charles, are you sure you really don''t see anything ?

Well, since I had errors (eventually), it makes sense different errors could happen too. The only way he''d not see the stars is if his monitor brightness is very low, because there''s plenty of them in all directions.

quote:It''s funny how everybody is working on a planet/space engine nowadays (well, not *everybody* but still.. )

Yeah, I remember yours (#1) (#2).

~CGameProgrammer( );

Screenshots of your games or desktop captures -- Upload up to four 1600x1200 screenshots of your projects, registration optional. View all existing ones in the archives..
~CGameProgrammer( );Developer Image Exchange -- New Features: Upload screenshots of your games (size is unlimited) and upload the game itself (up to 10MB). Free. No registration needed.
Advertisement
A Real-Time Procedural Universe, Part Three: Matters of Scale


When you are near that star, what are the coordinates you use for the sphere''s center? If they are not relative to the camera position, this may be what''s causing the problem (coordinates so large that they kill the precision).

Michael K.,
Co-designer and Graphics Programmer of "The Keepers"


We come in peace... surrender or die!
Michael K.
quote:
Actually, and this is telling, I had to fly (with ''9'' speed) around the galaxy for a little bit before settling down somewhere and seeing the errors.


Oh, now i see, you''re right, i didn''t travel far enough. I tried to fly at 9 speed for a while, and when zooming on a star i got the issues you described.

I faced the same problem in my own engine (on a smaller scale, since i''m using the kilometer unit), and it''s actually coming from a lack of precision with internal matrix calculations as everything is done on floats. For example, an offset of 1 centimeter at a distance of 1 kilometer from the origin will have a far lower error than an offset of 1 centimeter at a distance of one parsec.

The way to fix it (which i think is described in the gamasutra article, but don''t quote me, i don''t remember exactly) is to ban "huge" numbers in your matrices, especially huge translations. I''ve only implemented that system at the planet level in my new engine, but the principle should be the same at the universe level. The idea is similar to a skybox; you should generate your geometry in local space; always set your camera at origin (0, 0, 0); and set the world matrix (and that''s the real trick) relatively.

Ex.: in a "standard" engine, if your camera is at world position (10, 0, 1) and an object is at position (12, 1, -3), it''s fundamentally the same than having the camera at (0, 0, 0) and the object at (2, 1, -2). With a difference: since all translations are now relative to the camera, you no longer have huge numbers in your matrices, and have lowered the internal errors.

Hope that helps.

Y.
quote:Original post by Ysaneya
quote:
Actually, and this is telling, I had to fly (with ''9'' speed) around the galaxy for a little bit before settling down somewhere and seeing the errors.


Oh, now i see, you''re right, i didn''t travel far enough. I tried to fly at 9 speed for a while, and when zooming on a star i got the issues you described.

I faced the same problem in my own engine (on a smaller scale, since i''m using the kilometer unit), and it''s actually coming from a lack of precision with internal matrix calculations as everything is done on floats. For example, an offset of 1 centimeter at a distance of 1 kilometer from the origin will have a far lower error than an offset of 1 centimeter at a distance of one parsec.

The way to fix it (which i think is described in the gamasutra article, but don''t quote me, i don''t remember exactly) is to ban "huge" numbers in your matrices, especially huge translations. I''ve only implemented that system at the planet level in my new engine, but the principle should be the same at the universe level. The idea is similar to a skybox; you should generate your geometry in local space; always set your camera at origin (0, 0, 0); and set the world matrix (and that''s the real trick) relatively .

Ex.: in a "standard" engine, if your camera is at world position (10, 0, 1) and an object is at position (12, 1, -3), it''s fundamentally the same than having the camera at (0, 0, 0) and the object at (2, 1, -2). With a difference: since all translations are now relative to the camera, you no longer have huge numbers in your matrices, and have lowered the internal errors.

Hope that helps.

Y.

Oh! I see. The problem is that initially the camera is at (0,0,0) so whatever star is there will always be correct, so if I flew around and went back to that star, it''ll be fine. But when I move far away, then the absolute coordinates are high... wow, I wasn''t even close to coming to that conclusion. Thanks Ysaneya!

~CGameProgrammer( );

Screenshots of your games or desktop captures -- Upload up to four 1600x1200 screenshots of your projects, registration optional. View all existing ones in the archives..
~CGameProgrammer( );Developer Image Exchange -- New Features: Upload screenshots of your games (size is unlimited) and upload the game itself (up to 10MB). Free. No registration needed.
Cam = 0. That's what I meant by handling (concatenating) the total projection (modelview*projection) yourself. This eliminates such Translate-Translate stuff. But maybe this was unclear. I am probably too biased by my software rendering formation and I see things a bit differently.

When I mentionned an API I meant D3D or GL. My classification is :

User code or API (3) / HAL API (D3D or GL) (2) / Driver (1) / Hardware (0).

The problem how the original model coords are processed is level (1) or (2) probably handles such a matrix chain very poorly with big translations :

Projection*(Tcam*Rcam)*(Tobj*Robj)
(R:rotation, T:translation)

If you do it yourself (relativize to camera) you can lower the magnitudes of Tcam and Tobj in your computations.



Else Yasena, I have sent you a mail @ f.b...@vr...com. My new address is public here. I just changed it in my GD profile.

It's normal indies are interested in procedural techniques because it's ideal to produce content without graphic production. Ideal for small big games

I don't use Perlin noise since I generate tons of texels per second, that would not work. One can surf at 1 meter height, 500 mph and still see rocky details. I use a fast method for fractals which is a serious improvement of a rather well known technique (midpoint subdiv + rand). The details are quite complex to explain. It's not something you code in one night, specially with an infinte terrain, lod, pop-ups, t-verts, fpu precision, complex lighting, shadows, etc... To make it work costed some sweat and it's still not finished. I'll try to produce a mpeg of the demo.

The textures are simply as if you created infinitely more geometric details. If you want I render quasi infinitesimal shaded geometry in texture space. In one word I use textures to cache infinitesimal geometry. It makes my whole algorithm very coherent.


[edited by - Charles B on March 1, 2004 8:57:18 PM]
"Coding math tricks in asm is more fun than Java"
just one thing... about the fog. There is no fog in space. It''s a product of atmosphere. So don''t worry about the stars becoming brighter as they come closer. There is the epidimy of nothingness in space. There is nothing between you and the stars. Especially not fog.
quote:Original post by kahlyn
just one thing... about the fog. There is no fog in space. It''s a product of atmosphere. So don''t worry about the stars becoming brighter as they come closer. There is the epidimy of nothingness in space. There is nothing between you and the stars. Especially not fog.

But, you see, there is perspective. As stars get farther away, they appear smaller and consequently less bright. But since I can''t render stars smaller than one pixel, they''re all one pixel in size, but they get darker as they get farther away.

~CGameProgrammer( );

Screenshots of your games or desktop captures -- Upload up to four 1600x1200 screenshots of your projects, registration optional. View all existing ones in the archives..
~CGameProgrammer( );Developer Image Exchange -- New Features: Upload screenshots of your games (size is unlimited) and upload the game itself (up to 10MB). Free. No registration needed.
Everything''s going smoothly at the moment; I use a reference point that changes each time the camera moves one lightyear from the last reference point. All geometry is then in coordinates relative to that position.

I also noticed something really funny. In the code that generates the sphere for a star, I had this line:

Vertices[(Y * (DetailLevel+1)) + X].Position = Position + (Radius * SphereNormal) - Origin;

Origin is the reference point and Position is the center of the star in absolute coordinates. So by subtracting the reference point, I get a relative position. Anyway that still resulted in a misshapen sphere. It was fixed by doing this:

Vertices[(Y * (DetailLevel+1)) + X].Position = (Position - Origin) + (Radius * SphereNormal);

So that''s not even matrix math, that''s simple addition and it was inaccurate. In case you don''t get it, in the first code excerpt, the radius*normal is added to the very large position value, causing an inaccurate result. The origin was then subtracted but it''s too late, the damage is already done. So I had to subtract the origin from the position first so the value is low before I add the radius*normal.

By the way, here are some figures. A star is between 2-4 units in radius (4-8 units across). A lightyear is 8192 units. A galaxy is 1024x1024x1024 lightyears. That means it''s 8388608 units on each side. Floating-point hell! When the speed is ''9'' you move 16 light-years per second, so after 10 seconds of that, you''d cover less than 1/6 the length of the galaxy (though you start in the middle of it) and that was still enough for the floating-point calculations, and even mere addition, to fail.

~CGameProgrammer( );

Screenshots of your games or desktop captures -- Upload up to four 1600x1200 screenshots of your projects, registration optional. View all existing ones in the archives..
~CGameProgrammer( );Developer Image Exchange -- New Features: Upload screenshots of your games (size is unlimited) and upload the game itself (up to 10MB). Free. No registration needed.
Good to see you''re getting it to work, CGameProgrammer. That issue is one of the main reasons i''ve re-started my engine from scratch. In my old page (http://www.fl-tw.com/Infinity/engine.htm), you can see that effect in one of the videos... maybe not actually, since their quality is quite low, but believe me it''s here. I noticed it the first time when i tried to drop a building on the ground, i got horrible fighting between the walls base and the ground, but since the camera was close from the object this couldn''t be a ZBuffer problem.

Charles: the address should be correct (it''s also public in my profile), but i didn''t receive anything. Can you send it again? Btw. i can''t see yours in your profile, or i would stop to harass you on gamedev

Y.
Vertices[(Y * (DetailLevel+1)) + X].Position = (Position - Origin) + (Radius * SphereNormal);

Right it's exactly the same issue as in the matrix chain. Writing position-origin is exactly what Yasena told you, it's relativize to your camera, do as if it was {0,0,0}. If you render this star as a mesh it means Radius and Position-Origin are of the same order of magnitude. Always keep in mind the magintudes, you should never add or sub values of different magnitudes with floating points, specially in intermediate results such as : Position + (Radius * SphereNormal).

And BTW, changing the c code is sadly not enough since you do not control compiler optimisations (specially in release) that may transform your second code into the first one back again. Hell ! If you want something totally safe you should write :

Vector RelCenter[0] = Star.Center-Origin;
// then the rest of your computation.

The other way to do is code in asm, the compiler will not change the code sequence.

As you can see you probably underestimated the practical fpu precision issues. Since I've done a lot of software rendering in the past, mixing fp and int, I am very cautious with fp code.



Seeing your range of distances you have to be very aware on the IEEE754 format of floating points (Google).
Coords=2^-10, Radius=2^1, LY:2^13, Galaxie=2^23

I state 2^-10 as reasonable precision compared to the radius (0.1%). You must understand that 32bits floating points have a 24bits mantissa. So it's certain that since Galaxies are 2^23, if you translate Coords at the end of it, they'll be deleted from numerical precision !!!

Even if your Galxy was 2^13, imagine how your planet would render if you pass Coord+Translation at your Projection*Model matrix !!! A squary (scary) sphere (cube in fact) of 1.0 unit !

Solution 1) (not very good)

You could do all your calculations in double format (53bits mantissa) this would leave you 53-33=20 bits for your model coordinates. But that's memory wasting, you need to watch for 64bit alignement of the coords. Else the FPU speed is the same as in 32bits.

In this case you can avoid popping artifacts when your camera crosses 2^n boundaries. The way to do is offset your absolute coordinates by 2^n, here n=23 given by your galaxy size. That's what I call fixing the point of the floating points. This way everywhere you put them in your galaxy, the sphere models will render exactly the same.


Solution 2) (the one you explained)

That's good, but choose a partition your coordinates every 2^n. n could be 13, for one light year. But choose exactly a power of two it eliminates numerical garbage. Then offset your coordinates by the 1.5 that amount.

This way, in the matrix computations (inside GL), the intermediate pseudo absolute coordinates of your model will be :

x = 1.5*2^14 + xlocal
y = ...
z = ...
and -2^13 < xlocal < 2^13

This means that the precision of x will always be exactly 2^(14-24) units, or unit/1024. No tilt effects anymore. But you can also choose a lower n for the size of the 'coordinate chunks' and thus you'll get even a higher precision for x. You'll get what you want, anywhere in your galaxie.

Another very important point : store the (truely absolute)galactic coordinates of your stars/planets centers in double precision. This way you won't loose bits when you'll translate them to pseudo absolute coords.

Any better word for pseudo absolute coords ?

(Wrote that quickly, full of crap erratic chars, will reedit it later, but I must go now).


[edited by - Charles B on March 2, 2004 7:14:19 AM]
"Coding math tricks in asm is more fun than Java"

This topic is closed to new replies.

Advertisement