A little debugging reveals that the post-bounce Velocity Vector is ALWAYS 0,0,0 regardless of the input Velocity - there's something wrong with my implementation !! I'll rework it and see what happens..
Posted on 2003-12-18 23:41:31 by Homer
Further debugging reveals something VERY weird.

First I'll show some of my debug logfile output, then the snippet of code which generated it.


PlaneNormal x=0 y=1 z=0, DotProduct f=0.000000e+647
V.x=0 y=-0.294 z=0
Vn x=0 y=1.865552e-038 z=0
Vt.x=0 y=-0.294 z=0 (where Vt=V-Vn)
New Velocity Vector x=0 y=0 z=0

The problem is the calculation of Vt=V-Vn
How can this be happening?
Look closely.
If Y1=-0.294
and Y2=(a really small value)
and Y3=Y1-Y2
How the hell do I end up with Y3=Y1?
What the hell is happening here? FPU rounding error?
My debug function preserves esi and ecx @ Scronty :tongue:

invoke D3DXVec3Dot, addr .Plane.m_vNormal, addr vOldVelocity
mov ftemp,eax ;store Dot Product result
DebugFloat addr ErrBuf,CTEXT("DotProduct f=%s",13,10), ftemp

DebugFloat addr ErrBuf,CTEXT("V.x=%s "), vOldVelocity.x
DebugFloat addr ErrBuf,CTEXT("y=%s "), vOldVelocity.y
DebugFloat addr ErrBuf,CTEXT("z=%s ",13,10), vOldVelocity.z

mov esi,pPlane ;just in case api messes our registers
mov ecx,pParticle
fld .Plane.m_vNormal.x
fmul ftemp
fstp Vn.x
fld .Plane.m_vNormal.y
fmul ftemp
fstp Vn.y
fld .Plane.m_vNormal.z
fmul ftemp
fstp Vn.z
DebugFloat addr ErrBuf,CTEXT("Vn x=%s "), Vn.x
DebugFloat addr ErrBuf,CTEXT("y=%s "), Vn.y
DebugFloat addr ErrBuf,CTEXT("z=%s ",13,10), Vn.z

fld vOldVelocity.x
fsub Vn.x
fstp Vt.x
fld vOldVelocity.y
fsub Vn.y
fstp Vt.y
fld vOldVelocity.z
fsub Vn.z
fstp Vt.z
DebugFloat addr ErrBuf,CTEXT("Vt.x=%s "), Vt.x
DebugFloat addr ErrBuf,CTEXT("y=%s "), Vt.y
DebugFloat addr ErrBuf,CTEXT("z=%s (where Vt=V-Vn)",13,10), Vt.z
Posted on 2003-12-19 00:40:41 by Homer

V.x=0 y=-0.294 z=0
Vn x=0 y=1.865552e-038 z=0
Vt.x=0 y=-0.294 z=0 (where Vt=V-Vn)
New Velocity Vector x=0 y=0 z=0

The problem is the calculation of Vt=V-Vn
How can this be happening?
Look closely.
If Y1=-0.294
and Y2=(a really small value)
and Y3=Y1-Y2
How the hell do I end up with Y3=Y1?
What the hell is happening here? FPU rounding error?

its just the physical way of floats are: numbers between 1.0-1.0e+-minmax exp, with only space for a certain number of significant digits
the big difference between the exp in this case. close to -1.0 size and 38 digits below that makes it impossible to use the precision for that fsub, so fpu tries it best and ends up Y3=Y1-0 because you certainly dont have 38 digit precision in a float
so I dont see anything wrong with your code, its just the fpu and floats behaviour that causes it

test to add a fmul Y2, with for example 1.0e+30 something before the fsubs and see what happens
Posted on 2003-12-19 07:11:55 by daydreamer
If that is the case, how come the original cpp version works? As far as I am concerned , if the fpu can encode a given value, it should be able to perform subtraction, addition and multiplication with it, leaving only division because things get smaller... so are you saying that If I perform this fpu code using QWORDS or TWORDS that I'll find a magical fix? I agree the code looks fine...
Back in the real world, how can I round the floating point value UP to the next value which can usefully be used in a N bit basic math operation?
As for the *2, I tried that already too, it didn't seem to make any diff :(
Look for a small link early in this thread for a link to the original c++ source and exe.
Check out the code for the ParticleSystem::Update proc and nested in it the code for the planar collision testing.
Posted on 2003-12-19 10:04:41 by Homer
I've only read these last few posts but I see two things of note,

First, if Y2 is a very small value and Y3=Y1-Y2, then Y3 is approximatly Y1. That shouldn't be a problem except in scientific simulations I'd imagine.

More likely the cause is this DotProduct f=0.000000e+647. Thats not a real FPU value, the dotproduct isn't being worked out properly I fear.
Posted on 2003-12-19 16:07:03 by Eóin
I think I see it, floats are returned on the FPU stack. Try this;

invoke D3DXVec3Dot, addr .Plane.m_vNormal, addr vOldVelocity
fstp ftemp;store Dot Product result
Posted on 2003-12-19 16:09:32 by Eóin
I would agree that looks wrong, I'd assumed it was an issue in Hutch's FloatToString proc (used by my debug helpers) since it appears Vn=Normal Force is being calculated correctly, and the formula is simply
Vn=(N.V)*N Where
N=Normal of Plane which we are bouncing apon
V=Velocity prior to the collision

Looking again we see no problem with this PlaneNormal x=0 y=1 z=0,
just a floorplane facing up.
DotProduct f=0.000000e+647 does look odd I grant you,
but when multiplied with the Velocity prior to collision V.x=0 y=-0.294 z=0,
the result was Vn x=0 y=1.865552e-038 z=0 which looks ok, yes?
Finally, we want Vt=V-Vn, but when I subtract Vn.y from V.y it doesn't alter the value Vt.x=0 y=-0.294 z=0 is the New Velocity Vector, and we find we are still flying off in the same direction as before !! :(
Posted on 2003-12-19 20:41:38 by Homer
Altered it to fetch the fpu value, first results are as follows..
Vp (=Vt - f * Vn)

V.x=-3.104124 y=-0.3779874 z=3.120492
PlaneNormal x=0 y=1 z=0, DotProduct f=-0.3779874
Vn x=-0.000000e+647 y=-0.3779874 z=-0.000000e+647
Vt.x=-3.104124 y=0 z=3.120492 (where Vt=V-Vn)
Vp.x=0 y=0 z=0
Posted on 2003-12-19 21:06:42 by Homer
I suggest you singlestep thru that part with a debugger, to be absolutly sure how if the fpu stack is right
seem you endup with the same e+647 number later instead, must be a fpustack problem
and singlestep so you see what happens inside the fpu when subtracting with so small numbers
e+647 must either be marked as NaN or infinity
Posted on 2003-12-19 21:38:02 by daydreamer
Working on it - got bouncing working :)
Post soon :tongue:
Posted on 2003-12-20 10:09:44 by Homer
Fixed Colors and Implemented Lerping Colors..
Have a blast :)
Posted on 2003-12-21 00:27:45 by Homer
I've just modified Ultrano's CLASS support a little to support $invoke style usage of the "malloc" macro, which meant that "new" macro also needed altering.
This allows us to use it anywhere we'd use eax, example syntax is:
mov pSomething, malloc (sizeof SomeMemory)
Bringing the malloc macro into line with the same changes made to "new",
mov pObjectInstance, new (ClassObject)
All instances of malloc were altered to use the new convention.
I'm currently implementing a CMesh class so we can get a quick SkyDome happening without too much pain, and have support for more meshes later.
As for that last update, you may have noticed that the systems quit working after a while if we roll through them all a couple of times.
The reason for this is a failure in the ResetParticleSystem procedure.
It's job basically is to shove all ActiveList particles on the FreeList.
Somehow, somewhere, the LinkedList system is losing track of some particles.
If we don't Reset the systems, we don't seem to encounter this error.
I'm thinking it would be a wise move to implement a LinkedList class very soon and any classes that need to can Inherit from it.
How about some feedback on the last posting - what would you like to see in a Particle Engine? I'm thinking about adding a Class Method to handle the emissions of Particles such that it could be used as a Triggered System for firing bullets etc.
Then the Update Method could call that instead for Timed Emissions.
Posted on 2003-12-21 21:33:34 by Homer
PII with TNT 16mb:
it seem to in the end of the particles journey, particles get stuck in the final position, hoovering there until a new particles comes and changes its color
all possible colors, framerate something 39fps, always stuck with #99 particles
AMD XP with geforce 5600 128mb:
looks great, yellow sun with orange border spitting out yellow particles, but ends up with #particles which are active=4294967269 and all particles have flown away in the end, leaving only dx-bg left on screen
first framerate 99fps, while particles are on screen, then it shows framerate 184 fps
this happens after a few seconds

ok its probably not intended for lowend hardware, but I test it anyway, as its probably good for you to know how it behaves on different hardware
Posted on 2003-12-21 21:41:16 by daydreamer
Yes, this problem of the negative #particles is caused in the procedure "ResetParticleSystem" as described above. If we remove the call to it (found in onChar WM handler) the issue seems to go away but not really.
The issue with older particles stacking up at the end of their travel is definitely related, its to do with the way the LinkedList currently operates - as particles die they are shoved on the top of the FreeParticles list. As particles are emitted, they are ALSO grabbed from the top of this list. When the current #particles active is high, no new particles are emitted, and so the ones which died first are the last to be recycled and vice versa. Not pretty. The obvious answer is to alter the LinkedList Manager behaviour to use a LIFO buffer instead of a FIFO one.
Less obvious is that LinkedLists are very common and should be encapsulated in their own Inheritable Class, which I'll probably do as soon as I get my SkySphere to render. I'm currently implementing a CMesh Class. Then I'll do the LinkedList Class, and write some optimisations into it to handle cases I've encountered in my earlier experiences with LinkedLists. The alternative for at least the Particle Lists is not to use a FreeList at all, but to flag dead particles individually. Finally, the particles lifespan is currently based on a timer kept in the owner System, whereas each particle should calculate its LifeSpan uniquely. Looks like I have a little work to do before I can claim my booby prize :)
Posted on 2003-12-21 22:43:43 by Homer
CMesh class was implemented, and used to implement a SkySphere.
This is a giant ball whose textured surfaces all face inwards.
The idea is that we have Day and Night on the texture and simply revolve the SkyMesh around the world, while modifying the ambient lighting to suit the "time of day".
Posted on 2003-12-22 00:52:29 by Homer
Just wrote two new classes: CLinked and CFrame
CMesh now inherits from CLinked, which gives it LinkedList support.
CFrame is not being implemented just yet, but also inherits from CLinked.
Now I'll encapsulate the Particle-specific code in a new class called CParticle which will likewise inherit from CLinked. Then I'll write some changes to ParticleSystem in order to use the new Linking class for keeping track of our elusive Particle Lists.
After I've done that I'll add Frames Support for placing several Meshes and / or ParticleSystems in the same frame of reference ;)
This will allow us to (for example) attach a couple of particlesystems to Scronty's Fighter.x model , and rotate and position them all together.
Posted on 2003-12-22 03:44:07 by Homer
cool, tested it with something from my own old dxproject
Posted on 2003-12-22 05:18:16 by daydreamer
Nice :)
Currently making those changes to stabilize the ParticleLists, and am currently thinking about ditching the FreeList altogether and not worrying about recycing Particles at all, but simply killing them and recreating them on demand.
The overhead is pretty small, even with the additional overhead of the CParticle class object as opposed to a simple LinkedList of Structs - it amounts to a "malloc" (HeapAlloc) and a handful of mov's, which shouldn't be too painful. I'll still try to fix the current scheme first, and if I get the shits on, I'll fall back on the simpler method.
Either way, I'll post an update soon, which includes all the new structs.
If I hit the evil filesize limit, I'll start posting on the space provided to me by Ultrano instead, and just post links.
Posted on 2003-12-22 07:22:27 by Homer
I've made a few small changes, like moving the Expire code for Particles into the CParticle class as a separate procedure.
New particles are now appended to the END of the ActiveList.
I'm going to create a default Particle in each new ParticleSystem to act as a static Head Particle which will alleviate some issues with the 2D-LL CLinked class.
Blah. It's all the same day, man.
Posted on 2003-12-22 08:56:32 by Homer