APEX Emitter Programmers Guide

../_images/ParticlesIcon.JPG

Introduction

APEX particle emitter actors output particles at the start of the particle pipeline. Presently there are three basic types of Emitter Authorable Objects. They are the Simple Shape Emitter, Air / Ground Emitter, and the Weapon Impact Emitter. The Air / Ground Emitters are special purpose emitters that emit particles relative to the ground. Finally the Weapon Impact Emitter outputs particles in response to a collision or an explosion.

Shaped APEX Emitter

The shape emitters can be one of these geometries, under the NxParameterized included reference, geometryType:

  • Box - PxVec3 extents
  • Cylinder - PxF32 radius, PxF32 height
  • Sphere - PxF32 radius
  • Sphere Shell - PxF32 radius, PxF32 shellThickness
  • Explicit - PxVec3[] positions, PxVec3[] velocities

Within each of the shape geometry types is an emitterType which defines the frequency and position of the particles spawned in the emitter.:

  • rate - The emitter will emit at the rate specified by the asset’s rateRange
  • densityOnce - The emitter will fill the geometry according to the asset’s densityRange
  • densityBrush - As the emitter moves, the emitter will fill the volume that is not already covered by the previous position
  • fill - The emitter will fill the volume with particles based on the particle size

Creating the Shaped Emitter

The ApexEmitterActorParameters NxParameterized class contains the parameters necessary to create an NxApexEmitter Actor:

  • initialPose - The shaped emitter may be placed with a particular position and rotation
  • attachRelativePose - Once the shape is created, the NxApexEmitter::setAttachActor(NxActor*) method is used, if desired, to have the emitter’s pose match that of the NxActor’s pose. The attachRelativePose may be set in the actor parameter class during actor creation.
  • emitAssetParticles - A bool which tells the actor whether or not it should emit particles stored in the asset’s particle list.
  • overlapTestGroupMaskName - Before the emitter creates a particle it can test to see if the particle is within a collision volume, preventing particle popping issues. This string is mapped by the Named Resource Provider to a 32-bit mask of multiple collision groups used by the overlap tests.
  • overlapTestGroupsMask128Name - This string is mapped by the Named Resource Provider to a 128-bit mask (NxGroupsMask) used by the overlap tests.

Please note that the particle emitter state does not reflect emitAssetParticles bool when an ApexEmitterActor is created. The application must still explicitely call ‘startEmit’ to get the emitter started.

Depending on the scene, overlap tests may become expensive. To prevent them from happening, leave both overlap mask strings empty on actor creation. The EmitterActorOverlapAABBSceneQuery profiler event is emitted during the overlap tests.

Emitting Particles

Particles are emitted after the application calls NxApexScene::simulate() if the NxApexEmitter::startEmit() has been called. It is possible to emit particles just once by setting the persistent flag in startEmit() to false:

emitterActor->startEmit( false );

If the persistent flag is true, the emitter will emit particles every frame. Make note that the shaped emitter never takes into account particles that it emitted in previous frames for the density calculations.

Scalable Parameters

There are two scalable parameters registered for the shaped emitter, “Rate” and “Density”, with a range between 1 and 10. These scalable parameters scale between the min and max of the rateRange and densityRange parameters of the emitter asset. The scalable parameters are a direct way to throttle all shaped emitters before the LOD budget is enacted to limit the particle count. Here is an example of how to get the scalable parameters from the Particles module and set their values:

NxModule * emitterModule; // initialized elsewhere
physx::PxU32 numScalables   = emitterModule->getNbParameters();
NxApexParameter ** scalables = emitterModule->getParameters();

for( physx::PxU32 i=0; i<numScalables; i++ )
{
    NxApexParameter &p = *scalables[i];
    printf("%s: %d (%d-%d) ", p.name, p.current, p.range.minimum, p.range.maximum);
    emitterModule->setIntValue(i, p.range.maximum);
}

Using the Explicit Geometry

The explicit geometry type makes the APEX emitter very flexible by allowing the user to create particles at specific positions and velocities. These particle positions and velocities may be stored in the asset where all actors have access to the lists. The actor can also hold its own particle positions and velocities. Note, particles stored in the asset can be emitted by any actor created by the asset, particles stored in the actor’s list may only be accessed by the actor. Example:

During runtime, to access an explicit emitter actor's asset particles:
emitterActor->getEmitterAsset()->getGeom()->isExplicitGeom()->getParticleList(...)

During runtime, to access an explicit emitter actor's particles:
emitterActor->isExplicitGeom()->getParticleList(...)

The emitAssetParticles member of the emitter actor’s NxParameterized parameters (ApexEmitterActorParameters) will switch whether or not the asset’s particle list is emitted by the actor. If this parameter is true, then only the particles added through the actor’s explicit geometry will be emitted.

When the geometry is explicit, the densityRange asset parameter actually becomes a particle spawn probability:

1.0 - all particles in the particle list will be spawned every frame
0.0 - no particles will be spawned

Explicit Particle Velocities

If particle velocites provided are zero, then a random value within the emitter asset’s velocityRange parameter is used.

Explicit Emitter Pose

Since the emitter actor will transform all particle positions to the emitter actor’s position, it is possible to set multiple poses for the emitter in one frame. Every time the NxApexEmitterActor::startEmit() method is called, the current pose is stored in an array and each individual pose is used to emit particles during the simulation.

The application can avoid position and velocity transformations on particles by leaving the pose at the non rotated origin and using absolute particle positions and velocities.

Impact Emitter

The impact emitter packages both particle emission events and explosion events into one actor. The application is expected to perform raycasts and determine the correct parameters to pass to the NxImpactEmitterActor::registerImpact(...) method. The impact emitter asset and actor do not make any association between the physical material of the hit shape returned from the raycasts and the setID within the emitter.

It is expected that a game engine will already have physical material names, and these names can be stored as the event set name within the asset. All of the event set names (and their corresponding )may be retrieved using the NxImpactEmitterAsset::getSetNames() method. To determine the a setID from a particular event set name, use the NxImpactEmitterAsset::querySetID( const char * setName ) method.

Ground Emitter

The ground emitter is typically used to position ground debris around a player. As the player moves throughout the level, the emitter deposits particles on the ground. The pose of the ground emitter actor may be updated manually by calling NxGroundEmitterActor::setPose() or automatically with NxGroundEimtterActor::setAttachActor().

Ground emitters perform raycasts to determine where to place particles in a scene. If the application has not created its own NxMaterialLookupCallback class and registered it using NxGroundEmitterActor::setMaterialLookupCallback(), raycasts will be performed by the PhysX engine. These raycasts can be filtered using both an NxCollisionGroup bitmask and an NxGroupsMask.

The Named Resource Provider will callback in the NSCollisionGroupMask and NSCollisionGroup128 namespaces to retrieve both an NxCollisionGroup bitmask and an NxGroupsMask for the raycasts. If neither is provided, the raycast should collide with all objects. The application may set the NSCollisionGroup128 resource to NULL if NxGroupsMasks are not being used.

Every PhysX raycast will return an NxMaterialIndex (PxU16) for the physical material that was hit. This NxMaterialIndex needs to be mapped to one of the physical material strings listed in the emitter asset’s materialFactoryMapList. For each different physical material listed in the asset’s materialFactoryMapList, the Named Resource Provider will callback in the NSPhysicalMaterial namespace to fetch an NxMaterialIndex.

Named Resource Provider Callbacks

Here is a summary of the callbacks that the ground emitter may call:

Namespace Reason
IOFX A different IOFX could be used for each physical material listed in the materialFactoryMapList
NxFluidIosAsset A different IOS could be used for each physical material listed in the materialFactoryMapList
NSPhysicalMaterial The physical material names must be mapped to NxMaterialIndex values by the application
NSCollisionGroupMask Raycasts may be filtered with a 32-bit bitmask of NxCollisionGroups (0xffffffff to hit everything)
NSCollisionGroup128 Raycasts may additionally be filtered with an NxGroupsMask, return 0 if NxGroupdsMasks are not used by the application

Scalable Parameters

There is one scalable parameter registered for the ground emitter, “GroundDensity”, with a range between 1 and 10. This scalable parameter scales between the min and max of the densityRange parameter of the emitter asset. The scalable parameter is a direct way to throttle all ground emitters before the LOD budget is enacted to limit the particle count.

Emitter Asset Previews

Emitter asset previews are useful if a level editor wishes to place a representation of an emitter actor in a level.

Shaped Emitter

The shaped emitter preview rendering will draw the geometry of the emitter.

Impact Emitter

Because impact emitter actors do not have a pose and simply receive impact locations from the application, they do not implement preview rendering

Ground Emitter

The ground emitter preview rendering will draw a cylinder that describes the refresh radius, upDirection, and spawnHeight.

Asset Preview Creation

To create an emitter preview class, get the default NxParameterized parameters from the asset using NxApexAsset::getDefaultAssetPreviewDesc(). Then set the pose and/or scale, then create the preview class using NxApexAsset::createApexAssetPreview():

//Initialized elsewhere depending on type of emitter asset being created
NxApexEmitterAsset *asset;
NxGroundEmitterAsset *asset;

//Common code which sets the asset preview descriptors
PxMat44 pose = PxMat44::identity();
pose.setPosition( physx::PxVec3( 0.0f, 10.0f, 0.0f ) );
NxParameterized::Interface* p = asset->getDefaultAssetPreviewDesc();
NxParameterized::setParamMat44(*p, "pose", pose);
NxParameterized::setParamF32(*p, "scale", 1.0f);

//Create emitter asset preview depending on type of emitter asset being created
mApexEmitterPreview = static_cast<NxApexEmitterPreview*>(asset.createApexAssetPreview( *p ));
mGroundEmitterPreview = static_cast<NxGroundEmitterPreview*>(asset.createApexAssetPreview( *p ));

Debug Visualization

The APEX Emitter Module provides different debug visualizations for the emitter actors (shaped, impact, and ground).

Click here for a list of the APEX Emitter debug visualization parameters

For general information on how to use debug visualization within APEX, please see Debug Visualization.

Errors and Warnings

APEX Emitter outputs the following error and warning messages using the standard APEX error stream.

ERROR CODE MESSAGE
APEX_INVALID_OPERATION %s is not a valid descriptor class
APEX_INTERNAL_ERROR Could not create a new APEX Emitter parameter instance
APEX_INTERNAL_ERROR Cannot get NxParameterized handle for APEX Emitter geometry type.
APEX_INTERNAL_ERROR Could not initialize NxParameterized type: %s
APEX_INTERNAL_ERROR No matching NxParameterized type: %s
APEX_INTERNAL_ERROR IOFX, IOS, or IOS type not initialized
APEX_INTERNAL_ERROR No emitter geometry specified
APEX_INTERNAL_ERROR Invalid NxParameterized handle for name: eventSetList
APEX_INTERNAL_ERROR Cannot get NxParameterized handle for eventSet %d out of %d
APEX_INTERNAL_ERROR Could not access invalid NxParameterized eventSet
APEX_INTERNAL_ERROR Could not create a new Impact Emitter parameter instance
APEX_INTERNAL_ERROR Impact Emitter deserialization does not support versions before NxParameterized was added
APEX_INTERNAL_ERROR Invalid NxParameterized handle for name: eventSetList
APEX_INTERNAL_ERROR Cannot get NxParameterized handle for eventSet %d out of %d
APEX_INTERNAL_ERROR Could not initialize NxParameterized type: %s
APEX_INTERNAL_ERROR Invalid included NxParameterized type: %s
APEX_DEBUG_INFO IOS asset retrieval failure: %s
APEX_DEBUG_INFO IOS injector allocation failure
APEX_DEBUG_WARNING Not all objects have been emitted:
APEX_DEBUG_WARNING Unable to serialize an NxApexEmitter without a geometry
APEX_DEBUG_WARNING NxEmitterLodParamDesc version mismatch
APEX_DEBUG_WARNING Invalid eventSetName from Impact Emitter event sets