Godot 4 update
Opened this issue · 14 comments
Would it be possible to convert this to Godot 4?
I was hoping to adapt this to a 3D scene using Sprite3Ds. This seems like my best shot since Godot lacks a clip + draw feature on Sprite3Ds/stencil buffer support.
As a user fairly new to Godot, I've had some significant issues in trying to get everything working. With minimal knowledge I can get the scene running but only after breaking functionality.
Thanks
Getting this to work in Godot 4 shouldn’t be too much of a problem but I am unsure how it would apply to a 3D scene. If you could provide an example of what you’re trying to achieve that may help me figure out if it is possible or not.
Thank's for the reply! I have an image that also contains a diagram of what I'm trying to achieve.
Here's the copy+pasted text from a reddit post I just made on this:
"Hoping to be able to mask a GPUParticles2D with a Sprite3D. The Sprite3D will be animated so an efficient method would be great (hoping not to have to do anything manually for each frame as I will have a lot of different animations for lots of characters).
(One thing that I like about the Sprite3D that points to the SubViewport is that the particles can be 'shaded' and affected by light sources. I'd like to retain this if possible).
Not sure whether this is a job for a shader or some other method."
I'm fairly sure that this probably isn't the most efficient way to address my issue but pretty much everything else that I've tried has failed over the past couple of days.
Thanks again for taking the time to read this.
I don't believe that my method of masking stuff translates very well into a mixture of 3D and 2D but I'll have to think about it some more. In any case what your trying to achieve I'd do by putting the Sprite2D+GPUParticles2D inside the SubViewport and then assigning the SubViewport texture to the Sprite3D. I have an example if you want, but it should be simple enough for you to setup and try. Hopefully that does what you want.
Thank you for this. Funnily enough, that's exactly what I've done, which results in an issue where setting the Sprite2D to 'Clip Only' results in an opaque 'background'. Here are some screenshots of that 'shaded' and 'unshaded'. (If I could get the background to be transparent and have the particles be shaded, everything would be perfect)
I'm afraid that's as far as I've been able to get so far.
Thanks so much for testing this and showing me. That's exactly how I've got mine set up (and also Forward+ to be clear) which has now clued to me into the fact that there's something less obvious causing the issue.
I have to head off for the night but if you have the project file still open, would you mind emailing a .zip across to me so I can compare settings etc.?
(edited to remove email address)
No worries if not. Thanks so much again for looking into this for me! I'll check back in tomorrow.
Here's the zip file for my test project: TestMask GD4.2.1.zip
There are two scenes the "main.tscn" is working on my end, while "main-broken.tscn" gives the same results you indicate above.
Thank you so much. I'll check this out ASAP tomorrow and I'll certainly let you know if I find out what the issue was.
Thanks again for the project and for taking a look at this. I took a look at it and realised this actually has the same issue that I do.
So in the TestMask scene that you sent, we see both the Sprite2D and the particles as it's set to Clip + Draw. That's not what I need to happen unfortunately.
My Sprite2D looks much worse than my Sprite3D due to my (aesthetically necessary in my project) use of a StandardMaterial3D shader on the Sprite3D with a normal map enabled as well as other material changes.
So when (in both our projects) Clip Only is set instead on the Sprite2D, we now see particles on black... in the shape of the Sprite2D.
I need the Sprite2D to just mask the particles like an alpha but not to be displayed in any way itself.
So the intended result would be to see my Sprite3D and then the shaded particles over it masked to the same shape.
In my project (that doesn't work), I have my intended Sprite3D and then everything you have in your project is a child of that.
I didn't realize you were applying other effects with StandardMaterial3D in which case my method doesn't work as you found out. The issue with masked objects and transparency appears to be a known issue on the Godot issue tracker but there doesn't seem to be a fix for it yet.
In any case check out this project: TestMask.zip
I'm masking the particles using a VisualShader Material Override on a Sprite3D. The shader accepts two textures, the mask and the SubViewport texture (which would be providing the particle effect). The mask texture (called sprite_texture
) is automatically assigned from the Sprite3D texture via a tool script attached to it. You could forgo the tool script but then you will have to manually keep the shader sprite_texture
and the Sprite3D texture
updated and matching to keep everything aligned. This all works with a static character but once it is animated things may not be quite as easy.
Thanks again so much for your help on this.
This seems like it will be great for some static objects in my project. I'll try it out myself over the next hour!
The aim of this effect was predominantly for a main player character and NPCs with lots of animations. Animations also were throwing a spanner in the works for other workaround methods I was trying.
Another method I discovered that 'works' albeit without shaded particles but with animations is to use the Sprite2D clip masking method we used before... except the Sprite2D's sprite-sheet is a copy of the main Sprite3D's at 50% transparancy (via GIMP).
This works better than it may sound and retains the detail of the StandardMaterial3D on the Sprite3D.
Drawbacks are as follows:
- Unshaded particles
- Darkens the Sprite3D a little, (although this is easy to bump back up)
A solution that is shaded and with animations seems to be really elusive!
(The instructions you gave for your new method are great. I'll let you know how I get on with this shortly. Thank you.)
I thought I'd just check back in after giving the method from the latest project you sent a go.
Fantastic work!
The only thing that needed changing was to set the render priority on the ShaderSprite3D's material override to 1 (or at least anything higher than the render priority of the Sprite3D that it's a child of).
I have a follow-up question about animation if you don't mind,
I thought I'd try animation to see where the problem lied for myself. I animated the Sprite3D Base with no issue.
For the ShaderSprite3D (Sprite3D Masked Particles), I gave it its own animation player and added to the script to play an animation (matching the one from the other animation player) but that doesn't seem to be working. No errors but it isn't updating the animation (or at least the mask effect) 'in-game'.
I know you said that once it was animated, things may not be so easy and I presume this is the problem you were referring to?
If it helps, here's the updated project file:
TestMask Animated.zip
(I've swapped out the sprite for a spritesheet from Diablo II using the frames 0-7).
Do you have any thoughts on how/why animation may be an issue for the ShaderSprite3D? It's of course, very possible that I've simply overlooked something.
Please ask if there's anything you'd like to know if it saves time rather than digging through the project.
Thanks again
Edit:
As the 'sprite_texture' in the visual shader has no animation capability, this appears to be the issue. I assume that this needs to be extended somehow and my use of the AnimationPlayer on the ShaderSprite3D is pointless/redundant?
If you have any thoughts on how this may be achieved, I'd love to hear.
I don’t have access to a computer at the moment but as far as I know this issue is because we are using a shader. Because of this shader we are accessing the texture directly, bypassing the Godot default rendering. If I recall correctly some of the sprite3d options such as double sided render and such also stop working. I believe Godot uses a default shader to do the sprite sheet offsets to draw the correct frame and when you do a custom shader all that goes missing. However this is all an assumption at this point. If I am correct then you might be able to manually reimplement the missing features in the shader, possibly by copying them from the Godot source. Hope that helps somewhat.
Thanks, this all makes sense. Perhaps a bit ambitious to be adding features to Godot only a few weeks into using it but that's definitely something I'll consider looking into.
As a side note, I've realised that your shader method could even be used (with an orthographic camera view) to overlay particles onto non-rotating 3D objects with a sprite representative of the model's orthogonal shape and by setting the Sprite3D Base's modulate alpha to 0. Really cool.
Thanks again for your help. If I have success extending the animation functionality in the shader, I'll let you know. If there's a more appropriate way to do that than here, feel free to let me know.
Cheers