Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Suggestion / Idea  (Solved) UserData Indices - 4 is not enough, I want 16
#1
I would like more than 4 channels of UserData.

My Slime Player Character quickly filled up the 4 userdata with:
Motivation: Solid surfaces write 1, Air 0, values dilute to 0, such that only particles near the surface can move, with some moving in desired direction, and some "pushing back" against the surface
Bigness: Each square cell of fluid writes a factor of it's Mass to the particle at the center, which then dilutes outwards. Bigger slime sticks more, smaller slime drops slide off stuff.
Stranded: Particles "Inside" write 1, otherwise sharply dilute to 0. Particles on edge of big-enough slimes hover around 0.7 value, Particles on edge that is a "thin strand of slime" drop to 0.1, and are killed, so that thin strands do not awkwardly hold together large Blobs of Slime, or wrap around edges of objects and prevent Slime Splitting
Teams: An Orange/Blue "Team Signal" writes 0 or 1 to nearest particles, and particles near 0 or 1 Teamness accept input from either "Player 1" or "Player 2", with values around 0.5 being an idle grey that get no input

Workaround?
I can imagine an awful Workaround to the 4-channel limit, by creating one set of intangible "Zombie" Fluid per extra 4 Channels I want. It would copy Position and Velocity, and dilute fluid, and any of my calls to GetUserData(particleIndex, dataIndex) would would send dataIndex 0-3 to "real" Slime, and dataIndices 4-15 to any of the "Zombie" slimes. My need for more UserData has not reached the point to attempt such a disgusting (and probably grossly computationally wasteful) solution.

If Implemented
More UserData would allow me to allocate 2-3 channels to "Team", allowing 4-8 individually-controlled regions of Slime, instead of 2. I could add 1 for Temperature, 1 for Digestion/Energy, a few for Harmful Chemicals. I would especially like to allocate 2 channels to "Applied Forces on x/y axis" such that I can use diffusion to get more "Equal and Opposite Forces", ie applying additional braking where I notice "500 Force magnitude on a particle last frame"

From: Multiple user data and more flexible diffuse

(18-11-2021, 09:44 AM)josemendez Wrote: FYI, the reason why there's only 4 user data channels is because 4 is the length of the SIMD registers used to perform vector operations. This means operating with pairs of user data with 4 components is very efficient. In addition to this we know the data for particle n is at n*4 in the data arrays, making memory access efficient too. Using a variable size for the amount of user data channels would make both accessing the data and operating with it considerably less efficient.

Is there some Compile-Time #pragma technique, locked at runtime, that would maintain performance for 99% of users who stick to 4 channels of UserData?


Type of UserData changing from ObiNativeListVector4 to Vector8, Vector12, Vector16 sounds hairy already. I don't know how it would be implemented.
Adding a 1-4 int picker to ObiFluidEmitterBlueprint is probably totally insufficient, it has to be project-wide, for all fluids, right?

short text message to appease the scripts


Attached Files Thumbnail(s)
                   
Reply
#2
(09-09-2022, 07:32 PM)nanimo(null) Wrote: I would like more than 4 channels of UserData.

My Slime Player Character quickly filled up the 4 userdata with:
Motivation: Solid surfaces write 1, Air 0, values dilute to 0, such that only particles near the surface can move, with some moving in desired direction, and some "pushing back" against the surface
Bigness: Each square cell of fluid writes a factor of it's Mass to the particle at the center, which then dilutes outwards. Bigger slime sticks more, smaller slime drops slide off stuff.
Stranded: Particles "Inside" write 1, otherwise sharply dilute to 0. Particles on edge of big-enough slimes hover around 0.7 value, Particles on edge that is a "thin strand of slime" drop to 0.1, and are killed, so that thin strands do not awkwardly hold together large Blobs of Slime, or wrap around edges of objects and prevent Slime Splitting
Teams: An Orange/Blue "Team Signal" writes 0 or 1 to nearest particles, and particles near 0 or 1 Teamness accept input from either "Player 1" or "Player 2", with values around 0.5 being an idle grey that get no input

Workaround?
I can imagine an awful Workaround to the 4-channel limit, by creating one set of intangible "Zombie" Fluid per extra 4 Channels I want. It would copy Position and Velocity, and dilute fluid, and any of my calls to GetUserData(particleIndex, dataIndex) would would send dataIndex 0-3 to "real" Slime, and dataIndices 4-15 to any of the "Zombie" slimes. My need for more UserData has not reached the point to attempt such a disgusting (and probably grossly computationally wasteful) solution.

If Implemented
More UserData would allow me to allocate 2-3 channels to "Team", allowing 4-8 individually-controlled regions of Slime, instead of 2. I could add 1 for Temperature, 1 for Digestion/Energy, a few for Harmful Chemicals. I would especially like to allocate 2 channels to "Applied Forces on x/y axis" such that I can use diffusion to get more "Equal and Opposite Forces", ie applying additional braking where I notice "500 Force magnitude on a particle last frame"

From: Multiple user data and more flexible diffuse





Type of UserData changing from ObiNativeListVector4 to Vector8, Vector12, Vector16 sounds hairy already. I don't know how it would be implemented.
Adding a 1-4 int picker to ObiFluidEmitterBlueprint is probably totally insufficient, it has to be project-wide, for all fluids, right?

short text message to appease the scripts

Hi there!

Having 16 diffusion data channels per particle would result in considerably slower simulation, best-case scenario diffusion would be 4 times slower as it has x4 the amount of data to deal with.

Not all custom data needs to be stored there though, specially if it does not require diffusion. For instance, ObiEmitters store a "life" floating point value for each particle, that's stored in a regular array and not part of the simulation. Some of the things you mention could be stored that way: team index, or air/solid.

To determine if a particle is near the surface, you can use the length of its normal vector: particles near the surface have long normal vectors, particles inside a volume have near-zero normal vectors.

If you really need to go past 4 user diffusion channels, you will need to modify the solver's userData array (it currently is a ObiNativeVector4List, you could either allocate more than 1 Vector4 per particle, or create another struct that has more than 4 floating point values), as well as the diffusion implementation which can be found in BurstDensityConstraintsBatch.cs (UpdateDensitiesJob struct)

(09-09-2022, 07:32 PM)nanimo(null) Wrote: Type of UserData changing from ObiNativeListVector4 to Vector8, Vector12, Vector16 sounds hairy already. I don't know how it would be implemented.

Basically create a Vector8/12/16 struct of your own, and create a new ObiNativeVector8/12/16List specialization of ObiNativeList<T>. Then replace the code for dealing with Vector4/float4 in the engine to deal with 8/12/16 values. It will inevitably be slower, though.

(09-09-2022, 07:32 PM)nanimo(null) Wrote: Adding a 1-4 int picker to ObiFluidEmitterBlueprint is probably totally insufficient, it has to be project-wide, for all fluids, right?

Right, you cannot store different amounts of data for different fluids. The engine assumes all fluid particles store the same amount of data, and only the data itself can vary across fluid blueprints/emitters.

kind regards,
Reply
#3
Multiple vector4s per particle userdata is working, with Jobified UserData>Color averaging that scores 2/10 on aesthetics
Though it's only Cyan/Black/Yellow/Red, there are really 16 colors per-particle being averaged into 1 color, trust me...

Made a patch for the feature, which can be applied to your Unity repo if you also use TortioseGit
Open the .diff file with TortoiseGit, then click "File">"Apply Patch" and select the root folder of your Unity Project. TortoiseGit may propose a better match.
If you have any edits to these scripts, or Obi at a weird path, the patch won't work, but you can just read the snippets and re-write some it out yourself
https://pastebin.com/B88kVvYQ
save as "multiple userdata vectors per particle.diff" (no quotes) for TortoiseGit to open it


I modified FluidOverlapQuery.scene, so each cube draws 1 userdata to it's userdata channel. Colors are later averaged per-particle to display them.
Scene edits to add cubes and colors to OverlapTest.unity are not included, but there's a picture for reference

If userData has multiple values per-particle, then the conventional get/set userData accessors will Warn - see the modified Get/Set in ObiSolver.cs below

Notes:
ObiSolverEditor.cs: Add "numUserDataVecs" to inspector
Water.asset: diffusion set to 1
OverlapTest.cs: Add burst job to average colors for 16 channels into 1 color per-particle, and reduce userdata over time to prevent over-mixing
BurstDensityConstraintsBatch.cs: Diffusion job now iterates over multiple vectors per particle
ObiSolver.cs: Add numUserDataVecs, and multiply userdata size by that num. Add helper functions Get/SetUserData, Get/SetUserDataSingle
ProjectSettings.asset: Add OBI_BURST, defines now" OBI_ONI_SUPPORTED;OBI_BURST"

Performance: Tested it with 1500 vectors per-particle with 1500 particles, and got about 3 fps (compared to 100 fps with a more reasonable 4 vector4s per-particle)


Attached Files Thumbnail(s)
       
Reply