Setting a unique ID to each particle [SOLVED]
On 16/05/2015 at 01:05, xxxxxxxx wrote:
When particles die in my scene, the IDs get shifted and everything goes bananas.
I've tried using the "Python (set unique id to uid_maxon)" node in the system presets but can't seem to figure it out. And I did create a uid, uid_maxon channel and a dummy out port but no dice.
Thanks in advance for any help.
On 16/05/2015 at 21:04, xxxxxxxx wrote:
Alright. So I've edited the default code to work when there's an "Index" out port, but it gives an error each frame because 'Index' is expected to be an integer, not None. I'm just ignoring it for now and moving on. Here's the code:
It still gets weird when particles stop emitting on 'count' emmisions but 'rate' seems to work fine.
To use multiple pgroups, you'll need to make a new channel, and it will get messed up when you try to get some data from a particle because the actual index remains unchanged. Working on it now :/
#Welcome to the world of Python
#This script gives each particle an unique ID
#so we can always identify the particle
#and give it always the same shape
#the UID counter
count = 0
data_channel_id = None
def GetUIDChannelID(tp) :
Returns the index of a data channel
called 'Index(Integer)' or None.
:return: The index or None if failed
#lets browse the data channels and
#lets look for the name
name_to_look_for = "Index(Integer)"
for x in xrange(tp.NumDataChannels()) :
name = tp.DataChannelName(x)
if name == name_to_look_for:
data_channel_id = x
#no channel found
def main() :
#The user might change the data channel,
#so we have to reset the cached channel index
#data_channel_id = None
tp = doc.GetParticleSystem()
channelid = GetUIDChannelID(tp)
Index = tp.GetPData(Particle, channelid)
if Index == None:
tp.SetPData(Particle, channelid, count)
On 17/05/2015 at 03:37, xxxxxxxx wrote:
Aaalright. I think I've thought of a solution but don't know how to go about doing it.
The mastersystem seems to use the unique, birth-order indexes instead of using indexes that shift each time a particle dies. So you can't really use functions with index arguments because the ppass node gives you shifting indexes that are specific to the pgroup.
What I need is a counter that increases each time a particle is born, possibly using the pAge node which pumps out a '1' each time a particle is born. I'm a python noob so I was hoping someone here could offer some advice. This is the value that's going to be set to each particle's 'Index' channel.
Just realized how embarrassingly obvious this solution is. Stand by.
There seems to be some sort of priority issue with my 'IsBorn' function. I can't seem to get a True value. Here's what I have for the counter:
tp = doc.GetParticleSystem()
All = tp.GetRootGroup()
count = tp.GetGroupParticleCount(All, True)
for i in xrange(count) :
born = tp.IsBorn(i)
if born == True:
Counter += 1
There's nothing connected to any in ports at the moment, I think that's what is causing the priority issue.. any tips?
On 18/05/2015 at 11:32, xxxxxxxx wrote:
can you provide me with your scene (e.g. mail it to sdk_support). It would make testing much easier.
On 19/05/2015 at 13:59, xxxxxxxx wrote:
actually your setup is more complex than I expected.
I'm not sure, I understood everything correctly.
Some of my observations:
One of the problems with your setup is that the PStorm emits only one particle every 12 frames. In the following, everything that depends on this PStorm is only evaluated every 12th frame. So maybe it's an idea to emit one particle every frame and always kill eleven of them and keeping only every 12th.
Maybe this is a follow up of the above. But IsBorn() works here only, if the Python node is connected directly to the PStorm. I used simplified code for testing. Python node with one particle input: part_id (connected to PStorm's Particle Birth) and one integer input: count_in and one integer output: count (I'll explain these two later) :
import c4d def main() : global count # only outputs need to be defined as global tp = doc.GetParticleSystem() All = tp.GetRootGroup() num_particles = tp.GetGroupParticleCount(All, True) frame = doc.GetTime().GetFrame(doc.GetFps()) startframe = doc.GetMinTime().GetFrame(doc.GetFps()) if frame == startframe: ## THIS DOES NOT WORK, DUE TO THE NODE BEING ONLY EVALUATED EVERY 12th FRAME count = 0 if tp.IsBorn(part_id) == True: count = count_in + 1
By the way, this does not need the Python node at all, as PAge node can be used instead of IsBorn().
Instead of a global variable I use User Data of type integer on a Null object for example. Then I have the two nodes from the Null object. One with User Data as input, one with User Data as output. The later feeds in count_in and count output is connected to the first User Data. This eliminates the need for a global count variable and also makes it also possible to build the counter without Python node.
I know, I'm not presenting a final solution. But I hope, this provides you at least with some ideas to further investigate your problem.
On 20/05/2015 at 08:01, xxxxxxxx wrote:
Thank you, Andreas. This is definitely helpful information.
I tried using the pAge node before but couldn't get it to output anything more than a zero, but I've just made a global particle counter in a new scene without any problems with the pAge node, so it must be something in my scene or it's just deciding to not work..
But anyway, this is great. I'll be back soon with any more problems I run into. I don't have much time to work on it now other than some spare time but will Monday/Tuesday.
update: Couldn't make any progress. All I've learned is that it help to create a separate xpresso tag earlier in the hierarchy with just the emitter / particle setup. I've also learned how great xparticles is. I'll probably come back to this later if I don't get xparticles first.