Features Used in Particle Calculations

Animation Frame Control

ParticleModel and ParticleEmitter both store nw::anim::AnimFrameController.
They can be obtained using the ParticleAnimFrameController function.

Time can be advanced by making a set setting (SetStepFrame) and updating the frame (UpdateFrame). To advance to a particular frame, apply an offset from the previous frame to the animation. Depending on the animation type, values may differ when advancing one frame at a time.

In addition, the emitter emits for the amount of time that has advanced since an update was last called. A large volume of particles is therefore emitted if many frames are suddenly advanced at once.

This is not supported for reverse playback (where frame numbers are decreased).

Deleting All Particles

When ParticleSet* particleSet is set for a ParticleSet,
Particles are deleted using particleSet->ClearParticleCollection();

When ParticleModel* particleModel is set for a
ParticleModel,Particles are deleted using particleModel->
ForeachParticleSet(ParticleSetsClear());

Note

The clear function initializes streams. Just as when destryong a class, this function can only be used when there is no stream access from the GPU. This function is used for the purpose of initialization when re-using a class no longer being used.

Destroying Classes

If DetachChild is executed from SceneNode and nw::gfx::SceneNode::TraverseScene is invoked when removing ParticleEmitter and ParticleModel from the scene tree, calculations and rendering will stop being performed.

Finally, care is required when destroying a class to free memory.

After issuing drawing commands, do not free memory until the drawing is actually complete. If only a drawing command is issued, there is still a possibility of GPU access, and sometimes the GPU does not function correctly depending on the content of memory.
The same goes for textures.

Changing Resource Parameters

If you want to apply an effect to all nodes created from the same resource, you can change them by obtaining the resource and directly accessing associated parameters.

If you want to apply an effect to only one node out of all nodes created from the same resource, copy the resource for that node and manipulate the copied resource.
Resources can be copied automatically at time of node creation. If the IsResourceCopyEnable flag inside a resource is set before node creation, that resource is copied and stored at the time of node creation.
If the copied resource is for a given created node node only and that node is destroyed, the copied resource is also destroyed. Therefore, be sure to pay attention to the node's duration of existence when using a copied resource outside a node. In addition, since the original resource is also accessed even if it has been copied, be sure to carry out resource management as usual for the original resource.
Flags can be set ahead of time in the CreativeStudio UI. Set the flags for the following resources appropriately, when making changes after loading resources with an application. Resources that include IsResourceCopyEnabled

APIs for getting copied resources

By specifying true as an argument to these API functions, you can get resources that are only valid when being copied for use by a node. If it only has shared resources, IsValid() returns false. The default value of the API function arguments is false. If false is specified, resources can be obtained while prioritizing use by nodes, but if there are none, the function returns the shared resource.

A list of management information for initializers/updaters can be obtained using the GetInitializers and GetUpdaters functions of ParticleSet.

Notes on Changing Emission Volume, Lifespan, Etc.

Pay attention to possible memory shortages with ParticleCollection when making changes to parameters (such as the emission volume, emission interval, and lifespan) that will change the number of particles that exist simultaneously. Memory capacity cannot be changed after nodes are created. Be sure to make any changes to values in nw::gfx::Res::ResParticleCollection before creating nodes.

In addition to changing memory capacity at run-time, you can also allocate the maximum number of bytes anticipated ahead of time using CreativeStudio.

If there is a memory shortage, some particles that should have been emitted won't be. Once a particles has failed to be emitted it will no longer be generated at all, even if a spot opens for it due to another particle disappearing. A particle borne after the spot opens will be emitted. This can make it appear that particles are being emitted intermittently.

Changing Particle Information

Since most particle information is passed directly to the GPU shader, it's hard to manage a program built to reflect the internal implementation. A degree of knowledge regarding the internal structure is required for an application to change this information. Here's the explanation for this.

Included in particle information are streams that can include different values for each particle and fixed-value parameters in ParticleSet.

Whether particle information is a parameter or a stream is determined by optimization of the binary output from CreativeStudio.

Conditions for Optimizing Streams to Parameters

If all of the following conditons are satisfied, the Initializer is deleted and the stream is also output as parameters (fixed-value).

In addition to the distinction between parameters and streams, there is also a distinction between information that is used only in calculations by the CPU and information (VBO and vertex parameters) directly handled by the shader. This information is divided up at run-time depending on the attribute type. A double buffer is used for vertex attributes. A single buffer is used for other information.

Handling Attribute Types at Runtime

Type Role Type Parameter Availability Vertex Attribute?
TRANSLATE Location (local coordinate system) VEC3 Stream only Vertex attribute
SCALE Scale (local coordinate system) VEC3 Stream/Parameter Vertex attribute
ROTATE Rotation (local coordinate system) VEC3 Stream/Parameter Vertex attribute
COLOR RGB Color VEC3 Stream/Parameter Vertex attribute
ALPHA Alpha f32 Stream/Parameter Vertex attribute
TEXTURETRANSLATE0 Texture coordinate translation. VEC2 Stream/Parameter Vertex attribute
TEXTURESCALE0 Texture coordinate scale. VEC2 Stream/Parameter Vertex attribute
TEXTUREROTATE0 Texture coordinate rotation. f32 Stream/Parameter Vertex attribute
SCALE_EXT Scale (extended) VEC3 Stream/Parameter Vertex attribute
BIRTH Date created. ParticleTime Stream only -
LIFE Lifetime ParticleTime Stream/Parameter -
VELOCITY Speed VEC3 Stream only -
ACTIVEINDEX Indirect reference index to the element in use. u16 Stream only Vertex attribute
FREEINDEX Indirect reference index to a usable element. u16 Stream only -
NGE_TIMELIMIT Negative number (for speedup purposes) indicates the time when the particle should disappear. ParticleTime Stream only -

 

Changing Values

There are four methods of changing values. The one to use differs depending on whether information is a stream or parameter and whether it's a vertex attribute or other information.

For a sample implementation, see ParticleChangeVtxDemo.

Changing parameters

Overwrite parameters using nw::gfx::ParticleCollection::SetParameter. In the case of LIFE, overwriting is also possible using ParticleColection::SetLifeParameter. (Recommended.)

In the case of non-vertex parameters (LIFE only), only content of memory pointed to by the parameter pointer obtained by ParticleCollection::GetParameterPtr can be re-written. Because a single-buffer is used, the content of both PARTICLE_BUFFER_FRONT and PARTICLE_BUFFER_BACK is the same.

In the case of vertex attribute parameters, in addition to the content of memory pointed to by the parameter pointer obtained by ParticleCollection::GetParameterPtr, commands already created can be re-written. Because commands are double-buffered, only one side of the buffer can be re-written per call. Note that a command that does not specify a buffer does not re-write anything. There may be some difference between the contents of the address obtained using ParticleCollection::GetParameterPtr
and command double-buffer status. Although PARTICLE_BUFFER_FRONT/PARTICLE_BUFFER_BACK can be specified, do not change PARTICLE_BUFFER_BACK at any time a command may be issued to the GPU. Essentially, you should not write to PARTICLE_BUFFER_BACK at all because this timing is hard to grasp.

Moreover, inside the library, parameters are never changed after commands are created.

Changing streams

Streams can be obtained using ParticleCollection::GetStreamPtr. If NULL is returned, either the arguments are wrong or the specified class is being used as a parameter.

In general, obtain the stream from PARTICLE_BUFFER_FRONT.

The obtained stream is an array of types determined based on the class. The maximum number of entries that can be stored in the array can be obtained using the ParticleCollection::GetStreamPtr function. This stream is not necessarily used padded from the start. An index that can be obtained by the PARTICLEUSAGE_ACTIVEINDEX class must be used.

See ParticleUpdaterDemo for a sample implementation of making changes using UserUpdater.

Getting ACTIVEINDEX

This section describes how to get ACTIVEINDEX, which is required to access streams.

ACTIVEINDEX is used as the vertex index of DrawElements as a VBO. Applications cannot re-write this value because it affects various internal elements.

Although ACTIVEINDEX is usually stored starting from the start in the order created, if the rendering order is reversed (ResParticleShapeBuilder::IsAscendingOrder), it is stored starting from the end. The number of valid instances can be obtained using ParticleCollection::GetCount().

Basically, obtain streams from PARTICLE_BUFFER_FRONT, but obtain them from PARTICLE_BUFFER_BACK when getting PARTICLEUSAGE_ACTIVEINDEX inside UserUpdater. Even then, be sure to get all information other than ACTIVEINDEX from FRONT.

This requirement is due to the following process flow.

  1. Particle creation (AddParticles/InitializeParticles)
  2. Perform update processing (UpdateParticles)
    1. Swap FRONT and BACK by swapping buffers.
    2. Copy the VBO stream other than ACTIVEINDEX from BACK to FRONT.
    3. Perform update processing (UserUpdater is called here).
    4. In the delete due to lifespan process, delete unnecessary particles from BACK and arrange in FRONT.

Because the deletion process overlaps copying of the stream, ACTIVEINDEX used by UserUpdater must be obtained from BACK.
Do not overwrite contents because rendering for BACK may be in progress.

Particle Memory Usage

This section describes the memory used per particle as of NintendoWare 1.0.1.

Because particles are drawn by passing memory that stores particle information directly to the GPU, values are handled as floating point numbers. (This is done because quantizing multiple attributes increases the processing load on the GPU.)

Type Role Size Omittability Number of buffers
TRANSLATE Location (local coordinate system) 12 bytes × 2
SCALE Scale (local coordinate system) 12 bytes 2
ROTATE Rotation (local coordinate system) 12 bytes 2
COLOR RGB Color 12 bytes 2
ALPHA Alpha 4 bytes 2
TEXTURETRANSLATE0 Texture coordinate translation. 8 bytes 2
TEXTURESCALE0 Texture coordinate scale. 8 bytes 2
TEXTUREROTATE0 Texture coordinate rotation. 12 bytes 2
SCALE_EXT Scale (extended) 12 bytes 2
BIRTH Date created. 4 bytes × 1
LIFE Lifetime 4 bytes 1
VELOCITY Speed 12 bytes × 1
ACTIVEINDEX Indirect reference index to the element in use. 2 bytes × 2
FREEINDEX Indirect reference index to a usable element. 2 bytes × 1
NGE_TIMELIMIT Negative number (for speedup purposes) indicates the time when the particle should disappear. 4 bytes × 1

50 bytes if all omittable items can be omitted. 210 bytes if they could not all be omitted.

The number of bytes specified for "work memory at runtime" under CreativeStudio will be allocated per ParticleSet.

Memory used by main classes (main base classes are given in parentheses)

sizeof(values in parentheses are for version 1.1)
ParticleModel 636 (564)
ParticleSet 144 (136)
ParticleCollection 444 (436)
ParticleShape 528 (516)
ParticleEmitter 400 (388)
(SceneObject) 12 (12)
(SceneNode) 80 (72)
(TransformNode) 336 (324)
(Model) 556 (508)

In addition, memory for pointers such as to materials, the command cache, and children is also allocated.

1296 bytes per ParticleShape is allocated for the command cache to be used for particles.

Processing When Using Hierarchical Structures

When a particle is born, its position is determined by the emitter. However, coordinate conversion is performed so that its position does not shift when passed to the particle model. In other words, regardless of how the hierarchy is arranged, emitted particles appear in the emitter position at this point.

After emission, particles are drawn using the model coordinate system.

As an exceptional option for hierarchical structures, particle sets include an option for forcing the use of the world coordinate system. If this option is specified, the world coordinate system is used for the particle set regardless of the hierarchical structure. In other words, status is the same as if there was no hierarchical structure.

User Updater

An updater is a processing unit used to perform particle animations for ParticleSet. Mechanisms that can be added to a user-defined updater have been prepared in the library. Use of these mechanisms allows features not provided by the library to be used by an application.
ParticleUpdaterDemo is a sample demo of a user-defined updater.

Preparing resources

The resource ResParticleUserUpdater is supported for user updaters. A user process is called as a callback when processing of this resource is performed by ParticleSet.

Currently, intermediate files created using CreativeStudio are not supported by ResParticleUserUpdater. To add a user-defined updater, add the following to the ParticleUpdaters list in the intermediate file:
<ParticleUserUpdaterXml IsUpdaterEnabled="true" UserParameter="0">
<ParticleAnimationData />
<TargetStreams />
</ParticleUserUpdaterXml>
Although the addition and deletion of user updaters is not supported by CreativeStudio, reading and writing of intermediate files, binary output, and viewing of contents are possible. ParticleUserUpdater is a setting for each ParticleSet.

Using User-defined Updaters with Applications

Search for updaters supported by ResParticleUserUpdater from among updaters for the created ParticleSet, and set a user-defined function pointer for updater.work.

For details, see how the SetUserUpdater function is used in ParticleUpdaterDemo.

Emission volume from an emitter

This section gives an overview of parameters related to emitter emission and what they mean.

Emission timing

First, the basic concept is summed up as follows:

This is the fundamental concept.

This timing provides an opportunity at the integral frame level to control emission based on whether the actual time has exceeded this timing.
Evaluation is performed during actual calculations. Particles emitted between the last evaluation and the next are all treated as if born at time of evaluation. For example, consider a particle set to be emitted each frame and a playback rate of 2.0. In this case, double emission will take place once every two frames. There is no need to consider the time difference of unevaluated frames.

There is no opportunity for emission with an emission period of 0. With an emission period of 1, there is only one chance for generation (the first frame).

The emitter stores the timing for the next emission an updates information during emission processing.
Timing for the next emission is given by the following formula.

(int)(emission_interval * (1.0f + emission_interval_random * random_number_between(-1.0f, +1.0f))

This is calculated to find the time of next emission. However, if the calculated value is less than 1, 1 is used. This means there is no emission until the next frame even if a random number is included.

Emit Volume

The following calculation is performed at each time of emission.

emission_volume * (1.0f + emission_volume_random * random_number_between(-1.0f, +1.0f))

  The integer part of the accumulated value is the number of particle to be emitted at time of evaluation.

As an exception, an emission volume less than 1 is handled as 1 at time of first evaluation if the emitter's emission volume exceeds 0. This is due to the fact that, even though it may take a long time to accumulate a value of 1 given emission volume values less than 1, there are many cases where you want to emit exactly one particle in the first frame.
If this operation bothers you, either make it so that the emitter is not evaluated until actual time of emission or control things so the emission volume is 0.


CONFIDENTIAL