[solved]particleEmitter location on parent

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
pilesofspam
Posts: 62
Joined: Mon May 11, 2009 4:31 am

[solved]particleEmitter location on parent

Post by pilesofspam »

I've spent 2 days on this, and I'm sure the answer is simple, but I just can't figure it out on my own.

I've got a pirate ship mesh moving according to a straightlineanimator, and I'm shooting a cannonball at it (I'm doing some physics on the cannonball so it drops, so that's in an animation loop with a frametimer). I'm doing hit detection this way, which basically draws a line between the current frame's movement of the cannonball and checks for an object hit (the pirate ship is the only thing out there) in that line with getCollisionPoint.

Here's my problem: I want to know where the ball hit, so I can place a child particle emitter there. If I leave constants in the core::aabbox3d part of the createBoxEmitter, it always shows up right in the middle of the ship and then follows the ship. Very cool, but I want to displace it to where the cannonball actually hit and have it follow there. Any of my attempts to put a variable in there really throw off the location of my emitter.

Code: Select all

    if (activecannonballs > 0) {
            core::vector3df nodePosition = cannonball->getPosition();
            core::vector3df shipPosition = shipnode->getPosition();
            line.start=nodePosition;
            nodePosition.X += cannonballgravity[0] * frameDeltaTime;
            nodePosition.Y += cannonballgravity[1] * frameDeltaTime;
            nodePosition.Z += cannonballgravity[2] * frameDeltaTime;
            cannonballgravity[1] -= gravity * frameDeltaTime;
            cannonball->setPosition(nodePosition);
            line.end=nodePosition;

            if (smgr->getSceneCollisionManager()->getCollisionPoint(line, selector, intersection, tri)){  //there was a hit!
                movetheboat = smgr->createFlyStraightAnimator((shipPosition),core::vector3df(shipPosition.X,shipPosition.Y-900,shipPosition.Z), 7000, false);
                if (movetheboat)
                    {
                        shipnode->addAnimator(movetheboat);
                        movetheboat->drop();
                    }
                    scene::IParticleSystemSceneNode* ps =
                        smgr->addParticleSystemSceneNode(false,shipnode);
                    // put smoke on the boat
                    scene::IParticleEmitter* em = ps->createBoxEmitter(
                        core::aabbox3d<f32>(-14 , 0, -14, 14, 1, 14), // emitter size
                        core::vector3df(0.0f,0.3f,0.0f),   // initial direction
                        150,200,                             // emit rate
                        video::SColor(0,50,50,50),       // darkest color
                        video::SColor(0,200,200,200),       // brightest color
                        800,2000,0,                         // min and max age, angle
                        core::dimension2df(30.f,30.f),         // min size
                        core::dimension2df(80.f,80.f));        // max size

                    ps->setEmitter(em); // this grabs the emitter
                    em->drop(); // so we can drop it here without deleting it

                    scene::IParticleAffector* paf = ps->createFadeOutParticleAffector(video::SColor(0,255,255,255));

                    ps->addAffector(paf); // same goes for the affector
                    paf->drop();


                    ps->setScale(core::vector3df(4,4,4));
                    ps->setMaterialFlag(video::EMF_LIGHTING, false);
                    ps->setMaterialFlag(video::EMF_ZWRITE_ENABLE, true);
                    ps->setMaterialTexture(0, driver->getTexture("./cloud3.png"));
                    ps->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL);
            }

    // dump the cannonball if its gone far enough
            float distance=sqrtf(nodePosition.X * nodePosition.X + nodePosition.Y * nodePosition.Y + nodePosition.Z * nodePosition.Z);
            if ((nodePosition.Y < -30) || distance > MaxDistance) {
                cannonball->remove();
                activecannonballs=0;
            }
    }
Any ideas are greatly appreciated! I've tried all manners of nodePosition - shipPosition in the boxemitter location, but it _really_ displaces the emitter to somewhere I'm not expecting it.
Last edited by pilesofspam on Wed May 13, 2009 1:38 pm, edited 1 time in total.
pilesofspam
Posts: 62
Joined: Mon May 11, 2009 4:31 am

Post by pilesofspam »

I'm not sure yet, but I think the hint I've missed is here:

http://irrlicht.sourceforge.net/phpBB2/ ... tion+child

Specifically,
The unit of measurement is the scale of the parent node. AFAIK, it always has been. I can't see this changing, since (for example) you have a child positioned on the surface of a sphere node, and you double the dimensions of the parent, you'd want the child to remain at the surface, i.e. you'd have to double its relative position.
I'll play with this tonight and report back.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

If you want to attach the particle system to the ship, you need to calculate the position that the cannon ball hits the ship in the ship coordinate system (relative to the ships origin and rotation).

Assuming that you have a line that has start and end points that represent the position of the ball at time T and T+1 in world coordinates, all you'd need to do is transform that line into ship coordinates, and calculate the point of intersection of that line and the ship. You can do this by transforming the start and end points of the line by the inverse of the ships absolute transformation matrix and then using the collision manager getCollisionPoint() function.

Travis
pilesofspam
Posts: 62
Joined: Mon May 11, 2009 4:31 am

Post by pilesofspam »

Thank you Travis! That did it. Now I get it. Here's the important parts of the code for anybody who's just tuning in. Watch for this line: ishipTransform.transformVect( BallPos );:

Code: Select all

   if (activecannonballs > 0) {
            core::vector3df nodePosition = cannonball->getPosition();
            core::vector3df shipPosition = shipnode->getPosition();
        //record the position of the cannonball
            vector3df BallPos = cannonball->getAbsolutePosition();
            line.start=nodePosition;
        //Do physics for the next cannonball position
            nodePosition.X += cannonballgravity[0] * frameDeltaTime;
            nodePosition.Y += cannonballgravity[1] * frameDeltaTime;
            nodePosition.Z += cannonballgravity[2] * frameDeltaTime;
            cannonballgravity[1] -= gravity * frameDeltaTime;
            cannonball->setPosition(nodePosition);
            line.end=nodePosition;

            if (smgr->getSceneCollisionManager()->getCollisionPoint(line, selector, intersection, tri)){  //there was a hit!
                movetheboat = smgr->createFlyStraightAnimator((shipPosition),core::vector3df(shipPosition.X,shipPosition.Y-900,shipPosition.Z), 7000, false);
                if (movetheboat)
                    {
                        shipnode->addAnimator(movetheboat);
                        movetheboat->drop();
                    }

                    scene::IParticleSystemSceneNode* ps =
                        smgr->addParticleSystemSceneNode(false,shipnode);

                    scene::IParticleEmitter* em = ps->createBoxEmitter(
                        core::aabbox3d<f32>(-14 , 0, -14, 14, 1, 14), // emitter size
                        core::vector3df(0.0f,0.3f,0.0f),   // initial direction
                        150,200,                             // emit rate
                        video::SColor(0,50,50,50),       // darkest color
                        video::SColor(0,200,200,200),       // brightest color
                        800,2000,0,                         // min and max age, angle
                        core::dimension2df(30.f,30.f),         // min size
                        core::dimension2df(80.f,80.f));        // max size
                    vector3df psPos = ps->getAbsolutePosition();        //absolute pos of the particle emitter
                    matrix4 ishipTransform = shipnode->getAbsoluteTransformation();  //ships transformation matrix
                    ishipTransform.makeInverse(); //inverse matrix of the ship

                    ishipTransform.transformVect( BallPos ); //THIS IS IT-- this is the line that transforms the ball position
                    // into ship coordinates
                        
                        
                    ps->setPosition(BallPos);  //and so now we place the emitter there
                        
                    ps->setEmitter(em); // this grabs the emitter
                    em->drop(); // so we can drop it here without deleting it

                    scene::IParticleAffector* paf = ps->createFadeOutParticleAffector(video::SColor(0,255,255,255));

                    ps->addAffector(paf); // same goes for the affector
                    paf->drop();


                    ps->setScale(core::vector3df(4,4,4));
                    ps->setMaterialFlag(video::EMF_LIGHTING, false);
                    ps->setMaterialFlag(video::EMF_ZWRITE_ENABLE, true);
                    ps->setMaterialTexture(0, driver->getTexture("./cloud3.png"));
                    ps->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL);
            }

    // dump the cannonball if its gone far enough
            float distance=sqrtf(nodePosition.X * nodePosition.X + nodePosition.Y * nodePosition.Y + nodePosition.Z * nodePosition.Z);
            if ((nodePosition.Y < -30) || distance > MaxDistance) {
                cannonball->remove();
                activecannonballs=0;
            }
For further reseach check out tmx's tutorial thread:
http://irrlicht.sourceforge.net/phpBB2/ ... ion+matrix
Post Reply