[Solved] Depth test understanding

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
Sasha264
Party member
Posts: 131
Joined: Mon Sep 08, 2014 7:57 am

[Solved] Depth test understanding

Post by Sasha264 »

Good day! :3

I am trying to implement strict sprite appear ordering while keep them draw-order independent with the help of depth test. I watched some examples here and there, and wrote a simple playground for that, looks like it works, but I did it for the first time, and I need a review, did I get it right? Also I have a ton of small questions which I couldn't find on wiki or forum.

Here is expected result, brighter rings go on top of darker ones while they are drawn in random order:
result.png
result.png (108.37 KiB) Viewed 1188 times
Here is my example (just one main.lua file):

Code: Select all

local canvas1
local canvas2
local image
local shader
local depth

function love.load()
    love.window.setMode(1700, 900, { resizable = false, vsync = true, borderless = false })

    canvas1 = love.graphics.newCanvas(700, 700, { format = "rgba8" })
    canvas2 = love.graphics.newCanvas(700, 700, { format = "rgba8" })
    depth = love.graphics.newCanvas(700, 700, { format = "depth16" })
    image = love.graphics.newImage(love.image.newImageData(100, 100))

    shader = love.graphics.newShader([[
        extern float z;
        extern vec3 color;
        void effect() {
            float dist = distance(VaryingTexCoord.xy, vec2(0.5));
            if (dist > 0.5 || dist < 0.3) discard;
            gl_FragDepth = 1.0 - z;
            love_Canvases[0] = vec4(vec3(z) * color.rgb, 1.0);
            love_Canvases[1] = vec4(vec3(z) * color.bgr, 1.0);
        }
    ]])
end

function love.update(dt)
    love.window.setTitle(love.timer.getFPS())
    if love.keyboard.isDown("escape") then
        love.event.quit()
    end
end

function love.draw()
    love.graphics.setCanvas({ canvas1, canvas2, depthstencil = depth })
    love.graphics.clear({ 0.2, 0.4, 0.4, 1.0 }, { 0.4, 0.2, 0.2, 1.0 })
    love.graphics.setDepthMode("less", true)
    love.math.setRandomSeed(0)
    love.graphics.setShader(shader)
    shader:send("color", { 1.0, 0.8, 0.6 })
    for i = 1, 99 do
        shader:send("z", love.math.random())
        love.graphics.draw(image, love.math.random() * 600, love.math.random() * 600)
    end

    love.graphics.setCanvas()
    love.graphics.setShader()
    love.graphics.clear(0.2, 0.2, 0.2, 1.0)
    love.graphics.draw(canvas1, 100, 100)
    love.graphics.draw(canvas2, 900, 100)
end
  • For code simplicity all numbers are hardcoded.
  • Actually I am trying to draw images, but here in order to keep all in one simple file I replaced .png with simple shader that just draw colored rings from dummy image with unimportant content.
  • I understand that with that approach I can handle only full transparent pixels, not half transparent.
  • My example draw to 2 canvases simultaneously, that is key feature that I need, so I tested it here as well. One draw call, two canvases, one depth buffer.
  • Often z-buffer / depth-buffer examples contain vertex shader, meshes, z-depth interpolation from vertices to fragments, etc. Which is common for 3d cases. I don't need that, because for each sprite I know exactly its depth value, and it is constant, so here I used only fragment shader.
  • I want separately created depth buffer, not default fullscreen buffer. Because that way I can change its dimentions as I want.
So, the questions:
  1. Any advise? Did I done something wrong?
  2. What about format of depth buffer? Here I used depth16 because I thought that it is enough for my purposes. But is it safe? Can there be a system that only supports depth24, or some other caveats?
  3. Wiki says that except format there can be specified "readable", like { format="depth24", readable=true }. What is that?
  4. In my example I clear 2 canvases with love.graphics.clear() correctly, but how to clear depth buffer also? I tried something like

    Code: Select all

    love.graphics.clear({ 0.2, 0.4, 0.4, 1.0 }, { 0.4, 0.2, 0.2, 1.0 }, 0.5, 0.5)
    with no visible effect :cry:
  5. When setting draw target I use this:

    Code: Select all

    love.graphics.setCanvas({ canvas1, canvas2, depthstencil = depth })
    which looks correct by the wiki, but when I try that instead:

    Code: Select all

    love.graphics.setCanvas({ canvas1, canvas2, depth = depth })
    it also works :crazy: How? What is happening? Wiki says that name "depth" is supposed to be boolean. So, my depth buffer works like just "big true boolean value", and actually program uses another internal fullscreen depth buffer, or what? What format that buffer have? I never specified one...
  6. In example I am using

    Code: Select all

    love.graphics.setDepthMode("less", true)
    Looks like it works. But I can not get any results with different CompareMode, like "greater". Maybe because I failed to clear depth buffer with 1.0 instead of 0.0, maybe something else?
Wiki links:
https://love2d.org/wiki/love.graphics.setCanvas
https://love2d.org/wiki/love.graphics.setDepthMode
https://love2d.org/wiki/CompareMode
https://love2d.org/wiki/PixelFormat
https://love2d.org/wiki/love.graphics.clear
Last edited by Sasha264 on Sat Jan 14, 2023 6:18 pm, edited 1 time in total.
User avatar
pgimeno
Party member
Posts: 3691
Joined: Sun Oct 18, 2015 2:58 pm

Re: Depth test understanding

Post by pgimeno »

Sasha264 wrote: Fri Jan 13, 2023 4:01 pm
  1. Any advise? Did I done something wrong?
  2. What about format of depth buffer? Here I used depth16 because I thought that it is enough for my purposes. But is it safe? Can there be a system that only supports depth24, or some other caveats?
  3. Wiki says that except format there can be specified "readable", like { format="depth24", readable=true }. What is that?
  4. In my example I clear 2 canvases with love.graphics.clear() correctly, but how to clear depth buffer also? I tried something like

    Code: Select all

    love.graphics.clear({ 0.2, 0.4, 0.4, 1.0 }, { 0.4, 0.2, 0.2, 1.0 }, 0.5, 0.5)
    with no visible effect :cry:
  5. When setting draw target I use this:

    Code: Select all

    love.graphics.setCanvas({ canvas1, canvas2, depthstencil = depth })
    which looks correct by the wiki, but when I try that instead:

    Code: Select all

    love.graphics.setCanvas({ canvas1, canvas2, depth = depth })
    it also works :crazy: How? What is happening? Wiki says that name "depth" is supposed to be boolean. So, my depth buffer works like just "big true boolean value", and actually program uses another internal fullscreen depth buffer, or what? What format that buffer have? I never specified one...
  6. In example I am using

    Code: Select all

    love.graphics.setDepthMode("less", true)
    Looks like it works. But I can not get any results with different CompareMode, like "greater". Maybe because I failed to clear depth buffer with 1.0 instead of 0.0, maybe something else?
1. No idea.
2. Only you can know if 65536 depth levels are enough in your application.
3. I think readable means that shaders can read its contents, but don't quote me on that. For depth testing the way you're using it, I don't think you need it. I think effects like fog may need to read from the depth buffer.
4. Works for me. Only half of the circles are drawn. The darkest/black ones aren't drawn.
5. Maybe, I don't know.
6. Works for me with these changes:
- In the shader, use z instead of 1.0 - z (to keep the same sort order).
- In love.graphics.clear, add "..., false, 0)" (there's no stencil, so I set it to false).
- Change the depth test to "greater".
- After disabling the canvas and the shader, add love.graphics.setDepthMode("always", false) so that depth comparison is disabled when drawing the canvases to the screen.
User avatar
Sasha264
Party member
Posts: 131
Joined: Mon Sep 08, 2014 7:57 am

Re: Depth test understanding

Post by Sasha264 »

pgimeno wrote: Fri Jan 13, 2023 5:28 pm 4. & 6.
Yes, now it works for me too... (-_-)" :ultrahappy:
pgimeno wrote: Fri Jan 13, 2023 5:28 pm - After disabling the canvas and the shader, add love.graphics.setDepthMode("always", false) so that depth comparison is disabled when drawing the canvases to the screen.
!! :o That I definitely missed.

Thank you!
Now I have more confidence, and going to embed this in real game =)
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 8 guests