Generator POPs are similar to modifier POPs.
Most of the concepts introduced in writing a modifier POP apply here with a
few differences.
Differences from modifier POPs
An example of a generator POP can be found in the POP toolkit
examples.
Only the important differences will be examined.
PRM_Template
POP_RadialBirth::myTemplateList[] =
{
PRM_Template(PRM_FLT_J, 1, &POPactivateName, PRMoneDefaults, 0,
&PRMunitRange),
PRM_Template(PRM_XYZ_J, 3, &names[0]),
PRM_Template(PRM_FLT_J, 2, &names[1], distanceDefaults),
PRM_Template(PRM_FLT_J, 2, &names[2], speedDefaults),
PRM_Template(PRM_INT_J, 1, &names[3], PRMfourDefaults, 0, &birthRange),
PRM_Template(PRM_STRING, 1, &names[4]),
PRM_Template(PRM_FLT_J, 1, &POPlifeName, &POPlifeDefault),
PRM_Template(PRM_FLT_J, 1, &POPlifevarName),
PRM_Template(PRM_INT_J, 1, &POPoriginindexName),
PRM_Template()
};
The source group used in modifier POPs represents a subset of particles
to apply the operation on. This concept doesn't really apply when birthing
particles, so generator POPs don't require a source group. The activation
field still applies.
void
newPopOperator (OP_OperatorTable* table)
{
table->addOperator(
new OP_Operator("radialbirth", // Name
"Radial Birth", // English
POP_RadialBirth::myConstructor, // "Constructor"
POP_RadialBirth::myTemplateList, // simple parms
0, // MinSources
0, // MaxSources
0, // variable pair
OP_FLAG_GENERATOR)); // op flags
}
Note that the OP_FLAG_GENERATOR flag must be set to tell the
operator table that this POP is a generator.
POP_RadialBirth::POP_RadialBirth (OP_Network* net, const char* name,
OP_Operator* entry)
:POP_Node (net, name, entry)
When birthing new particles, it doesn't make sense to have local variables
that represent the particle's attributes. It's the classic chicken and
the egg problem. It's not possible to define particle attributes based on
local variables because the attributes have no value yet. So, it makes no
sense to inherit from the POP_LocalVar class. Generator POPs should inherit
from POP_Node.
part = data->getPrimPart(this);
initParticleList(context, part);
Each generator creates a new particle system, or in Houdini geometry
terms, its own particle primitive.
The POP_Node variable,
myParticleList should contain a list of particle primitives that
the POP processes. For modifier POPs, this list is generated from the
input wires using the method buildParticleList(). Generator POPs
will want to initialize the list with the primitive is creates.
The getPrimPart() method
of the POP_ContextData returns the primitive associated with this generator.
The call will create a new primitive if one doesn't exist yet.
The method initParticleList() initializes the list with the
newly created primitive.
birthParticle(data, part, birthpos, NULL, NULL, NULL,
(POP_IntFunc) getOriginIndex, 0, POP_ORIGIN_INDEX,
(POP_FloatFunc) getLifetime,
(POP_BirthAttribFunc) setAttrib);
The POP_Node method birthParticle() is used to birth particles
into the particle primitive. This method will birth a particle
at a specific location, allow the new particle to inherit attributes,
and set some of the particle's initial attributes like the origin and
lifetime. A detailed description of the method can be found in the section
on POP classes.
Summary
This example demonstrated the general structure of a generator POP. It
covered the following topics:
Generator POPs are similar to modifier POPs.
Generators should inherit from POP_Node.
Generators don't need a source group parameter.
The list of particle systems to modify is held in
myParticleList.
The method birthParticle() is used to actually birth
particles.