Archived

This topic is now archived and is closed to further replies.

leiavoia

plotting a graph through discreet units

Recommended Posts

i''m designing a simple particle system that in it''s current state makes fireworks. It''s very pretty. But what i''d like to do is draw a particle (a single pixel) and a "light trail" behind it. So i get the time the particle was "born" and the present time and then i can do the math to plot where the pixel will be, then i''d like to backtrack, say, 10 pixels and draw it''s "light trail". The problem is this: I have to backtrack 10 *pixels*, not 10 units of time. Why is this a problem? consider this simple example. Let''s plot an arc with some arbitrary math function:
*******************
*          XXXXXXX*
*       XXX       *
*     XX          *
*    X            *
*   X             *
*  X              *
* X               *
* X               *
*X                *
*X                *
*X                *
*X                *
*******************
My original plan was to step through the X-axis and just find the last 10 Y-points. This is pretty simple:
for (int x=0; x < 10; x++) {
     y = some_math_function( x );
     }
This will spit out a Y point for whatever you plug in for the last 10 steps. The problem is that this leaves holes! By that i mean, look at the theoretical graph above. If i use this technique to try to "Draw" this graph on the screen in pixels, it would come out like this:
*******************
*          XXXXXXX*
*       XXX       *
*     XX          *
*    X            *
*   X             *
*  X              *
*                 *
* X               *
*                 *
*                 *
*                 *
*X                *
*******************
You see the holes at the bottom left where it starts? This occurs because there are several places in between the first X and the second X point that could give back valid Y coords. If i reverse my technique and step through the Y coords and derive the X, i would leave gaps on the other side of the graph How can i create some drawing function that leaves no holes when plotting an arc? If i was simply drawing a line, i could find which axis to step through so that it would not make any holes. But with an arc, the only solution i can think of is to step through the X and Y and mix the two together afterward (but this is very sloppy of course). I''m stumped. Any ideas? Advice is much appreciated. Thank you.

Share this post


Link to post
Share on other sites
parametric curves are usually less troublesome for that type of effects. It''s especially simple if all you do is fire a rocket at an angle, and let the gravity do the rest.


anyway, if, for the rocket, you store previous positions in time in a FIFO queue, and connect those positions with segments (which should give a good approximation of the curve), you can walk along the segments with a given step, and render particles.

You can use any types of curves really, just connect the points with segments, and walk along the segments with a distance step. It''s similar to plotting curves on a screen, where the step would be one pixel.

Share this post


Link to post
Share on other sites
what properties of parametric curves make it easier? I may or may not want that since there is some possability i would want to change a particles speed/gavity/vector in flight (just for kicks)



This is what i''ve got now, and i''m using the "time snapshot method" you suggested. Every frame, it records it''s position, up to the last X number of frames. The problem is that it gets choppy (shown here) depending on the frame rate and speed of the particle. I would like to have fast particles that still leave nice clean trails. Right now, the faster it goes (or the slower the screen), the chunkier it gets. Especially noticable on the streaking decent of falling particles.

I like your connect-the-dots idea though. That would not be hard to do.

Share this post


Link to post
Share on other sites
you don''t have to record the particle position every frame. for trail effects in general, you can do this



class CTrail
{
public:
CTrail(float fDistance, float fLifeTime)
{
m_fDistance = fDistance;
m_fLifeTime = fLifeTime;
m_iFirst = 0;
m_iLast = 0;
}

// remove all points in the trail

void Clear()
{
m_iFirst = 0;
m_iLast = 0;
}

// report the last position in the trail

bool ReportLastPosition(const Vector& xPoint, float fGameTime)
{
if (m_iFirst == m_iLast)
{
// create first segment in the trail

m_iFirst = m_iLast = 0;
AddPoint(xPoint, fGameTime);
return true;
}

// check particle disatnce from last added particle

Vector xDiff = xPoint - m_xPoint[m_iLast];
float d = xDiff.Magnitude();

// new particle too close, no need to add it

if (d < m_fDistance)
return false;

// add particles along the segment, until the end of segment is reached

// (it''s a linear interpolation).

float dt = m_fDistance / d;

for(float t = dt; t < 0.999f; t += dt)
{
Vector P = xPoint + xDiff * t;
AddPoint(P, fGameTime);
}
return true;
}

void Update(float fGameTime)
{
for(int i = m_iFirst; i != m_iLast; i++)
{
if (i >= eNumTrailPoints)
i += eNumTrailPoints;

// remove old particles

float dt = fGameTime - m_fTime[i];

if (dt > m_fLifeTime)
m_iFirst = i;
}
}

int GetNumPoints() const
{
int iNum = m_iLast - m_iFirst;

if (iNum < 0)
iNum += eNumTrailPoints;

return iNum;
}

const Vector& GetPoint(int i) const
{
int iIndex = m_iFirst + i;

if (iIndex > eNumTrailPoints)
iIndex -= eNumTrailPoints;

return m_xPoint[iIndex];
}


private:
bool AddPoint(const Vector& xPoint, float fGameTime)
{
// find particle index to add new particle

int iNewIndex = m_iLast+1;

if (iNewIndex >= eNumTrailPoints)
iNewIndex -= eNumTrailPoints;

// if we ran out of space, delete the oldest particle

if (iNewIndex == m_iFirst)
{
m_iFirst = m_iFirst+1;

if (m_iFirst >= eNumTrailPoints)
m_iFirst -= eNumTrailPoints;
}

m_iLast = iNewIndex;
m_xPoint[m_iLast] = xPoint;
m_fTime [m_iLast] = fGameTime;

return true;
}
private:
// wrapper. to avoid things like :

// "if (m_iFirst >= eNumTrailPoints)...."

// use a power-of-2 number of trail points and do :

// "m_iFirst &= eWrapper"

enum { eNumTrailPoints = 32, eWrapper = eNumTrailPoints-1 };

Vector m_xPoint[eNumTrailPoints];
float m_fTime [eNumTrailPoints];

int m_iFirst;
int m_iLast;
float m_fDistance;
float m_fLifeTime;
};


... or somehting like that. a stack based system, that add particles if the new position is far enough from the last reported position. If the disatnce is too great, it generates extra steps along the segment from the last reported position to teh new reported position. if it''s too small, it does not insert a point in the trail.

this is untested code, I did that as I will use a similar system myself

Share this post


Link to post
Share on other sites
i''ve been tinkering with the idea this evening and came up with the following:

my original idea, like yours, was to keep a record of points visited to leave a trail. However, this comes at the cost of a lot of expensive position-saving overhead. I''ve sped up my sim by probably at *least* x5 by doing away with all of that. Now, i record the time the particle was born and on each frame i plot the particle at it''s current position and the last X positions before that (length of trail) at regular time intervals. My interval time is hardcoded at 10ms, but you can sharpen it in real time if your velocity is changing, tighten up the interval time to avoid the trail breaking up at high speeds, or getting too congested at low speeds.

This still doesn''t solve the original post''s problem, but perhaps this solution is "good enough"

Share this post


Link to post
Share on other sites
as I said, you have to generate intermediate points yourself if the gap is too great, by means of linear interpolation, or other techniques. also, line plotting algorithms use things like the bresendham algorithm to render two distant points on the screen.

Share this post


Link to post
Share on other sites