Procedural ParticleSystem Shape Texture not Working

Hi all,

I’m trying to get my particles to render and clip from a procedural texture mask.

Double-clicking to make sure it’s the right texture, I see the following, which looks about right.

It’s just a Texture2D via…

Graphics.CopyTexture(renderTexture, texture);

Where renderTexture is a CustomRenderTexture, with the following settings.

If I use a regular texture from Photoshop, it works just fine (settings for that seen below).

Any idea on what I may be doing wrong? My particles are neither clipped nor coloured from the generated clip mask Texture2D, but it works if I use a pre-rendered Texture2D.

Can’t see anything blatantly wrong but I will say that

Graphics.CopyTexture(renderTexture, texture);

is a bit of a strange thing to do. Usually, you’d use the render texture directly (assign the render texture to the material).

If you do want to do this, take a RenderDoc capture and see what’s going on. Also check the RenderDoc warnings tab.

My guess is that copying from RenderTexture to Texture2D doesn’t actually get the pixel data onto the CPU, which is where the particle system needs it. Probably you just end up with GPU data. Might need to call GetPixels or something to read it back into the cpu cache of the Texture2D. Google may be able to help with the specifics of how to do this - sorry I’m not sure.

(code monkey, the copy is because the particle system can’t use render textures, due to wanting the data on the cpu)

Eg this thread discusses that you may need to use ReadPixels. But beware - this will be really slow! RenderTexture to Texture2D too slow?!

The efficient solution here is to use Visual Effect Graph, if you can, because then everything will be happening on the GPU with no need to copy back to the CPU.

Hi all,

First off, thanks for the responses.

Actually, I do already have ReadPixels in my code as well (switching based on a RTToTexture support check), but ended up with the same results (and issue) when I was testing to see if that made a difference.

Speed won’t be an issue in my use-case (well, hasn’t been so far), and I can use a much smaller texture if that would help. I’m trying to dynamically control the mask and was hoping to avoid something like a hacked-in flipbook, as that would force me to pre-render the mask animation rather than a CustomRenderTexture shader.

Unfortunately, this project is in the built-in pipeline, so VFX Graph is a no-go for me.

@richardkettlewell , any other ideas?

I’m willing to sacrifice some performance to keep this within the context of Shuriken.
If not, as a last resort, I’ll move the demo to URP just to see what’s possible.

By the way, this seems like a “bug” of sorts if there’s no warning to indicate why things aren’t working, despite everything in the editor being okay.

Nothing else springs to mind :frowning:

If you were able to submit a bug report with an example project, mentioning me/this thread, QA will process it and make sure it reaches me. Then I could debug it to be sure what’s gone wrong.

To be sure, you’re doing this?

It would also be interesting to call GetPixels and see if that gives you what you expect…

Yes, I’m certain I’m doing that. :frowning:

Start:
8356137--1099788--upload_2022-8-11_17-46-18.png

Coroutine WaitForEndOfFrame:
8356137--1099791--upload_2022-8-11_17-46-29.png

I can see the mask change as I adjust the custom render texture material, so it’s working on that front.

— UPDATE (while I was writing this post, before even submitting…) —

It’s working now!

I did some more tests, and moving the shape.texture assign to after the texture.Apply() every frame resolved the issue. Note in the screencap above I correctly assigned it after creating a new texture, but this was once in Start.

So in the editor, the texture still updated on the particle system shape module whenever I double-clicked it, indicating it was updating as expected, but internally in the PS I’m assuming it’s not actually checking for the updated data.

8356137--1099794--upload_2022-8-11_17-47-16.png

Here’s a video of the above code to show what I mean.

You’ll see the tiny red texture preview in the Shape module’s Texture slot update as I move the slider, which I confirm by clicking through. The method being used (CopyTexture/ReadPixels) shows in the console. Until I reassign every frame, ReadPixels doesn’t work.

https://www.youtube.com/watch?v=J9tHdyePS8k

@richardkettlewell , I’ll make that bug report with a reference to this thread as you suggested. Thanks again. :slight_smile:

For reference, here’s the effect I’m trying to improve using this technique in BiRP. Right now the particles won’t clip in the areas where there’s no opacity. Using a custom render texture I can force them to emit correctly as the effect would scroll using a slider.

https://www.youtube.com/watch?v=Y7T3T7-4EAY

Summary: Graphics.CopyTexture doesn’t work, but Texture.ReadPixels does so long as I reassign the texture to the shape module after every texture.Apply(). If this is the expected behaviour, it’s not clear because the editor shows the texture updating.

Great write-up, thanks!

I will take a look at this when the bug report reaches me.

My gut feeling is that the order of the assign/Apply shouldn’t matter (Ie you found a bug) Maybe we cache the pixel data when the texture is assigned. So it misses the changes done by the Apply. but I wonder if there is a way for us to detect that the cached pixel data is dirty. In theory you should only need to assign once, and then any calls to Apply with new data should be picked up. Whether there is a way for me to detect this… I’m not sure :slight_smile: but I’ll look into it!

Thanks again!

PS. I’ve seen quite a bit of your Shuriken content online over the years. It’s some of the best! That dissolve effect is great too!

That’s amazing to hear, thank you. :slight_smile:
Also just found this , which seems to be the same issue.

Submitted the bug report: IN-13902.

Good news - I was able to fix this. It’ll probably only go into Unity 2023 though, as it’s a minor issue and not a regression.
(Please let me know if that’s a problem and I can try to get backports)

Thanks again for reporting it!

Forgot to reply to this. It’s not an issue since there’s a workaround available (assign every frame). Thank you!