Rendering custom particles with Thinking Particles

  • On 25/04/2018 at 22:17, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   19 
    Platform:   Windows  ;   Mac OSX  ; 
    Language(s) :     C++  ;  XPRESSO  ;

    I have zero experience with Thinking Particles so I am wondering how can I have my particles show up in a PGroup so that I can render them?

    What I would like is for my particles to show up similarly to what is shown in this video at 3:05.

    The person right clicks on "All" (in the Thinking Particles Settings under Particle Groups) and chooses Add. This adds a RealFlow object to the scene.

    How would this RealFlow object be registered? I am currently registering my object as an OBJECT_GENERATOR, but this does not seem to work.

    Any help would be much appreciated.


  • On 26/04/2018 at 06:34, xxxxxxxx wrote:

    Hi Kent,

    First of all, about the video, It's looks like the group is already here (just folded) even before he adds a group. So it's probably the object within the scene which add a new group.

    Here is a CommandData to demonstrate how to add a group, create particles, then assign them to the group and finally move them.
    Same things should work for an ObjectData.

    #include "c4d.h"
    #include <c4d_particles.h>
    class TpGenerator : public CommandData
    	INSTANCEOF(TpGenerator, CommandData)
    	TP_MasterSystem* GetTpMasterSystem(BaseDocument* doc);
    	TP_PGroup* GetRootGroup(TP_MasterSystem* master);
    	virtual Bool Execute(BaseDocument* doc);
    	virtual Int32 GetState(BaseDocument* doc);
    TP_MasterSystem* TpGenerator::GetTpMasterSystem(BaseDocument* doc)
    	if (!doc)
    		return nullptr;
    	BaseSceneHook* hook = doc->FindSceneHook(ID_THINKINGPARTICLES);
    	if (!hook || hook->GetType() != ID_THINKINGPARTICLES)
    		return nullptr;
    	return static_cast<TP_MasterSystem*>(hook);
    TP_PGroup* TpGenerator::GetRootGroup(TP_MasterSystem* master)
    		return nullptr;
    	TP_PGroupArray groups;
    	Int32 gcnt = master->GetParticleGroups(nullptr, &groups, TP_GETPGROUP_ALL, false);
    	if (gcnt == 0)
    		return nullptr;
    	TP_PGroup* grp = (TP_PGroup* )groups.GetIndex(0);
    	return grp;
    Bool TpGenerator::Execute(BaseDocument* doc)
    	// Get the TP master system
    	TP_MasterSystem* master = GetTpMasterSystem(doc);
    	if (!master)
    		return false;
    	// Get the Root Group
    	TP_PGroup* rootGroup = GetRootGroup(master);
    	if (!rootGroup)
    		return false;
    	// Create a new group
    	TP_PGroup* customGroup = master->AllocParticleGroup();
    	if (!customGroup)
    		return false;
    	customGroup->SetName("Custom Particle Group");
    	// Insert customGroup as a child of root ("All") 
    	master->SetPGroupHierarchy(rootGroup, customGroup, TP_INSERT_UNDERFIRST);
    	// Create 100 particles
    	Int32 particleIds[100];
    	if (master->AllocParticles(100, particleIds) == NOTOK)
    		return false;
    	// Set all particles to the group and move them
    	for (auto pId : particleIds)
    		master->SetGroup(pId, customGroup);
    		master->SetPosition(pId, Vector(pId * 10));
    	return true;

    Moreover please make sure to call InitThinkingParticles before to use any TP function, the recommended way is to call it in C4DPL_STARTACTIVITY

    Bool PluginMessage(Int32 id, void* data)
    	switch (id)
    	retun true;

    Hope it helps,


  • On 30/04/2018 at 01:39, xxxxxxxx wrote:

    Thanks Maxime. Got it working.

Log in to reply