MotionTrailSceneNode

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

MotionTrailSceneNode

Post by Foaly »

Interface:

Code: Select all

// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
 
#ifndef __I_MOTION_TRAIL_SCENE_NODE_H_INCLUDED__
#define __I_MOTION_TRAIL_SCENE_NODE_H_INCLUDED__
 
#include "ISceneNode.h"
 
namespace irr
{
namespace scene
{
 
//! Possible facing directions for the IMotionTrailSceneNode.
enum E_MOTION_TRAIL_FACING_DIRECTION
{
    //! Face toward the camera.
    EMTFD_CAMERA = 0,
 
    //! Face towards the camera and lock at a custom axis.
    /** You have to use setCustomAxis for this, or you will get warnings.*/
    EMTFD_CUSTOM_AXIS = 1,
 
    //! Set a custom facing direction per segment.
    /** You have pass the custom direction in every addSegment/setSegment call
    or you will get a warning.*/
    EMTFD_CUSTOM_PER_SEGMENT = 2
};
 
//! How to interpolate vertex colors and shrinking.
enum E_MOTION_TRAIL_INTERPOLATION_MODE
{
    //! Interpolate linearly.
    EMTIM_LINEAR = 0,
 
    //! Use a squareroot approximation to interpolate.
    /** Produces a very thick look.*/
    EMTIM_ROOT = 1,
 
    //! Square for interpolation.
    /** Makes the end very thin.*/
    EMTIM_QUADRATIC = 2,
 
    //! Use smoothstep (approx. remapped sine) for interpolation.
    /** Makes the mid thicker end the end thinner.*/
    EMTIM_SMOOTH = 3,
 
    //! Use a custom function. You have to pass a method pointer on setInterpolationType() to use this.
    /** Note: This cannot be serialized!*/
    EMTIM_CUSTOM = 4
};
 
//! Names for motion trail facing directions
const c8* const MotionTrailFacingDirectionNames[] =
{
    "camera",
    "customAxis",
    "customPerSegment",
    0
};
 
//! Names for motion trail interpolation modes
const c8* const MotionTrailInterpolationModeNames[] =
{
    "linear",
    "root",
    "quadratic",
    "smooth",
    "custom",
    0
};
 
//! A scene node for creating simple motion trails and other similiar special effects.
/**
It can either be lenght based oder time based.
Length based means, that you can set a maximum length, time based means, that
it gets longer if it's faster (which behaves more like a real light trail).
Note that the generated normals might not be the best. Anyways this is
meant to be used without lighting. If you need it, you should write a shader
which ignores normals.*/
class IMotionTrailSceneNode : public ISceneNode
{
public:
 
    //! constructor
    /** \param timeBased True for time based trails, false for length based.
    \param globalSpace True for using coordinates in global coordinate space, false for local.
    \param useCenterVertex Enables the center vertex, so a segment will have 3 instead of 2 verts.
    Should be used only if you use the vertex colors.*/
    IMotionTrailSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
        const core::vector3df& position = core::vector3df(0,0,0), u32 segmentCount = 32,
        bool timeBased = false, bool globalSpace = true, bool useCenterVertex = false,
        E_MOTION_TRAIL_FACING_DIRECTION facingDirection = EMTFD_CAMERA)
            : ISceneNode(parent, mgr, id, position) {}
 
 
    //! Adds a new segment to the motion trail.
    /** Use this version for length-based motion trails without custom direction.
    When you use the wrong one, it will log a warning.*/
    virtual void addSegment(const core::vector3df& position) = 0;
 
    //! Adds a new segment to the motion trail.
    /** Use this version for time-based motion trails without custom direction.
    When you use the wrong one, it will log a warning.*/
    virtual void addSegment(const core::vector3df& position, u32 currentTime) = 0;
 
    //! Adds a new segment to the motion trail.
    /** Use this version for length-based motion trails with a custom direction.
    When you use the wrong one, it will log a warning.*/
    virtual void addSegment(const core::vector3df& position, const core::vector3df& customDirection) = 0;
 
    //! Adds a new segment to the motion trail.
    /** Use this version for time-based motion trails with a custom direction.
    When you use the wrong one, it will log a warning.*/
    virtual void addSegment(const core::vector3df& position, const core::vector3df& customDirection, u32 currentTime) = 0;
 
 
    //! Sets a segment directly.
    /** If the motion trail hasn't got that many segments, it will be increased.
    Use this version for length-based motion trails without custom direction.
    When you use the wrong one, it will log a warning.*/
    virtual void setSegment(u32 index, const core::vector3df& position) = 0;
 
    //! Sets a segment directly.
    /** If the motion trail hasn't got that many segments, it will be increased.
    Use this version for length-based motion trails with a custom direction.
    When you use the wrong one, it will log a warning.*/
    virtual void setSegment(u32 index, const core::vector3df& position, const core::vector3df& customDirection) = 0;
 
    //! Sets a segment directly.
    /**If the motion trail hasn't got that many segments, it will be increased.
    Use this version for time-based motion trails without custom direction.
    When you use the wrong one, it will log a warning.*/
    virtual void setSegment(u32 index, const core::vector3df& position, u32 currentTime) = 0;
 
    //! Sets a segment directly.
    /** If the motion trail hasn't got that many segments, it will be increased.
    Use this version for time-based motion trails with a custom direction.
    When you use the wrong one, it will log a warning.*/
    virtual void setSegment(u32 index, const core::vector3df& position, const core::vector3df& customDirection, u32 currentTime) = 0;
 
    //! Removes all segments.
    /** Can be used for example, if you want to teleport the tracked object.*/
    virtual void clearSegments() = 0;
 
    //! Sets the axis to lock the segments on.
    /** You have to call this, when using the facing direction EMTFD_CUSTOM_AXIS,
    otherwise you cannot use it.*/
    virtual void setLockedAxis(const core::vector3df& lockAxis) = 0;
 
    //! Sets the maximum length of the motion trail.
    /** Can only be used in lenght-based mode.*/
    virtual void setLength(f32 length = 10.0) = 0;
 
    //! Sets the lifetime of a segment.
    /** Can only be used in time-based mode.*/
    virtual void setLifetime(u32 lifetime = 10000) = 0;
 
    //! Sets the width.
    virtual void setWidth(f32 width = 1.0) = 0;
 
    //! Sets whether and where the motion trail should shrink.
    /** \param clipEnd Whether or not to clip the last segment to the maximum length.*/
    virtual void setShrinkDirection(bool shrinkTip = false, bool shrinkEnd = false, bool clipEnd = true) = 0;
    
    //! Set the interpolation mode for vertex colors and shrinking.
    virtual void setInterpolationMode(E_MOTION_TRAIL_INTERPOLATION_MODE interpolationType = EMTIM_LINEAR) = 0;
 
    //! Set the interpolation mode for vertex colors, texture coordinates and shrinking.
    /** \param interpolationFunc A method which takes a value from 0(tip) to 1(end)
    and returns a value from 0 to 1.*/
    virtual void setInterpolationMode(f32 (*interpolationFunc)(f32)) = 0;
 
    //! Sets the vertex colors.
    virtual void setVertexColors(
        video::SColor tip = video::SColor(255, 255, 255, 255),
        video::SColor end = video::SColor(0, 255, 255, 255)) = 0;
 
    //! Sets the vertex colors.
    /** You can only use this version, if you use the center vertex.*/
    virtual void setVertexColors(
        video::SColor tipCenter = video::SColor(255, 255, 255, 255),
        video::SColor tipEdge = video::SColor(255, 255, 255, 255),
        video::SColor endCenter = video::SColor(0, 255, 255, 255),
        video::SColor endEdge = video::SColor(0, 255, 255, 255)) = 0;
 
    //! Returns whether the trail is time based. If not, it is length based.
    virtual bool isTimeBased() const = 0;
};
 
} // end namespace scene
} // end namespace irr
 
#endif
All features that can be seen in the header are implemented.
Also, the scene manager has these new methods:

Code: Select all

//! Adds a motion trail scene node.
        /** \param timeBased True for time based trails, false for length based.
        \param globalSpace True for using coordinates in global coordinate space, false for local.
        \param useCenterVertex Enables the center vertex, so a segment will have 3 instead of 2 verts.
        Should be used only if you use the vertex colors, because it doubles the triangle count.
        Useless for texturing.*/
        virtual IMotionTrailSceneNode* addMotionTrailSceneNode(
            ISceneNode* parent = 0, s32 id=-1,
            const core::vector3df& position = core::vector3df(0,0,0), u32 segmentCount = 32,
            bool timeBased = false, bool globalSpace = true, bool useCenterVertex = false,
            E_MOTION_TRAIL_FACING_DIRECTION facingDirection = EMTFD_CAMERA) = 0;
 
        //! Adds a preset time based motion trail.
        /** \param attach The scene node, the motion trail should be attached to.
        \param segmentCount The count of segments to be used. Higher means smoother but also slower.
        \param lifetime The length of the trail in ms.
        \param useCenterVertex Enables the center vertex, so a segment will have 3 instead of 2 verts.
        Should be used only if you use the vertex colors, because it doubles the triangle count.
        Useless for texturing.
        \param lockedAxis An axis on which the trail is locked. A zero vector means no lock.*/
        virtual IMotionTrailSceneNode* addMotionTrailTimeBased(
            ISceneNode* attach, u32 segmentCount = 32, u32 lifetime = 1000,
            bool useCenterVertex = false, const core::vector3df& lockAxis = core::vector3df(0)) = 0; 
 
        //! Adds a preset length based motion trail.
        /** \param attach The scene node, the motion trail should be attached to.
        \param segmentCount The count of segments to be used. Higher means smoother but also slower.
        \param length The length of the trail in Irrlicht units.
        \param useCenterVertex Enables the center vertex, so a segment will have 3 instead of 2 verts.
        Should be used only if you use the vertex colors, because it doubles the triangle count.
        Useless for texturing.
        \param lockedAxis An axis on which the trail is locked. A zero vector means no lock.*/
        virtual IMotionTrailSceneNode* addMotionTrailLengthBased(
            ISceneNode* attach, u32 segmentCount = 32, f32 length = 10,
            bool useCenterVertex = false, const core::vector3df& lockAxis = core::vector3df(0)) = 0; 
 
        //! Adds a lightning.
        /** \param start The tip of the lightning.
        \param end The end of the lightning.
        \param segmentCount More segments makes the lightning have more 'wrinkles'.
        \param maxOffset How far the segments should be offset at maximum. Higher makes it look spikier.
        \param lifetime If set to 0, the lightning will stay forever and change its shape. If you set a lifetime, it will fade out.
        \param addTime Current time. Only needed, if the lightning fades out (lifetime > 0).*/
        virtual IMotionTrailSceneNode* addLightning(
            const core::vector3df& start, const core::vector3df& end,
            u32 segmentCount = 32, f32 maxOffset = 1.0, u32 lifetime = 0, u32 addTime = 0) = 0;
Everything is tested. For the serialization I'm not 100% sure, but at least it does not crash.
Problems / missing stuff:
- attached trails don't work after deserialization
- not yet possible to attach to bones
- wind (?)

Here's the patch (only the vs2010 project file was used, example added to 08.SpecialFX):here
Image
Last edited by Foaly on Sun Feb 11, 2018 9:23 am, edited 4 times in total.
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: MotionTrailSceneNode

Post by hendu »

Pardon me for a juvenile moment, but you might want to consider different naming for your enum.
EMTIT_SMOOTH
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: MotionTrailSceneNode

Post by Foaly »

What about E_MOTION_TRAIL_INTERPOLATION_MODE?
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Post by Foaly »

Can I add the motion trail to example 08.SpecialFX? So I don't have to create a separate one.

And I assume it has to be serializeable? For that, I've got the problem, that I allow the user to use a custom interpolation function, which might be invalid when loading.
And I'll have to add all the animators and that to the factories. So this will probably take a few days...
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: MotionTrailSceneNode

Post by CuteAlien »

I don't think we need an example for the engine. But if we add it to some I guess that's the best. Basically I just need something to test it before I can add it to the engine.

Serializable - yes. Just ignore the custom interpolation function, people have to set that per code. But data should be serialized. You don't have to care about animators and factories - I can do that. I think animators are not serialized anyway as part of scene-nodes (not sure right now).

And take your time, no need to hurry :-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: MotionTrailSceneNode

Post by Foaly »

Is it possible to store a pointer to a scene node in serialization?
Because I want to be able to attach the trail to a node, which would be lost during serialization. (I don't want to do it using the parent, I want to store the node in the animator.)

And how can I serialize the material?

And how can I add a scene node animator to the ESCENE_NODE_ANIMATOR_TYPE enum without breaking it? Do I have to add it before the ESNAT_COUNT or after the ESNAT_UNKNOWN?
Last edited by Foaly on Sat May 16, 2015 12:01 pm, edited 1 time in total.
chronologicaldot
Competition winner
Posts: 684
Joined: Mon Sep 10, 2012 8:51 am

Re: MotionTrailSceneNode

Post by chronologicaldot »

Sorry, the engine isn't designed for that in serialization (linking nodes like that). But because of that, I was able to control construction of, for instance, the GUI tabbing system. I created a system for loading GUI elements from XML using irrlicht's serialization system, and its possible for someone to do the same thing for scene nodes.
However, you might check out ISceneManager::saveScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node) and consider implementing ISceneUserDataSerializer. I haven't looked into it much there, but it might help you save an index to the scene node of interest in order to allow linking to nodes. Notably, it makes no sense to store a "pointer" to a scene node, since it would be invalid when the program loaded again anyways.

For a custom program, you could probably just use ESNAT_UNKNOWN (I'm not sure what you're doing). Either that, or add it after ESNAT_UNKNOWN. But don't add it before ESNAT_COUNT.
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: MotionTrailSceneNode

Post by Foaly »

chronologicaldot wrote:For a custom program, you could probably just use ESNAT_UNKNOWN (I'm not sure what you're doing). Either that, or add it after ESNAT_UNKNOWN. But don't add it before ESNAT_COUNT.
This is meant to be added to the Irrlicht engine and will be added to the default scene node animator factory, for example. So I think it has to be added before the ESNAT_COUNT. But I'm not sure, whether I have to change some values elsewhere to make it work.
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: MotionTrailSceneNode

Post by Foaly »

By the way, I've got another question:
Does anybody know a simple function which is similar to the squareroot(x) where 0 < x < 1? Because that function creates a pretty nice shape, but it's really expensive doing it every frame for every segment.
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: MotionTrailSceneNode

Post by hendu »

Foaly wrote:By the way, I've got another question:
Does anybody know a simple function which is similar to the squareroot(x) where 0 < x < 1? Because that function creates a pretty nice shape, but it's really expensive doing it every frame for every segment.
Multiple alternatives to that:
1) Use Q3's fast sqrt approximation
2) Precalculate a table
3) Ask wolframalpha
4) Record ten values of it between 0 and 1, then ask libreoffice for a polynomial approximation
5) If the specific curve is not needed, just move to smootherstep, I use it for almost everything involving animation
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Re: MotionTrailSceneNode

Post by Foaly »

hendu wrote:If the specific curve is not needed, just move to smootherstep, I use it for almost everything involving animation
The motion trail allows you to choose between different interpolation functions (smoothstep is possible as well), but sqrt makes the streaks look thick.

I just asked in case someone had a function for that already.
chronologicaldot
Competition winner
Posts: 684
Joined: Mon Sep 10, 2012 8:51 am

Re: MotionTrailSceneNode

Post by chronologicaldot »

Foaly wrote:
chronologicaldot wrote:For a custom program, you could probably just use ESNAT_UNKNOWN (I'm not sure what you're doing). Either that, or add it after ESNAT_UNKNOWN. But don't add it before ESNAT_COUNT.
This is meant to be added to the Irrlicht engine and will be added to the default scene node animator factory, for example. So I think it has to be added before the ESNAT_COUNT. But I'm not sure, whether I have to change some values elsewhere to make it work.
In that case, add it before COUNT. It would be better there, since if it's part of the engine, the user isn't going to know it exists (per say) and may still want to iterate through all of the options, in which case, COUNT needs to represent all of them - including yours.
Foaly
Posts: 142
Joined: Tue Apr 15, 2014 8:45 am
Location: Germany

Released!

Post by Foaly »

Done! Patch + screenshot in the first post.
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: MotionTrailSceneNode

Post by CuteAlien »

Thanks, I'll look at it soon (once I feel a little better again, still ill).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: MotionTrailSceneNode

Post by CuteAlien »

Code looks very good on a quick view, but it's a little more than I expected. So have to find a longer evening for this than I got tonight :-). Weekend also planned out already... but I'll get to it soon!
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply