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.
The shape emitters can be one of these geometries, under the NxParameterized included reference, geometryType:
Within each of the shape geometry types is an emitterType which defines the frequency and position of the particles spawned in the emitter.:
The ApexEmitterActorParameters NxParameterized class contains the parameters necessary to create an NxApexEmitter Actor:
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.
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.
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);
}
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
If particle velocites provided are zero, then a random value within the emitter asset’s velocityRange parameter is used.
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.
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.
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.
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 |
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 are useful if a level editor wishes to place a representation of an emitter actor in a level.
The shaped emitter preview rendering will draw the geometry of the emitter.
Because impact emitter actors do not have a pose and simply receive impact locations from the application, they do not implement preview rendering
The ground emitter preview rendering will draw a cylinder that describes the refresh radius, upDirection, and spawnHeight.
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 ));
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.
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 |