Page 1 of 2

MotionTrailSceneNode

Posted: Sun May 10, 2015 1:18 pm
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

Re: MotionTrailSceneNode

Posted: Sun May 10, 2015 1:36 pm
by hendu
Pardon me for a juvenile moment, but you might want to consider different naming for your enum.
EMTIT_SMOOTH

Re: MotionTrailSceneNode

Posted: Sun May 10, 2015 2:44 pm
by Foaly
What about E_MOTION_TRAIL_INTERPOLATION_MODE?

Posted: Mon May 11, 2015 3:50 pm
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...

Re: MotionTrailSceneNode

Posted: Mon May 11, 2015 4:20 pm
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 :-)

Re: MotionTrailSceneNode

Posted: Thu May 14, 2015 7:19 am
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?

Re: MotionTrailSceneNode

Posted: Thu May 14, 2015 8:36 pm
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.

Re: MotionTrailSceneNode

Posted: Fri May 15, 2015 1:24 pm
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.

Re: MotionTrailSceneNode

Posted: Fri May 15, 2015 3:48 pm
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.

Re: MotionTrailSceneNode

Posted: Fri May 15, 2015 4:59 pm
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

Re: MotionTrailSceneNode

Posted: Fri May 15, 2015 8:41 pm
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.

Re: MotionTrailSceneNode

Posted: Fri May 15, 2015 8:54 pm
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.

Released!

Posted: Sat May 16, 2015 12:43 pm
by Foaly
Done! Patch + screenshot in the first post.

Re: MotionTrailSceneNode

Posted: Sat May 16, 2015 3:11 pm
by CuteAlien
Thanks, I'll look at it soon (once I feel a little better again, still ill).

Re: MotionTrailSceneNode

Posted: Tue Jun 02, 2015 9:03 pm
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!