In my 2D pixel art game, when you kill the other characters, the blood splats come out as sprites and I want to “paste” them onto a background layer so they build up over time. Essentially painting onto a canvas using a sprite image as a brush.
I think in both Godot and Unity I had to manually do this by accessing the sprite’s texture and getting the right pixels for that sprite frame and plotting them to an Image object which had a feature to “Update” which would push that data to the GPU and replace an existing texture, whenever I want to update it. For my game there’s no scrolling, so I just need one giant transparent image that overlays the whole screen and will be the “canvas” that the blood splats are pasted onto.
Possibly I didn’t look hard enough but I was having trouble finding something like this in the documentation.
Sound like you could solve this by drawing the blood sprites using a different predicate onto a render target which you never clear and then draw the render target to a quad.
Here’s where I’m a bit uncertain how to proceed. @britzl you said I could render to a quad - but can’t I render to the existing surface by overlaying my offscreen buffer?
I’ve inserted my attempt to render, just after sprites render:
Nothing shows up. I’ve attached a little white sprite to the main character as a test, using the material with the “test” flag, and because I never clear this buffer, I’m expecting it to streak along the screen, but it never renders at all.
Wait, so you render this white little sprite to the render target. But what do you do with the render target afterwards? Are you drawing it to something? If not, then that explains why you don’t see anything. You need to draw your render target / canvas somewhere to actually see it.
Think of a render target as a separate canvas or area where you can draw stuff. In Defold there is a default render target where everything is drawn to (using render.draw()), unless you specifically tell the render script to use a different render target (using render.set_render_target()).
Now imagine that you point a camera at the default canvas and watch the canvas through the lens of the camera. If I take a paint brush, go up to the canvas and draw something on it you’ll immediately see it through the lens of the camera right?
But if I walk up to a second canvas that is offscreen and draw something on it then you’ll not see that since you are watching the default canvas through the lens of the camera. In order for you to see what I drew on the offscreen canvas I need to take a polaroid camera, snap a picture, and put it somewhere on the default canvas for you to see. Right?
It sounds like you are drawing to that offscreen render target, but never put the result somewhere on the default render target. Drawing the offscreen render target to a quad or a sprite is the analog of the polaroid picture I mentioned above.
Thank you, I appreciate the explanation. I understand the concept of needing to paste my “canvas” back into the main canvas, i just wasnt sure of how that is done. I thought where I put the code it might do that, but now I see (especially after you re-emphasising set_render_target for me) that I’ve set the render target to my canvas and drawn on it, and then set the target back to default canvas. I still need to put my canvas back onto the default canvas.
So if I understand correctly:
If put it on a sprite, it should get collected up in the usual pipeline when it renders the “tile” predicate, so I should make sure I draw to my canvas before that so its not one frame behind.
I remember seeing code for updating the texture of a sprite so I’ll look into that as well as the post processing example.
Ok I’ve got a sprite that covers the whole screen already (I was using it for the drawpixels add-on).
Just having trouble working out how to set my off-screen buffer onto that sprite’s texture. Or, send a texture handle to the render script for it to use as the off-screen buffer instead, what ever is easier.
You start by enabling the render target as the texture in slot 0 and then draw with a predicate that matches the tag you have on the material on your quad or sprite:
Open the above example in Defold and study the material on the quad to get an understanding of the final step.
Thank you for directing me to that. If I understand it correctly, I think my problem is one step before that; I have a full screen sprite “blood canvas” with a blank 512x512 texture (as part of working with drawpixels) and it uses the normal sprite material, so whatever is on it will end up on the screen whenever sprites are rendered (“tile” predicate).
But I can’t work out how to make the “blood canvas” sprite use my off-screen buffer as its texture, instead of it’s own texture from the resources.
Here’s what I’ve got so far, and my missing step, please let me know if my understanding is correct:
I’ve got a full screen sprite “blood canvas” using a 512x512 texture, it uses the default sprite material (tag “tile”)
My little white test sprite uses it’s own “sprite test” material - a copy of the default sprite material, with tag “test” added, tag “tile” removed - it no longer renders to the default output
In render script init(), an off screen render target is created, called “blood rt”
in render script update(), it sets the render target to be my off screen buffer “blood rt”
I draw predicate “test”, my white sprite should end up being drawn to “blood rt”
MISSING STEP - how does the “blood canvas” sprite use the contents of “blood rt” as its texture?
I switch back to default render target - and my “blood canvas” sprite should get rendered along with the other sprites when predicate “tile” gets rendered.
@AGulev informed me this can only be done on meshes, not sprites yet (there’s even a feature request for it here). So I must follow the post processing example.
Ok I got it working. Using the example from the article “Mastering Render Targets” was extremely helpful in breaking down what I needed to do to get it working.
I just need to add some more functionality to it and I’ll do a tutorial on “pasting sprites to the background” for the Defold Mine.
In the below clip, I’m toggling the canvas on and off with a key press, to show it’s a separate layer.