Problem when rendering a skybox

Started by
14 comments, last by nachilau 20 years, 5 months ago
craze> in your case, what''s depth test useful for? (as you draw it before anything else anyway...)
Advertisement
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]
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...
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
Nachi Lau (In Christ, I never die)www.sky-dio.com/Nachi
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]
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
- To learn, we share... Give some to take some -

This topic is closed to new replies.

Advertisement