Opengl shadow acne when using shadow2D

拟墨画扇 提交于 2019-12-08 18:19:32

Why is your bias based on the angle between the light and surface? That is what is causing these bizarre moiré patterns. Usually if you want to bias the depth against angle (think of it like anisotropic bias for shadow maps) you would use glPolygonOffset (...) when you create the shadow map, and in your shader you would use a constant bias, or a bias that varies slightly with distance (but not angle).

The problem with polygon offset, however, is that it will disable hierarchical Z-Buffering when enabled (so shadow map construction fill-rate will theoretically dip). The offset occurs after primitive assembly. It is not a perfect solution, but definitely better than what you have right now.

You might be able to implement slope based biasing in your shadow map's vertex shader by biasing the W coordinate slightly, this will allow early Z rejection using the results of the primitive assembly stage... but it will be harder to find a good value to use for W.


... so I decided to use sampler2Dshadow with shadow2D, cause I've read it serves as simple anti-aliasing solution.

As for the difference between sampler2D and sampler2DShadow, when used in a call to texture (...) (or shadow2D (...) in older versions of GLSL) a sampler2DShadow that has texture comparison enabled will produce a binary result - 1.0 if it passes the test function, 0.0 if it fails. Considering your fragment shader already performs a comparison and expects the value returned by the sampler to be the depth, and not a pass/fail result you should be using sampler2D -- ignore the existence of sampler2DShadow in this case.

                                      

I have no idea what version of GLSL you are using, since you make use of shadow2D (...), which has long been deprecated. However, if you take a look at the GLSL specification for version 440, pg. 153 (8.9 - Texture Functions) it will refer you to the table I included above.

For shadow forms (the sampler parameter is a shadow-type), a depth comparison lookup on the depth texture bound to sampler is done as described in section 8.22 “Texture Comparison Modes” of the OpenGL Graphics System Specification. See the table below for which component specifies Dref. The texture bound to sampler must be a depth texture, or results are undefined. If a non-shadow texture call is made to a sampler that represents a depth texture with depth comparisons turned on, then results are undefined. If a shadow texture call is made to a sampler that represents a depth texture with depth comparisons turned off, then results are undefined. If a shadow texture call is made to a sampler that does not represent a depth texture, then results are undefined.

Effectively sampler2DShadow will reduce aliasing, but only because it produces exactly two results: 1.0 and 0.0 and the average of these results is more meaningful than the average depth (as I will explain below). So there is some truth to that statement, but you have taken it out of context I believe.

In reality, if you want to reduce shadow aliasing what you ought to do is take the average of N-many depth tests. Using linear filtering is usually a valid approach to reduce aliasing in traditional textures, but with depth textures the value stored in the texture is actually supposed to be used for comparison purposes. If you were to use linear filtering and sampler2D, the GPU would gather the 4 nearest depths in the shadow map, average them and then you would perform a single pass/fail test on the averaged depth. This actually gets you nothing useful because your fragments still either pass or fail.

What you want to do is gather the 4 nearest depths, test them individually and then average the pass/fail result. Then instead of each fragment either passing or failing, you may naively have 0%, 25%, 50%, 75% or 100% obstruction -- in fact, the average may be weighted by distance of each sample from the sample coordinate. This is known as Percentage Closer Filtering (PCF), shadow2D (...) and sampler2DShadow actually do exactly this if you enable linear filtering on some drivers. Instead of averaging sampled depths, they test the sampled depths and then average the results of all tests.

This is actually where the anti-aliasing properties of sampler2DShadow come from, but you must structure your GLSL shader properly to take advantage of it. You can just as easily (and more portably) sample 4 points yourself using a sampler2D with a NEAREST filter and perform the testing and averaging yourself...


Also, try not to read the z component of a depth texture. You are lucky that for versions of GLSL >= 130, a sampled depth texture produces the result: vec4 (r, r, r, 1.0), but in older versions of GLSL the behavior depends on something called a depth texture mode. It is equally possible for z to be 0.0, or completely undefined pre-GL3. You should read r or x, since depth textures are single-component by nature. The table above even indicates this - the computed result is stored in r, not b.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!