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: 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.
- Any advise? Did I done something wrong?
- 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?
- Wiki says that except format there can be specified "readable", like { format="depth24", readable=true }. What is that?
- In my example I clear 2 canvases with love.graphics.clear() correctly, but how to clear depth buffer also? I tried something like
with no visible effect
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)
- When setting draw target I use this:
which looks correct by the wiki, but when I try that instead:
Code: Select all
love.graphics.setCanvas({ canvas1, canvas2, depthstencil = depth })
it also works 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...Code: Select all
love.graphics.setCanvas({ canvas1, canvas2, depth = depth })
- In example I am using
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?
Code: Select all
love.graphics.setDepthMode("less", true)
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