+ All Categories
Home > Documents > Maximizing Depth Buffer Range and Precision

Maximizing Depth Buffer Range and Precision

Date post: 03-Jun-2018
Category:
Upload: jonathan-johnson
View: 224 times
Download: 0 times
Share this document with a friend

of 10

Transcript
  • 8/12/2019 Maximizing Depth Buffer Range and Precision

    1/10

    7/16/2014 Outerra: Maximizing Depth Buffer Range and Precision

    http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html

    Wednesday, November 28, 2012

    Maximizing Depth Buffer Range and Precision

    (new: Japanese translationavailable, thanks to Yuki Ozawa)

    Common depth buf fer setups used in 3D graphics hardware to this day are woefully inadequate for the task. One can easily get

    artifacts known as z-fighting even with relatively limited scene depth range. Utilization of the available depth buffer values is

    quite horrible: half of the resolution is essentially wasted just in the distance from the near plane to twice that (short) distance.

    This leads to the need to move the near plane as far as possible, which is not very desirable in itself, and its still not enough as

    soon as you need to cover just a slightly extended detail range. Its of course completely unusable for large scale rendering, with

    developers having to use various tricks that bring their own bag of complications.

    This article talks about the ways to set up the depth buffer so that it's able to handle blades of grass in front of your eyes while

    also rendering objects hundreds of kilometers in distance. It's mostly biased towards OpenGL, but most of i t applies to DirectX

    as well.

    Lets go fi rst into some details about the depth processing that arent immediately obvious, wh ich nevertheless play a significant

    role in understanding the properties of depth buffering.

    A common perspective depth buffer setup relies on the use of a standard projection matrix that involves setting the near and far

    clipping plane distances. While you can set the projection matrix in any way you want, a perspective-correct depth buffering will

    work only as long as the matrix satisfies certain conditions.

    With the standard perspective OpenGL projection matrix, the value of w and z outpu t from the vertex shader is usually computed

    as:

    wp= -z

    zp= z*(n+f)/(n-f) + 2fn/(n-f)

    That means w ends up holding the positive depth from the camera plane, while z can be generally expressed as a linear equation:

    zp= -az + bor

    zp= awp+ b

    Values from the vertex shader are then converted into the normalized device coordinates by dividing by w, and z thus becomes:

    zndc= a + b/wp= a - b/z

    A typica l scene in plan etary engine Outerra: from blade s of g rass to several te ns of kilometers distant mountains

    How the standard depth buffer works

    outerra.comforum.outerra.com

    @outerra@cameni

    +outerra

    Search

    Search This Blog

    2014(2)

    2013(4)

    2012(13)

    November(4)

    Maximizing Depth BufferRange and Precision

    View Frustum Culling ofSphere-mappedTerrain

    OpenGL Notes #2:Texture bindperformance

    Importing models andbasic scripting inOuterra

    August(1)

    July(2)

    June(1)

    May(1)

    April(1)

    March(2)

    February(1)

    2011(10)

    2010(19)

    2009(15)

    2008(8)

    Blog Archive

    books (2)cessna (2) chromium

    (2) depthbuffer (6)

    flight simulator(4)

    fog (2) fractal terrain (5)Google Maps (2) grass (2)

    horizontaldisplace (2) lighting (3)

    OpenGL (2) planetrendering (6) roads (6)

    simulator (2)water

    (3)

    Labels

    33 More Next Blog Create Blog Sign

    Text

  • 8/12/2019 Maximizing Depth Buffer Range and Precision

    2/10

    7/16/2014 Outerra: Maximizing Depth Buffer Range and Precision

    http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html 2

    After that it gets clipped to -1 .. 1 range.

    DirectX uses 0..1 range for z, bu t the principle is the same.

    Specification says that with perspective interpolation all vertex shader outputs are interpolated in perspective (by interpolating

    p/w and 1/w linearly and then dividing the two to get perspective-correct values), except for the value of z which will be

    interpolated linearly. Why is that?

    Its because the rendering API expects that you are using a projection matrix that has a 1/z term in it (the above mentioned a -

    b/z), and thus to interpolate it in a perspective-correct way the hardware has to (and will only) use a linear interpolation.

    Now the problem is that this value is also used for the depth comparison. At the first look it may seem to be a fairly nice function

    to be used for depth: providing a fi ner resolution for the near objects, getting reduced with the distance where its needed less as

    the objects get smaller in perspective.

    However, in reality the profile is horribly unsuitable because it wastes way too much of the available range for the close values.

    Half of the available range is packed into tiny di stance from the near plane to twice the near plane distance.

    If there was a possibility to turn on the perspective interpolation on the depth component (as its already done for other

    interpolants unless the noperspectivequalifi er is used), then we wou ld have several good ways to radically enhance the depth

    buffer precision without in terpolation artifacts. Alas, the hardware doesnt seem to count wi th that possibility anymore, as the W-

    buffers has been gradually phased out.

    Lets take a look on what can be done about it using the available resources. First, what would be the ideal profi le.

    To avoid z-fighting artifacts, depth buffer should provide resolution that is proportional to the size of geometry needed to render

    a constant screen size image at different distances from the camera, across the whole depth range. Projected screen size i s

    proportional to the reciprocal of geometry depth, 1/z. In other words, we are looking for a function whose derivative is

    proportional to 1/z. That function happens to be the logarithm.

    To see how an ideal utilization of depth buffer values compares to the common setup, see the following graph with computedprecision of the common pipeline with 32bit floats, compared to logarithmic depth buffers at 24 and 32 bits.

    While the logarithmic distribution handles the 9 decades of depth detail range easily, a common depth buffer setup strides in to

    the unusable region after its brief 4 decades. Four decades is roughly the range we can get with the normal depth buffer setup,

    after that the precision gets into the unusable region and the depth buffer can't resolve the depth values properly anymore. With

    the logarithmic buf fer we have a plenty of reserve, in fact we could handle the scene with a 16 bit logarithmic depth buff er.

    Note that the axes in the graph are using l ogarithmic scales, so anything rising faster than 10dB is actually degenerating very

    quickly.

    Speaking of an ideal utilization, its desirable to add that theres also a lower bound on the required depth buffer resolution that

    reflects the physiognomy of our eyes - we cant focus on objects very close to our eyes, so theres no need to have a micrometer

    resolutions f or miniscule objects in f ront of us. This can be used to enhance the resolution elsewhere, as well see later.

    If the values used for depth comparison were the depth values themselves, floating poin t values would be good for the depth

    buffering technique: closer to the viewer you get values near zero, for which floating point encoding provides higher precision by

    Optimal depth resolution profile

    Floating-point depth buffers

    Join this site

    with Google Friend Connect

    Members (117) More

    Already a member? Sign in

    Followers

    Brano Kemen

    161have me incircles

    Viewall

    Add to circles

    Google+ Followers

    Subscribe To

    Posts

    Comments

  • 8/12/2019 Maximizing Depth Buffer Range and Precision

    3/10

    7/16/2014 Outerra: Maximizing Depth Buffer Range and Precision

    http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html 3

    keeping the number of bits in mantissa constant and adjusting the exponent. The farther you go less depth resolution you need,

    since the screen size of distant objects goes down by 1/z .

    Unfortunately, the value used for depth comparison is the 1/z function itself which has the unfortunate property of eating all the

    resolution on breakfast and then starving till evening.

    The use of f loating-po int values in depth bu ffer doesnt bring much if used directly: theres an increased dynamic range close to

    zero, but since the depth buffer already uses most of the value range in this region, its not useful at all.

    Theres a trick that can do something about it: swapping the near and far values will make use of the increased range of floating

    point for the distant part, instead of the near one. This is actually very effective: the increasing resolution of floating point

    number close to zero neatly compensates the dwindling resolution of 1/z function.

    Heres the graph showing the resolution of reversed floating point bufferin DirectX:

    Reversed 32bit floating point depth buffer brings slightly better resolution than a 24bit logarithmic buffer (a 32bit logarithmic

    depth buffer is roughly 20X finer), consistent across the whole 9 decades. Thats pretty great. One downside is that in

    comparison to a 24 bit integer buffer it consumes 8 more bits that could be otherwise used for stencil. Before, on older hardware,

    the use of stencil consumed twice as much memory for the f ramebuffer, since the next available format was padded to 32bits,

    with higher bandwidth required as well. However, nowadays it's not a problem - stencil is kept separate and depth buffer isoptimized/packed, and the only th ing that remained is a bit misleading OpenGL enum.

    You wil l also noti ce I mentioned DirectX explicitly. If you try the trick on OpenGL you will see zero improvement.

    As much as I am a fan of OpenGL and prefer it over DirectX, there are things in OpenGL that make me want to climb walls holding

    with fingernails.

    Some time back someone decided that OpenGL normalized device coordinates should be in range -1 .. 1 on all 3 axes, including

    the z coordinate. Normally, one would pl ace the camera into the center, projecting towards +z or -z . Z axis projects to the screen

    center, so its only log ical that x and y would be symmetric, but Z?

    For the screen depth axis it s more natural to assume normalized coordinates in 0..1 range, from the camera (or the near plane) to

    the far plane. Especially when the depth values written in to the depth buf fer are also in range 0..1.

    However, someone dreamed of a symmetric world and decided it should be more important to prefer the symmetry over the

    reason, and to have z in the -1 .. 1 range as well. Of course, then it needs to be reprojected into the depth buff er values by

    performing additional computation: 0.5*zc + 0.5

    How thi s connects with the depth buf fer precision issue? First , reversing the depth range does essentially nothing, because it

    just swaps the mapping of the near and far plane between -1 and 1, with the extra precision around the zero mapped to 2*near

    distance in both cases.

    This can be helped by using a projection that maps the far plane to 0. Normally the 3rd row of the OpenGL projection matrix is

    mapping the near plane to -1 and the far plane to 1. Changing it to

    DirectX vs. OpenGL

  • 8/12/2019 Maximizing Depth Buffer Range and Precision

    4/10

    7/16/2014 Outerra: Maximizing Depth Buffer Range and Precision

    http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html 4

    will map the far plane to 0 instead. This is essentially the reversed-depth DirectX projection matrix with an i nverted sign, so that

    the depth function doesn't change (but it can be easily switched to 1..0 range).

    Clipping still applies at 1.0, so one would have to use a custom clipping plane to clip at 0. But it can be also ignored if the

    situation allows it. For example, in Outerra theres actually no need to clip geometry behind the far plane, as its usually set as far

    as possible anyway.

    But using this alternative projection alone does not resolve the problem, the resolution is still miserable. The second part of theproblem is the additive term in the remapping (0.5zc + 0.5). That 0.5 bias locks the floating point exponent and pretty much

    destroys any and all additional precision that the encoding of floating point values brings close to zero, since now there are just

    24 bits of mantissa to handle the unfortunate 1/z shape. Hello, symmetry!

    Fortunately, at least on Nvidi a theres a way to eliminate the bias by (indi rectly) setting the mapping function via the

    glDepthRangedNV call with -1, 1 arguments, which effectively sets the DirectX-style mapping. Heres the final resolut ion graph of

    a floating point depth buffer without the bias, with the far plane mapped to 0 in OpenGL. The resolution was actually measured

    on the 460 GTX GPU:

    Unfortunately neither AMD nor Intel hardware does support the NV_depth_buffer_floatextension. I was told its a

    hardware limitation, its not able to support arbitrary output depth values. But arbitrary isnt needed. Since it supports

    DirectX depth mapping without the bias, I believe it should be entirely possible to turn off the OpenGL style

    remapping.

    Update: glDepthRangedNV is exposed in AMD Catalys t 13.11 betav9.2 drivers

    Also note that even though OpenGL 4.2+ specificat ion removed the note saying that the core funct ion glDepthRange

    arguments will be clamped to 0..1 range for floating-point depth buffers, implementations are apparently still allowed to

    clamp the values on use, effectively making the spec change somewhat useless. As of now the values are being

    clamped even on Nvidia, so we need to use glDepthRangedNV extension.

    There are two issues with the above described bias-less floating point OpenGL depth buffer - the lack of universal

    support, and the increased memory and bandwidth requirements in case a stencil buffer is needed.

    We can actually use the above mentioned ideallogarithmic distribution on all current hardware. First described on the

    Outerrablog - see the logarithmic depth bufferarticle. Thatcher Ulrich later came up with a slightly different version here.

    Logarithmic depth buffer technique works by outputting the desired logarithmic value from the vertex shader,

    premultiplied by the value of w, to get rid of later implicit perspective division.

    Its quite easy to implement, you just need to add the following code in the vertex shader after your normal projection

    matrix multiply:

    gl_Position.z = 2.0*log(gl_Position.w*C + 1)/log(far*C + 1) - 1;

    Logarithmic Depth Buffers

  • 8/12/2019 Maximizing Depth Buffer Range and Precision

    5/10

    7/16/2014 Outerra: Maximizing Depth Buffer Range and Precision

    http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html 5

    gl_Position.z *= gl_Position.w;

    or

    gl_Position.z = 2.0*log(gl_Position.w/near)/log(far/near) - 1;

    gl_Position.z *= gl_Position.w;

    The latter is Ulrichs variant (here referred to as N-F) that has a nice property of having a constant relative precision

    over the whole near-far range, but as well see later, nice (or symmetric) isnt always the best option.

    Obviously, the constant part (2.0/log(far*C+1)or 2.0/log(far/near), respectively) can be optimized out

    into a constant or uniform variable.

    Notice that the C variant doesnt use a near plane distance, it has it set at 0.

    This algorithm works well, providing excellent precision across the whole range with a huge reserve. But it alsosuffers on issues with long polygons close to the camera.

    The problem is that the vertex shader computed value is correct only at the vertices, but the interpolated values at

    pixels can stray from the expected value because of two factors: non-linearity of the logarithmic function between

    two depth values, and the implicit linear (and not perspective) interpolation of the depth value in the rasterizer. To fix

    it, one has to output the correct value by writing to gl_FragDepthin the fragment shader.

    While this works nicely, it has a couple of negative drawbacks - increased bandwidth from the use of

    gl_FragDepth; it also breaks depth-related optimizations etc. These issues can be addressed to some extent,

    results will depend on situation.

    To compute the exact per-pixel value of logarithmic depth one has to interpolate the depth and then compute the

    logarithm in the fragment shader. While the logarithm seems to be a reasonably fast instruction on the GPU, we canget rid of it by using a trick.

    The problem of depth interpolation appears mainly on close objects for specific reason - geometry of the objects is

    usually sufficiently tesselated only starting from a certain distance. Up close the triangles take a larger space on the

    screen, with interpolated values straying from the exact ones much more.

    If we could linearize the logarithmic curve for the region close to the camera, we can simply output the interpolant

    directly without any code in the fragment shader.

    Turns out that the C parameter in the equation can be used for that linearization. The following graph compares the

    N/F logarithmic function with the one with tunable C. N/F provides higher precision close to the near plane. However,

    thats not where we actually need a better precision - our eye cant even focus properly at those distances, theres no

    need to have sub-micrometer resolutions there.

    Getting rid of the fragment shader computation

  • 8/12/2019 Maximizing Depth Buffer Range and Precision

    6/10

    7/16/2014 Outerra: Maximizing Depth Buffer Range and Precision

    http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html 6

    By adjusting the C coefficient we can change the width of the flat part (which

    corresponds to a linear part of the depth mapping function), tuning it to the

    width we need for our scene and tesselation parameters. For C=1 the linear

    part is not deep enough to hide the zooming errors, but C=0.01 its about 10

    meters, which is enough for FPS style views.

    To use this you have to add a new output attribute to the vertex shader:

    out float logz;

    and change the post-projection code to the following:

    const float FC=1.0/log(far*C + 1);

    //logz = gl_Position.w*C + 1; //version with fragment code

    logz = log(gl_Position.w*C + 1)*FC;

    gl_Position.z = (2*logz - 1)*gl_Position.w;

    Fragment shader will then contain the matching input declaration and an assignment to gl_FragDepth:

    in float logz;

    void main() {

    //gl_FragDepth = log(logz)*CF;

    gl_FragDepth = logz;

    ...

    }

    While it doesn't seem to be boosting the performance in any significant way in comparison to the commented out

    version, it's interesting in that if we had a possibility to turn on the perspective interpolation for z (like with all other

    interpolants), we would be able to use it directly without needing to write fragment depth values. Then again, seeingthat log instruction is very fast, it could be used in the depth hardware to compute values for depth comparison

    directly. Anyway, both would likely require a change at the hardware level.

    Conservative depth

    Writing to gl_FragDepthdisables early-z optimizations, which can be a problem in certain situations.

    Logarithmic functions are monotonous, so we could use ARB_conservative_depth

    extensionto provide a hint to the driver that depth values from the fragment shader always lie below (or above) the

    interpolated value. This allows to skip shader evaluation if the fragments would be discarded.

    To use conservative depth you have to redeclare gl_FragDepthin the fragment shader:

    #extension GL_ARB_conservative_depth : enable

    layout(depth_less) out float gl_FragDepth;

    At f irst one could think that the hint to provide would be depth_greater, since a secant on the logarithmic curve

    always lies below it. But, surprisingly, the proper hint is depth_less. It's because while the value of z is being

    interpolated linearly in the rasterizer, the interpolant which we use to set gl_FragDepthis interpolated perspectively

    by interpolating p/w and 1/w linearly and getting its correct value by dividing the two. That means it's a comparison

    between:

    ((1-t)*log(A+1) + t*log(B+1));

    ((1-t)*log(A+1)/A + t*log(B+1)/B)/((1-t)/A + t/B)

    It turns out that the perspectively interpolated values go below the linearly intepolated ones.

    With depth compare GL_LESS that means the values written to gl_FragDepthcan be only closer to the camera.

    Unfortunately that's of no use for early-z rejects.

    A bit of consolation may be that in Outerra we didn't measure any speedup even with an inverted hint, even though it

    clearly showed on the geometry bugs.

    A performance comparison in Outerra. Since the terrain and grass are tesselated adaptively, they don't need writing

    depth in the fragment shader. In case of the "Logarithmic FS" column of the following tables, only the objects are

    using fragment shader that writes depth. The decrease in FPS then largely depends on the amount of screen

    (+overdraw) that's covered by the objects.

    A scene with a large area of the screen writing fragment depth. No stencil operations used. Even though the depth

    buffer format is DEPTH32F_S8, if stencil is not being used it has the same performance on Nvidia as the DEPTH32F

    format.

    Comparison

  • 8/12/2019 Maximizing Depth Buffer Range and Precision

    7/10

    7/16/2014 Outerra: Maximizing Depth Buffer Range and Precision

    http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html 7

    34 comments

    Top comments

    Add a comment as Arthur Yidi

    Posted by Brano Kemen at 20:32

    Labels: depth buffer

    Table shows frames per second.

    Reverse FPLogarithmic

    VS only

    Logarithmic

    FS

    Nvidia 460GTX

    310.5430 30

    27

    (-10%)

    AMD 7850

    12.11 b8- 48

    44

    (-8%)

    FPS, 565k triangles on objects (660k in shadow map), 356k faces terrain

    The same scene but objects taking a smaller part of the screen, with less bandwidth needed for fragment depth writes. No stencil

    operations used.

    Table shows f rames per second.

    Reverse FPLogarithmic

    VS only

    Logarithmic

    FS

    Nvidia 460GTX

    310.5432 32 32

    AMD 7850

    12.11 b8- 48 47

    FPS, 327k faces objects, 339k faces terrain, millions of grass faces

    A simple scene with water rendering using stencil. Because of the increased bandwidth needed for the depth and stencil (32b

    depth + 8b stencil), its performance goes down a bit in this Outerra scene. In other programs/cases that are fill-rate bound the

    difference can be higher.

    Table shows f rames per second.

    Nvidia 460GTX310.54

    Reverse FP LogarithmicVS only

    LogarithmicFS

    no MSAA 57 58 58

    MSAA 4x 54 56 56

    There are several ways to significantly enhance the range and precision of depth buffers, unfortunately all of them

    rely on driver and hardware support. For OpenGL the absolute minimum would be the ability to get rid of the bias

    that OpenGL pipeline applies when remapping from normalized depth coordinates to depth buffer values; right now

    it's only possible on Nvidia. It's highly likely that other vendors will be able to support it since the same mode is

    used by DirectX.

    The best option would be to implement HW support for optimal depth buffer utilization. This would allow to reducethe bandwidth needed for depth and stencil usage, since even 16 bit logarithmic buffers are able to handle planetary

    scale with perfect precision where one needs it. With a 24bit logarithmic buffer one can handle cosmic scales.The

    next best option would be the ability to enable perspective interpolation on the z component, allowing to use linear

    and logarithmic depths without a loss of performance.

    In Outerra we are currently using the logarithmic depth buffer with a couple of optimizations. Neither conservative

    depth nor the linearization seem to bring any significant performance improvements for us, but the dynamic control of

    fragment depth writes for object rendering can reclaim it back in most cases, as only the objects that are not

    tesselated enough require it. From this point of view it would be interesting to use dynamic tesselation for polygons

    that cross certain depth range threshold, but this needs to be tested yet.

    @cameni

    Conclusion

    +33 Recommend this on Google

  • 8/12/2019 Maximizing Depth Buffer Range and Precision

    8/10

    7/16/2014 Outerra: Maximizing Depth Buffer Range and Precision

    http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html 8

    Brano Kemenshared this via Google+ 1 year ago - Shared publicly

    +3 Reply

    Hmm, I suspect your w buffer implementation differs from mine, which I believe I can argue is truly

    optimal (if two fragments have different z_eye values, they will be ordered correctly.)

    Read more (13 lines)

    Walt Donovan 1 year ago

    Yes, if we could use the whole range of the floating point depth buffer directly without performance

    penalties, there would be no point in doing any of that magic. On 32-bit targets anyway. Theproblem is that the whole archaic depth buffer handling is prescribed in the spec.

    Read more

    Brano Kemen 1 year ago

    Franois-Xavier Thomas via Google+ 1 year ago - Shared publicly

    Some rendering issues are far less simple than one might think. This post has a lot of details on one of

    them : depth-buffer precision.

    +1 Reply

    Mostafa Saadshared this via Google+ 1 month ago - Shared publicly

    Reply

    Dmitri Kostenkov shared this via Google+ 1 year ago - Shared publicly

    Reply

    Liuqing Yangshared this via Google+ 1 year ago - Shared publicly

    Dmitri Kostenkov originally shared this

    Reply

    Sheila Franclvia Google+ 2 months ago - Shared publiclyin depth article, beyond my expertise

    Reply

    Walt Donovan 1 year ago - Shared publicly

    I brought up the issue with one of the nVidia driver writers, who pointed me at the

    GL_NV_depth_buffer_float extension, found here

    at http://developer.download.nvidia.com/opengl/specs/GL_NV_depth_buffer_float.txt.

    Read more

    Reply

    Actually on Nvidia it's ok, you can use the reversed (near-far swapped) normal depth buffer together

    with glDepthRangedNV to get a great precision, without needing to use gl_FragDepth and without

    losing early-z .

    Read more (11 lines)

    Brano Kemen 1 year ago

    Understood. I'll experiment with DepthBoundsdNV, and I'll continue to talk with nVidia about true w-

    buffering.

    Walt Donovan 1 year ago (edited)

    Eric Haines 8 months ago - Shared publicly

    Nice article. You and others might also

    enjoy http://www.virtualglobebook.com/Under_the_Hood_of_Virtual_Globes.pdf, pages 26-52. I

    suspect you know of it, since your work is used on page 37.

  • 8/12/2019 Maximizing Depth Buffer Range and Precision

    9/10

    7/16/2014 Outerra: Maximizing Depth Buffer Range and Precision

    http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html 9

    +2 Reply

    Thanks! Yes I know about the book, I've been asked to review the chapter.

    Brano Kemen 7 months ago

    Henrique Rocha 1 year ago (edited) - Shared publicly

    nice tutorial, what are the values that you're using for near and far? what is the radius of the planet you

    are using (6371000 meters)? What are the units?

    thank you for helping one more time ;-)

    View all 3 replies

    Reply

    +Brano Kemen

    I am having issues, if I choose a radius of 6378 it's ok, but with bigger units the camera freaks out

    (or the planet changes its position). I am using glsl 1.30. Thank you anyway, I am improoving bit by

    bit ;-)

    Henrique Rocha 1 year ago (edited)

    Sorry I had a problem with gluLookAt, basically I was adding Camera Position with Direction, a big

    vector with a small vector, somehow that was causing precision errors when rotating.

    By the way, I must thank you, this post helped me a lot.

    Keep up working, you are doing a great work ;-)

    Henrique Rocha 1 year ago

    Eric Haines 8 months ago - Shared publicly

    Oh, and one more reference (pointed out to me by Morgan

    McGuire): http://research.microsoft.com/pubs/79213/GH%202006%20p027%20Akeley%20Su.pdf

    +5 Reply

    Brano Kemen 1 year ago

    You are right, I swapped them mistakenly. But otherwise it should work, you probably have to debug it

    with some simple cases to see if it produces the right signs and values.

    Marius Dransfeld 1 year ago

    I believe it should be proj[2][2]=-1 and proj[3][2]=0, because they way you wrote z_p will always be

    calculates as -1. Either way it does not work...

    Brano Kemen 1 year ago

    With depth value from the depth buffer in range 0..1, the camera depth is: (exp(depth/FC)-1.0)/C Since

    you are using logarithmic depth, you can use projection matrix that produces camera depth in z

    component (since it's not used in shaders anymore), in OpenGL by setting proj[2][2]=0 and proj[3][2]=-1

    Make the inverse viewproj matrix from the viewproj matrix made from the view matrix and this updated

    projection matrix. Then you can simply use your existing routine to compute the worldspace position

    from uv and the camera depth computed above.

    Marius Dransfeld 1 year ago

    How can I restore the worldspace position of a pixel from screenspace position and depth ? This is

    what I use for a standard depth buffer: vec3 getPosition(in float depth, in vec2 uv){ vec4 pos = vec4(uv,

    depth, 1.0) * 2.0 - 1.0; pos = m_ViewProjectionMatrixInverse * pos; return pos.xyz / pos.w; } My

    logarithmic depth is calculated like this: logz = log(gl_Position.w * C + 1.0) * FC; gl_Position.z = (2.0 *

    logz - 1.0) * gl_Position.w;

    someone 1 year ago

    Thanks! I`ll try it out

  • 8/12/2019 Maximizing Depth Buffer Range and Precision

    10/10

    7/16/2014 Outerra: Maximizing Depth Buffer Range and Precision

    h // bl /2012/11/ i i i d h b ff d h l 10

    Newer Post Older PostHome

    Subscribe to: Post Comments (Atom)

    Show more

    Brano Kemen 1 year ago

    If you are NV-only and no stencil, the best thing would be to use the reverse floating point depth buffer.

    You are safe from depth artifacts that way, and performance-wise it's almost the same as with the

    logarithmic 24b depth. To use the reverse FP depth buffer in OpenGL, you need to: - use FP32 depth

    buffer format - call glDepthRangedNV(-1,+1) - use the DX-like matrix from 'DirectX vs. OpenGL' part of

    the article, together with GL_LESS depth func (the matrix can be also modified to invert the mapping to

    use GL_GREATER) No modification to gl_Position is done here in this case, you just use the matrix in

    normal way.

    someone 1 year ago

    Thanks for detailed explanation! So for now, the best solution for NVonly users would be: 0. use FP32 or

    D24\D32 depth buffer? 1. call glDepthRangedNV with -1,+1 2a. override z in VS as gl_Position.z =

    2.0*log(gl_Position.w*C + 1)/log(far*C + 1) - 1; or 2b. draw with projection matrix you 've specified in

    'DirectX vs. OpenGL' part of your article; invert depth test to GL_GREATER\GL_GEQUAL; override z in

    VS as gl_Position.z = 2.0*log(gl_Position.z*C + 1)/log(far*C + 1) - 1; 3. gl_Position.z *= gl_Position.w;

    Just don't understand which combination would be best possible on NV hardware (stencil is not used at

    all)... Would you give an advice for this case, please? Thanks!

    Brano Kemen 1 year ago

    When you use a normal projection matrix in OpenGL, gl_Position.w comes out as a positive depth from

    the camera, whereas gl_Position.z contains something expressible as a*z+b, what after perspective

    division by w falls into -1..1 range. Since the logarithmic equation needs the depth from the camera, I'm

    using w there, otherwise I'd have to use a modified projection matrix where z comes out as the depth.

    Being able to use an unchanged projection matrix makes it simpler to switch to the reverse floatingpoint depth mode.

    someone 1 year ago

    Why you are using gl_Position.w when overriding gl_Position.z? gl_Position.z = 2.0*log(gl_Position.w*C

    + 1)/log(far*C + 1) - 1; i thought it should be gl_Position.z = 2.0*log(gl_Position.z*C + 1)/log(far*C + 1) - 1;

    Correct me if i`m wrong, please

    Brano Kemen 1 year ago

    The inverse is ok, either: z = (exp(d*log(C*far+1)) - 1)/C or z = (pow(C*far+1,d)-1)/C z is the viewspace

    depth already, screenspace x and y need to be multiplied by z first and then by the projection inverse

    (but just x and y, since z is right already)

    Post a Comment

    Awesome Inc. template. Powered by Blogger.


Recommended