Precautions

This page describes the various precautions to keep in mind when using particles.

Precautions when Calling ParticleSet::UpdateParticle Multiple Times

When there is only a single command buffer, it is possible to call UpdateParticle multiple times within a single frame. When command buffers are doubled, the implementation makes alternate use of the rendering buffers (doubled) within the particles, so it is not possible to UpdateParticle multiple times within a single frame.

    Ex: Calling UpdateParticle multiple times within a single frame when command buffers are doubled
    CPU: UpdateParticle(DrawBuff0) -> UpdateParticle(DrawBuff1)
    GPU: Draw(DrawBuff1)

    In the second call, UpdateParticle(DrawBuff1), overwrites DrawBuff1 as its being processed by the GPU.
    

Use one of the following approaches to allow calling UpdateParticle multiple times in a single frame.

Delete Shader Resources During Binary Output

During ordinary binary output with no arguments specified, the binary includes shader resources. Delete shader resources from the binary output to reduce the particle binary file size by up to 70%. However, when loading binaries without shader resources, you must attach the shader resources to load separately. See ResGraphicsFile Operations for details.

Delete Unnecessary Animation Members

Delete any unnecessary animation members to reduce the binary file size by up to 15%. Deleting these from the binary files should be quite effective for particle data that does not use material animations. See Optimization Tips for details.

    Sample XML with all animation members deleted:
    
    <?xml version="1.0" encoding="utf-8"?>
    <OptimizeAnimationMemberSettings>
      <Filters Mode="positive">
      </Filters>
    </OptimizeAnimationMemberSettings>

Precautions when Using Doubled Command Buffers

When command buffers are doubled, the implementation makes alternate use of the rendering buffers (doubled) within the particles, so you cannot update or change the rendering order.

    Ex: Rendering after updating

    0th frame:
    CPU: UpdateParticle(DrawBuff0) → Draw(DrawBuff0)
    GPU:  -

    1st frame:
    CPU: UpdateParticle(DrawBuff1) → Draw(DrawBuff1)
    GPU: Draw(DrawBuff0)

    2nd frame:
    CPU: UpdateParticle(DrawBuff0) → Draw(DrawBuff0)
    GPU: Draw(DrawBuff1)


    Ex: Updating after rendering

    0th frame:
    CPU: Draw(DrawBuff0) → UpdateParticle(DrawBuff1)
    GPU:  -

    1st frame:
    CPU: Draw(DrawBuff1) → UpdateParticle(DrawBuff0)
    GPU: Draw(DrawBuff0)

    UpdateParticle overwrites DrawBuff0 as the GPU is processing it.

Precautions when Deleting Instances

Deleting an instance at the wrong time can cause the destruction of a particle's rendering buffer as it is in use by the GPU, possibly causing the GPU to hang.

    Ex: When there are only single command buffers
    CPU: UpdateParticle(DrawBuff0) → Draw(DrawBuff0)        
    GPU:                                   → Draw(DrawBuff0)

    It is dangerous to delete an instance after CPU rendering.
    To delete after CPU rendering, wait until the GPU is done processing.


    Ex: When command buffers are doubled
    CPU: UpdateParticle(DrawBuff0) → Draw(DrawBuff0)
    GPU: Draw(DrawBuff1)

    The preceding frame's rendering buffer is used by the GPU. You must factor this in when deleting an instance.
    (Such as by halting the render and deleting one frame later)

Precautions Regarding Random Numbers

The ParticleContext, ParticleEmitter, and ParticleSet classes all have objects of the ParticleRandom class. You must configure an appropriate seed for each of these ParticleRandom objects. Use the ParticleUtil::SetupParticleObject function to properly configure the random number seed. Not using this function will result in the animation using the same fixed particle emission pattern each time, so you must properly configure the random number seed on the user side for the ParticleEmitter and ParticleSet objects.

About Reusing Instances

Particle creation and destruction are very expensive processes. Every time the effect occurs, an instance (node) is generated and then destroyed again after playback, causing considerable CPU processing load. Nintendo recommends deleting unnecessary instances beforehand and reusing instances where possible.

Ex: How to reuse an instance

Generates nodes.
nw::gfx::ParticleModel*   particleModel   = nw::gfx::SceneBuilder();
nw::gfx::ParticleEmitter* particleEmitter = nw::gfx::SceneBuilder();

// Attach node to scene.
sceneRoot->AttachChild(particleModel);
sceneRoot->AttachChild(particleEmitter);

   :

// Detach from scene once scene is done playing.
sceneRoot->DetachChild(particleModel);
sceneRoot->DetachChild(particleEmitter);

   :

// When reusing, reset ParticleModel and ParticleEmitter objects, and reattach to the scene.
// 
particleEmitter->Reset();
particleModel->ForeachParticleSet(nw::gfx::ParticleSetsClear());
particleModel->ParticleAnimFrameController().SetFrame(0.f);

sceneRoot->AttachChild(particleModel);
sceneRoot->AttachChild(particleEmitter);

When using doubled command buffers, take care when calling nw::gfx::ParticleSetsClear, as this can wind up clearing the buffer referenced by the GPU.

About Instances that Are Done Playing

Nintendo recommends immediately detaching nodes once they are done playing to reduce the processing load. Use code like the following to check if a node is done playing.
Ex: Code sample for checking if a node is done playing
bool IsDone()
{
    nw::gfx::ParticleModel*   particleModel;
    nw::gfx::ParticleEmitter* particleEmitter;

    // Are any particles playing?
    if  (particleModel->HasParticle())
    {
        return false;
    }

    // Is emitter done?
    if (particleEmitter->IsAlive())
    {
        return false;
    }

    return true;
}

CONFIDENTIAL