Skip to main content
GameDev.net gamedev.net
🔒 Locked

Alpha Testing vs. Depth Testing

Started by axv4745 May 3, 2006 at 12:18 PM 12 replies 13k views
Original Post
axv4745
axv4745
Is there any substantial difference between Alpha Testing and Depth Testing. It seems both in the end do the same thing (i.e test some value (alpha value or depth value) and if the test fails then the corresponding pixel doesn't get drawn to the frame buffer). Am I understanding this correctly so far? If so, then is there any advantage to using one over the other? Thanks,
Luminous
Luminous
I may not be 100% correct but I thought depth testing was strictly for determining if a pixel should be drawn or not depending on its position in space.

And alpha testing is just for testing the alpha color of the pixels/primitives/textures to be drawn. Depending on the function and value you specify. So if you have a compare function of greater, and a value of 0, you would draw all pixels with an alpha value greater than 0.

So they both get rid of pixels or whatever, but they have different purposes.
S1CA
S1CA
Luminous: yep, you're correct.


Alpha Test:

- When alpha testing is enabled (D3DRS_ALPHATESTENABLE=TRUE), the alpha value (if present, else A=1) of a pixel being drawn is tested against a single 'reference' value (D3DRS_ALPHAREF) using a comparison function (D3DRS_ALPHAFUNC).

- If the the test against this reference value fails, the pixel is discarded and doesn't proceed any further in the pipeline.

- If the test against the reference value succeeds, the pixel proceeds to the next stage of the pipeline.


Depth Test:

- The Z values (and/or W - depending on type of depth buffering) of the [transformed] vertices of a polygon are interpolated to produce a depth value for every pixel in that polygon.

- These per-pixel depth values can also be written from a pixel shader (ps2.0 and above) using the oDepth output register.

- Each of these (per-pixel) depth values are compared against the corresponding pixel at that [2D] position in the depth buffer (Z-buffer or W-buffer, usually).
If the comparison passes, the pixel is drawn to the frame buffer (via alpha blending), and it's depth value is written to the depth buffer (assuming D3DRS_ZWRITEENABLE=TRUE). If the comparison fails, the pixel is discarded.

- D3DRS_ZFUNC controls the type of comparison performed between the depth value of the pixel being drawn and the depth value already in the depth buffer. The default comparison rejects pixels if their depth is further away than the depth already in the depth buffer.


Pipeline:

- When enabled, depth testing happens for every pixel that's about to be rendered to the frame buffer.

- Alpha test happens before Depth test in the pipeline. This means that if a pixel fails alpha test, then it a) won't be rendered, and b) won't be considered for depth testing.

- This behaviour can be useful for things using 1-bit alpha (on/off transparency) for hard-edged shapes (picket fences etc) since you can still use depth buffering to avoid the manual sorting necessary with variable alpha semi-transparency.

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site
Demirug
Demirug
Quote:
Original post by S1CA
Pipeline:

- When enabled, depth testing happens for every pixel that's about to be rendered to the frame buffer.

- Alpha test happens before Depth test in the pipeline. This means that if a pixel fails alpha test, then it a) won't be rendered, and b) won't be considered for depth testing.

- This behaviour can be useful for things using 1-bit alpha (on/off transparency) for hard-edged shapes (picket fences etc) since you can still use depth buffering to avoid the manual sorting necessary with variable alpha semi-transparency.


A small addition:
If the alpha test is not enabled and the depth value is not changed from the pixel shader (version 1.x supports this too) modern GPUs can use an additional depth testing on blocks of pixel (a quad or larger) before they reach the pixel shader.
As an active alpha test disables this behavior it can have a huge performance impact if you use a complex pixelshader and your objects are in front to back order.
ET3D
ET3D
Quote:
Original post by Demirug
If the alpha test is not enabled and the depth value is not changed from the pixel shader (version 1.x supports this too) modern GPUs can use an additional depth testing on blocks of pixel (a quad or larger) before they reach the pixel shader.
As an active alpha test disables this behavior it can have a huge performance impact if you use a complex pixelshader and your objects are in front to back order.


Theoretically, if depth isn't changed in the shader, pixels could be rejected by depth regardless of alpha, and alpha testing will only affect depth buffer writes. So the way I see it alpha testing shouldn't have a detrimental effect on depth buffering. However, I've heard the comments about alpha testing disabling depth optimisation before, so I wonder if there's a flaw in my logic.
Demirug
Demirug
Your logic is fine but did not match with the way the Early-Z test on a GPU works. The main problem with Early-Z is that the unit that does it need to know the current depth values or at least a compressed version of the whole depth buffer to do it’s work. (I can go in this much deeper if necessary). After a pixel block pass the Early-Z test the deep buffer or the compressed version is update to make sure the next block have the current data. The passed block will then go to the pixel shader and many clocks later it will go to the alpha test. If the alpha test is not passed we have a big problem because the Early-Z test unit have already updates there own depth buffer in a way that includes this pixel as final written. There are only two ways to work around this problem. First you can roll back and redo the Early-Z test for every pixel block on the same position or you simply deactivate Early-Z if alpha test is enabled. As such a roll back is very complicated current chips don’t do this and the driver simply deactivate the Ealy-Z unit if you use alpha test. You will notice a very similar problem with stencil tests.
ET3D
ET3D
Thanks for the explanation, Demirug. Seems to me that it'd still be possible to treat completely failed blocks (that don't need an update) separately, but it may be more trouble than it's worth.
Demirug
Demirug
Quote:
Original post by ET3D
Thanks for the explanation, Demirug. Seems to me that it'd still be possible to treat completely failed blocks (that don't need an update) separately, but it may be more trouble than it's worth.


Same problem as the Early-Z depth buffer always contains the data for the passed block. You need to rollback. It is possible to do Early-Z and Alpha Test at the same time if you don’t use Z-Write.
ET3D
ET3D
I still don't understand. If the block fails completely (is completely occluded), it means that no Z writing needs to be done for that block, and that no pixel shader will run on any pixel of that block. So why would you have to roll back anything?

I think that we have a miscommunication about what "passed block" means. If you're talking about a block that passed testing (i.e., not the blocks that I'm talking about) then I don't understand how this interacts with the failed blocks. If you're talking about a block that's being passed around, then that's something else.
LeGreg
LeGreg
Quote:
Original post by axv4745
Is there any substantial difference between Alpha Testing and Depth Testing. It seems both in the end do the same thing (i.e test some value (alpha value or depth value) and if the test fails then the corresponding pixel doesn't get drawn to the frame buffer). Am I understanding this correctly so far? If so, then is there any advantage to using one over the other?


Well simply put, you cannot emulate one with the other. Those have two non intersecting scopes. And more importantly you can use both at the same time (an alpha tested polygon can still be occluded, by existing geometry and write a partial occluder into the ZBuffer).

LeGreg
Demirug
Demirug
Quote:
Original post by ET3D
I still don't understand. If the block fails completely (is completely occluded), it means that no Z writing needs to be done for that block, and that no pixel shader will run on any pixel of that block. So why would you have to roll back anything?

I think that we have a miscommunication about what "passed block" means. If you're talking about a block that passed testing (i.e., not the blocks that I'm talking about) then I don't understand how this interacts with the failed blocks. If you're talking about a block that's being passed around, then that's something else.


The problem cases are pixel that pass the early-Z test but fail the alpha test. They will cause an invalid Z-Buffer in the Early-Z test unit.

Example.

Two Pixel are draw front to back. The first (front) will pass the Early-Z unit and this updates the Z-Buffer of this unit. The second pixel will then rejected by the early Z-Unit because it is behind the first. Unfortunately the first one will leave the pixel shader many clocks later and the alpha test throw it away. In this case the second pixel should never be rejected but it is already too late.

Early-Z and Alpha-Test together can cause that pixel blocks are rejected that should be drawn.
ET3D
ET3D
Then I understood you correctly before, but I guess I wasn't clear myself, so I'll provide some more detail.

What I described was something like this:

Block is tested against Z.

If entire block fails, reject all the pixels.

If any pixel in the block passes, mark block for not being tested further. All future tests using this block (in this rendering call) will bypass hierarchical depth processing.


I realise it's not as simple as that, but it seems much easier than doing rollback, and keep most of the benefit of hierarchical depth.
Demirug
Demirug
Now I understand and this is a real good idea. Unfortunately you will not be able to get a patent (Hierarchical depth test with dynamic block based deactivation) for it after you have written about it here.
ET3D
ET3D
Ah, well. I was never any good at setting myself up to be a millionaire. :)

At least it means that nobody else will be able to patent it. Patents can be annoying things.

Now all I need is to get this to ATI's and NVIDIA's (and S3's?) attention, and hope they implement it.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.