Archived

This topic is now archived and is closed to further replies.

Problem when rendering a skybox

This topic is 5150 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, I have a problem when rendering a skybox. Currently, I render my skybox by disabling the zbuffer. Everything seems fine with this approach except I encounter a far clipping plane problem. The skybox appears just right after my far clipping plane. The scene doesn''t make sense when the character walks in a large open area since other objects may suddenly appear from the skybox when the character approaching those objects (because of the far clipping plane). Is there any solution of this problem... or I must used a extremely big skybox instead... but it will cause another problem since the character may never seen the skybox.... Thank for your help! Nachi

Share this post


Link to post
Share on other sites
I suggest moving the far clip plane so it's always behind the skybox and making the skybox big enough so that it's always behind on your scenery (assuming your scenery has some limit). For a z-buffer (as opposed to w-buffer) moving the far clip plane has much less effect on your z-buffer error distribution than moving the near clip plane (see http://groups.yahoo.com/group/opengl-gamedev-l/message/14257).

In my case I have skybox at 10,000 units, my world size is 1,000 units and my far clip plane is at 10,000,000 units. Though I don't really need to have that much room for error.

EDIT: changed 'front' to 'behind' and 'distribution' to 'error distribution'.

[edited by - soiled on November 5, 2003 9:07:30 PM]

Share this post


Link to post
Share on other sites
You should render the skybox with depth test and depth write disabled. The size of the skybox has nothing to do with your far clipping plane or objects popping into view at distance.

Share this post


Link to post
Share on other sites
Sorry, but I think your approach doesn''t really work. It is becuase I cannot set my far clipping plane to such big value. Since I am using octree to reduce number of polygons that drawn to the screen, so I need to make the far clipping plane as tight as it can.

Nachi


quote:
Original post by Soiled
I suggest moving the far clip plane so it''s always behind the skybox and making the skybox big enough so that it''s always behind on your scenery (assuming your scenery has some limit). For a z-buffer (as opposed to w-buffer) moving the far clip plane has much less effect on your z-buffer error distribution than moving the near clip plane (see http://groups.yahoo.com/group/opengl-gamedev-l/message/14257).

In my case I have skybox at 10,000 units, my world size is 1,000 units and my far clip plane is at 10,000,000 units. Though I don''t really need to have that much room for error.

EDIT: changed ''front'' to ''behind'' and ''distribution'' to ''error distribution''.

[edited by - soiled on November 5, 2003 9:07:30 PM]


Share this post


Link to post
Share on other sites
nachilau:
what do you mean by saying the far clipping plane has to do something with your octree?

you reduce the number of polygons with an octree algorithm so the number you draw is only affected by your octree (and clipper) not by your far clipping plane. If you rely on OpenGL''s clipping planes to do the culling you are doing something wrong.

Besides that setting the clipping planes to high values is not a good idea as the zbuffer gets more inaccurate the greater the distance is it has to cover.

So what fingers said is the best solution:
disable zbuffer reads&writes
draw skybox (doesn''t have to cover the whole world as the z buffer takes out the places where your world is drawn)
reenable zbuffer writes
draw your world

Share this post


Link to post
Share on other sites
Soiled> hem... my skyboxes used to be a 5 units cube and I had objects displayed more than 10000 units away... like Fingers_ said, the size absolutely doesn't matter, as long as it doesn't intersect with your _near_ clipping plane (in my case, that was 2)

edit: lousyphreak:
would be better that way:

load identity matrix
apply camera rotations
disable zbuffer reads&writes
draw skybox (doesn't have to cover the whole world as the z buffer takes out the places where your world is drawn)
load camera matrix (rotations + translations)
reenable zbuffer writes
draw your world






[edited by - sBibi on November 6, 2003 2:22:00 AM]

Share this post


Link to post
Share on other sites
quote:
sBibi wrote
Soiled> hem... my skyboxes used to be a 5 units cube and I had objects displayed more than 10000 units away... like Fingers_ said, the size absolutely doesn't matter, as long as it doesn't intersect with your _near_ clipping plane (in my case, that was 2)


Yeah I agree and that's what I used to do on my old gf1 but I had strange clipping problems so I've since just made the skybox really large (which also works fine). I should go back to the sensible way to do it though. Actually I think the clipping problems I was having were somehow due to mapping the viewport z range from [0,1] to [1,1].
quote:
LousyPhreak wrote
Besides that setting the clipping planes to high values is not a good idea as the zbuffer gets more inaccurate the greater the distance is it has to cover.


Yes, but not by much (see http://groups.yahoo.com/group/opengl-gamedev-l/message/14257).

EDIT: The problem I had with my old gf1 is described here (http://discuss.microsoft.com/SCRIPTS/WA-MSD.EXE?A2=ind0207A&L=DIRECTXDEV&P=R7394&I=-3).


[edited by - soiled on November 6, 2003 8:29:22 AM]

Share this post


Link to post
Share on other sites
Actually, for my scenario this works best (note, draw world *first* instead of *last*)...

- clear z to 1
- draw world,
- zbuffer-tests-on/zbuffer-writes-off/zbuffer-func-lessequal,
- draw skybox (either make skybox larger than world or set screen_space_z = screen_space_w in vs so that screen-space z/w is 1... ie larger than any generated by the world).

...this way the world occludes sky and saves fillrate when drawing sky (especially if using multiple passes with expensive pixel shaders to do dynamic clouds on the sky).

[edited by - soiled on November 6, 2003 8:48:23 AM]

Share this post


Link to post
Share on other sites
i personally use a small skybox of 10unit edges. Irrespective of its size compared to the world, just enable depth test but disable depth write... then render the skybox first before all else. Reenable depth writing and do everything else u need to do.

also, this way, u can disable color-buffer clearing coz ideally the skybox sorta masks the entire scene background, unless u have alpha.. hrm.

Share this post


Link to post
Share on other sites
quote:
Original post by sBibi
sounds good for opaque faces


You're right (I didn't include alpha-blended faces), so how about...

- clear z to 1
- zbuffer-tests-on/zbuffer-writes-on/zbuffer-func-lessequal,
- draw opaque parts of world,
- zbuffer-writes-off,
- draw skybox (and set screen_space_z = screen_space_w in vs),
- setup alpha blending,
- draw translucent parts of world.

...so expensive sky pixel shaders still get zbuffer-culled at opaque world pixels and translucent parts of world still blend properly with sky and opaque-world. This assumes that you can split your world into opaque and translucent parts. For objects that contain both, like anti-aliased grass, you should be able to do this...

draw_opaque_pass_of_foliage:
- alpha-test-on/alpha-ref-one/alpha-func-equal/alpha-blend-off/zbuffer-test-on/zbuffer-writes-on/zbuffer-func_lessequal,
- draw all foliage.

draw_translucent_pass_of_foliage:
- alpha-test-on/alpha-ref-zero/alpha-func-greater/alpha-blend-on/zbuffer-test-on/zbuffer-writes-off/zbuffer-func-less,
- draw all foliage.

...so opaque bits of foliage get properly depth-sorted by zbuffer and anti-aliased edges of foliage get blended (a rough back-to-front sort should do). The other advantage is the alpha-blending hit is reduced (assuming opaque parts of foliage are significant) so it serves the dual purpose of reducing alpha-blending and reducing sky pixel shading. The translucent pass should be pretty easy on fillrate since only alpha-blended edges get rendered (ie, fully-transparent and fully-opaque parts get rejected).

The drawback with this whole approach is the sky is now drawn inbetween opaque and translucent passes of partially-opaque objects which can mean more state changes (ie, you can no longer draw a patch of grass as opaque and then immediately draw same patch of grass as translucent... you have to draw all patches of grass as opaque, draw skybox and then go back and draw them all again as translucent). Alternatively you could ignore the sky-occluding ability of the opaque parts of foliage and simply draw the sky before drawing any parts of any foliage (then you could draw grass any way you like and it would be correctly blended with the sky). Note that you'd still get the sky-occluding advantage of other fully-opaque objects like the terrain, houses, etc.

So it should probably look more like:

- clear z to 1
- zbuffer-tests-on/zbuffer-writes-on/zbuffer-func-lessequal,
- draw fully-opaque objects of world (eg terrain, houses, etc),
- draw opaque pass of large screen-size, partially-opaque objects (eg bushes near viewer),
- zbuffer-writes-off,
- draw skybox (and set screen_space_z = screen_space_w in vs),
- setup alpha-blending,
- draw translucent pass of large screen-size, partially-opaque objects,
- draw small screen-size, partially-opaque objects any way you like.


quote:
CraZeE wrote
also, this way, u can disable color-buffer clearing coz ideally the skybox sorta masks the entire scene background, unless u have alpha.. hrm.


As long as you can guarantee that your sky + opaque_world covers the entire screen then you can avoid the colour-buffer clear. Though the bandwidth for clears is so much faster than the memory bandwidth that it probably doesn't matter much anyway.

[edited by - soiled on November 7, 2003 5:10:36 AM]

Share this post


Link to post
Share on other sites
mmh, drawing the major opaque occluders (like terrain/buildings/tree trunks) first before the sky should cull enough pixels I guess. then draw every other small stuff (characters/grass/tree foliage/etc..) afterwards... there probably is no need to get a perfect occlusion for opaque objects (if at all possible), and as you said, the overhead introduced by partially opaque objects would probably be usually more important than just rendering a bit more sky pixels...

Share this post


Link to post
Share on other sites
quote:
Original post by nachilau
Hello,

Sorry, I am not sure what actually you people mean set screen_space_z = screen_space_w. What is the actually code to do that in DirectX??

Nachi


In a DirectX9 vertex shader this would look like...

"vs_1_1\n"
"dcl_position v0\n"
"mul r0, v0.x, c0\n"
"mad r0, v0.y, c1, r0\n"
"mad r0, v0.z, c2, r0\n"
"mad r0, v0.w, c3, r0\n"
"mov r0.z, r0.w\n" // screen_space_z = screen_space_w
"mov oPos, r0\n"

...the first four arithmetic instructions transform skybox position to view screen-space (ie, c0-c3 is the model-view-projection matrix - I do it this way so that I don't have to transpose my D3DXMATRIX before passing it to shader). So now 'r0' is in screen-space. The fifth arithmetic instruction then copies w component to z component. The sixth instruction just moves result to output position. After the vertex shader finishes, the viewport scaling and then the homogenous divide is done to get window coordinates. So the z window coordinate ends up looking like "minZ + (maxZ-minZ)* (oPos.z/oPos.w)" where minZ and maxZ come from viewport structure. Assuming minZ=0 and maxZ=1 and since oPos.z=oPos.w we get a window z of 1. This gets converted to the maximum zbuffer value of (2^zbuffer_bits)-1 which is always behind the world (unless the world also happens to have the largest zbuffer value somewhere... eg, world gets clipped by far plane). You need to use zbuffer-test of lessequal since cleared zbuffer also has maximum value.

I haven't actually done this since I opted for the less-elegant solution of drawing a large skybox (but I plan to switch over because I would then not need to keep track of how large my world is and constantly adjust the skybox size to make it larger).

quote:
sBibi wrote
major opaque occluders (like terrain/buildings/tree trunks)first...
small stuff (characters/grass/tree foliage/etc..) afterwards...


Yes, good idea... separate the tree trunks from the tree foliage.


[edited by - soiled on November 7, 2003 9:05:36 PM]

Share this post


Link to post
Share on other sites
sBibi -- depth testing shud still be enabled because the skybox is still a box with multiple sides. Although for a simple skybox with 6 sides, u''ll never come to a point where u can see 2 opposite sides (say the front and back) at the same time so u may disable depth testing altogether. But if u begin doing some form of multipass or maybe multi-layered skyboxes ala unreal, u''ll want to keep the depth test enabled.

on a lesser scale, state changes are best avoided if possible. I suppose leaving depth enabled throughout is better, but occasionally masking writes is a convenient way rather than disabling depth altogether. Hope i got that right though

Share this post


Link to post
Share on other sites