I have a script that generates a texture3D at the start of the game. This texture3D am I using for a VFX made with VFX graph. Now I want to make some interactions that shall change this VFX by manipulating the texture3D it uses. For example changing the pixels of that specific texture3D. Is that in general possible while the VFX is still active? I think it should be possible when I turn the VFX off, regenerate the texture and then restart the VFX with the new texture3D, but I somehow want to prevent that.
I guess its not possible because as long as the VFX is active, the texture3D file is opend and therefore blocked for manipulation by a running program. is that right?
Or does anybody have an Idea for me?
Not sure I understood your problem, but lets say there is texture and you use pixels to set particle positions when spawned. If you want to update position of these particles you can either recreate whole thing as you said or update them every frame.
In the first case, no, there is no such thing as “file is open”, or rather not in the way you described it. Texture exists inside GPU memory and CPU pointer if you check read/write. In any case you can modify this texture (memory) by script (set pixels + apply or modify nativearray) or by compute shaders, but even if you do it those spawned particles are not going to change if you only sampled it inside initialize - you would need to respawn everything.
In the second case you can use update context and set their positions every frame, so any changes to texture will be reflected instantly, but obviously it’s more costly than doing nothing.
Hi Qriva, I think you understood correctly what I am using the texture for, but I am not sure about the part with the manipulation of the texture. I am using the texture3D file format as a data storage that defines different instances of the appearance of the VFX dependent on user input that can change in runtime of the VFX. That what I want to do now is either to completely overwrite this texture file with new data or replace it with an other one.
I have an update function that recreates the texture, which I also can run but it does not refresh my VFX. When I stop testing the VFX and I return into Unitys edit mode, I see that the texture has changed. But even the changes are represented in the scene view in the way I expect them to be, the texture symbol in the Project Manager is broken and the preview window stays empty. And yes I am also using the update part of the Particle System.
But I think my problem is explained by what you mentioned with the GPU memory. I think that when I start the VFX, my texture will be loaded into the GPU memory. When I then recreate my texture, this newly created texture exists only outside the GPU memory, so I would need something that refreshes the GPU memory with that new texture data.
Well, it’s hard to say anything as you didn’t attach any code.
It depends what you mean by recreate texture, in my case I actually mean to modify texture, not create new object. Also if you use the same texture in some shader to display it on screen and it changes correctly then it means GPU has is correctly loaded, otherwise it would not be possible to display it. Maybe graph has wrong pointer to that texture.
ok my code for the texture generation looks like this:
public class TextureGen : MonoBehaviour
{
int regen = 0;
void CreateTexture3D(int x = 1, int y = 1, int z = 1)
{
TextureFormat format = TextureFormat.RGBA32;
TextureWrapMode wrapMode = TextureWrapMode.Clamp;
FilterMode filterMode = FilterMode.Point;
Texture3D texture = new Texture3D(x, y, z, format, false);
texture.wrapMode = wrapMode;
texture.filterMode = filterMode;
Color colors = new Color[x * y * z];
// some code filling my array “colors” with data
In the game I make some manual changes on some input parameters which then changes the filling process of the array “colors”. and then I start the update with setting the parameter “regen” to 1 in the inspector.
I am aware that the way I am handling the update function is not the proper way, but I don’t see a reason why it should not work just for a trial.
Please use code tags.
You are not updating the texture content, you create new one every frame. What I mean is to do something like this:
public Texture3D texture;
private void Awake()
{
// Create texture only once
texture = new Texture3D(x, y, z, format, false);
// [...]
}
private void Update()
{
// Retrieve pixels
Color[] pixels = texture.GetPixels();
// Modify returned array in any way you like
// [...]
// Update texture data
texture.SetPixels(pixels);
// Update GPU
texture.Apply();
// Even better alternative way to modify texture via script is to modify texture data directly
//Unity.Collections.NativeArray<Color> flattenedTextureData = texture.GetPixelData<Color>(0);
}
* not tested code
If you set this texture in vfx graph it will be updated automaticaly because pointer to memory does not change.
Also if you create texture in runtime there is no need, or probably even not desired to save this texture in asset database.
That is exactly what texture.Apply() does.
In the end the texture is just a huge 1D array with a 3d accessing pattern, so there is no reason it shouldn’t work. You could theoretically also use SetVectorArray to set such an array but Texture3D is a really convienent data container
Qriva’s example is exactly like I would do it too.
Thanks a lot, that’s very helpful. I think I got what you mean. I implemented it, but it seems to work only when I have the VFX Graph editor window opened while I am testing. otherwise the texture on my object is not refreshed. Did I forget a setting somewhere in my particle system?
Edit:
To be honest, I didn’t get that part with the asset that does not need to be generated, so I am make an asset, but thank to your input, I am only creating it once. But I dont know how to reference a texture to the VFX graph since in your way it only exist on runtime. Like that there is no texture existing that I somehow could reference by drag&drop/dropdownSelect in the VFX graph editor paramater:
You don’t do it in inspector, you should do it with script. You need reference to this component and as this texture is public field you have acces to it, or you can set it directly from the same script. To set it use SetTexture function.
I finally found some time to comeback to this problem and I could find the troubles cause. it was a List that I wasn’t clearing and so I added the data behind the existing data. Like that I was overriding my texture3D always with the same content (first X List entries…).
besides of that, your hint about not making an asset all the time was also very helpfull to better understand what an asset actually is. And finally your texture.SetPixels() hint helped me to correct my mistake of the asset creation, even though I’m not using the texture.GetPixels() command before. I guess since I’m creating the Color array anyway in the same size, that command is not needed.
I’m happy that my VFX now works how it’s meant to work. Thanks a lot again.