Beam scenenode

A forum to store posts deemed exceptionally wise and useful
cdbarrett
Posts: 1
Joined: Thu Nov 17, 2005 9:33 pm

Beam scenenode

Post by cdbarrett »

I got bored today and created this.
Draws 2 quads from point a to point b in a cross pattern.

Image

The node

Code: Select all

// Just a simple wrapper :D
struct IrrQuad {
	video::S3DVertex verts[4];
};

class CBeamNode : public scene::ISceneNode {
	private:
		// The beam material.
		video::SMaterial material;

		// Start/End Points
		core::vector3df vStart;
		core::vector3df vEnd;

		// Bounding Box
		core::aabbox3d<f32> Box;

		// Size of the beam
		float flScale;

		// Beam color
		video::SColor beamColor;

		void DrawQuad( IrrQuad& quad ) {
			u16 indices[] = { 0,2,3, 2,1,3, 1,0,3, 2,0,1 };
			video::IVideoDriver* driver = SceneManager->getVideoDriver();
			driver->setMaterial(material);
			driver->drawIndexedTriangleList( &quad.verts[0], 4, &indices[0], 4 );
		}

		// Thanks to whoever wrote this little function :)
		core::vector3df getTargetAngle( core::vector3df v, core::vector3df r) {
			//v -current node position
			//r -target node position

			core::vector3df angle;
			float x,y,z;
			x = r.X - v.X;
			y = r.Y - v.Y;
			z = r.Z - v.Z;

			//angle in X-Z plane
			angle.Y = atan2 (x, z);
			angle.Y *= (180 / 3.14); //converting from rad to degrees

			//just making sure angle is somewhere between 0-360 degrees
			if(angle.Y < 0) angle.Y += 360;
			if(angle.Y >= 360) angle.Y -= 360;

			//angle in Y-Z plane while Z and X axes are already rotated around Y
			float z1 = sqrt(x*x + z*z);

			angle.X = atan2 (z1, y);
			angle.X *= (180 / 3.14); //converting from rad to degrees
			angle.X -= 90;

			//just making sure angle is somewhere between 0-360 degrees
			if(angle.X < 0) angle.X += 360;
			if(angle.X >= 360) angle.X -= 360;

			return angle;
		} 

	public:

		CBeamNode( scene::ISceneNode* parent, scene::ISceneManager *mgr, s32 id, char* szBeam ) : scene::ISceneNode( parent, mgr, id ) {
			// Setup the beam material
			material.Wireframe = false;
			material.Lighting = false;
			material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
			material.Texture1 = mgr->getVideoDriver( )->getTexture( szBeam );

			// Default to 32 units for the scale
			flScale = 32.0;

			// Default to white
			beamColor.set( 255, 255, 255, 255 );
		}

		virtual void OnPreRender( ) {
			if( IsVisible ) {
				SceneManager->registerNodeForRendering( this );
			}
		}

		virtual void render( ) {
			// Figure out quads based on start/end points.
			core::matrix4 m;
			m.setRotationDegrees( getTargetAngle( vStart, vEnd ) );
			core::vector3df vUp( 0, 1, 0 );
			core::vector3df vRight( -1, 0, 0 );
			m.transformVect( vRight );
			m.transformVect( vUp );

			// Draw the first cross
			IrrQuad beam;
			beam.verts[0] = video::S3DVertex( vStart + vUp * flScale, core::vector3df( 1, 1, 0 ), beamColor, core::vector2df( 0, 1 ) );
			beam.verts[1] = video::S3DVertex( vStart + vUp * -flScale, core::vector3df( 1, 0, 0 ), beamColor, core::vector2df( 1, 1 ) );
			beam.verts[2] = video::S3DVertex( vEnd + vUp * -flScale, core::vector3df( 0, 1, 1 ), beamColor, core::vector2df( 1, 0 ) );
			beam.verts[3] = video::S3DVertex( vEnd + vUp * flScale, core::vector3df( 0, 0, 1 ), beamColor, core::vector2df( 0, 0 ) );
			DrawQuad( beam );

			// Draw the second cross.
			beam.verts[0] = video::S3DVertex( vStart + vRight * flScale, core::vector3df( 1, 1, 0 ), beamColor, core::vector2df( 0, 1 ) );
			beam.verts[1] = video::S3DVertex( vStart + vRight * -flScale, core::vector3df( 1, 0, 0 ), beamColor, core::vector2df( 1, 1 ) );
			beam.verts[2] = video::S3DVertex( vEnd + vRight * -flScale, core::vector3df( 0, 1, 1 ), beamColor, core::vector2df( 1, 0 ) );
			beam.verts[3] = video::S3DVertex( vEnd + vRight * flScale, core::vector3df( 0, 0, 1 ), beamColor, core::vector2df( 0, 0 ) );
			DrawQuad( beam );
		}

		virtual const core::aabbox3d<f32>& getBoundingBox() const {
			return Box;
		}

		virtual s32 getMaterialCount() {
			return 1;
		}

		virtual video::SMaterial& getMaterial(s32 i) {
			return material;
		} 

		void SetStartPoint( core::vector3df pos ) {
			vStart = pos;
		}

		void SetEndPoint( core::vector3df pos ) {
			vEnd = pos;
		}

		void SetBeamScale( float size ) {
			flScale = size;
		}

		void SetBeamColor( video::SColor color ) {
			beamColor = color;
		}
};
How to use.

Code: Select all

CBeamNode* beam = new CBeamNode( smgr->getRootSceneNode( ), smgr, 200, "laserbeam.bmp" );
beam->SetStartPoint( core::vector3df( -500, 0, 0 ) );
beam->SetEndPoint( core::vector3df( 500, 0, 0 ) );
beam->SetBeamColor( video::SColor( 255, 0, 255, 0 ) );
beam->drop( );
That creates a green laser beam using the given texture.
dracflamloc
Posts: 142
Joined: Sat Dec 11, 2004 8:13 am
Contact:

Post by dracflamloc »

Thats very handy thank you!
Guest

Post by Guest »

Noob question-sorry.

Where should

Code: Select all

 CBeamNode* beam = new CBeamNode( smgr->getRootSceneNode( ), smgr, 200, "laserbeam.bmp" );
beam->SetStartPoint( core::vector3df( -500, 0, 0 ) );
beam->SetEndPoint( core::vector3df( 500, 0, 0 ) );
beam->SetBeamColor( video::SColor( 255, 0, 255, 0 ) );
beam->drop( );
go?

thanks
sRc
Posts: 431
Joined: Thu Jul 28, 2005 1:44 am
Location: Salt Lake City, Utah
Contact:

Post by sRc »

Anonymous wrote:Noob question-sorry.

Where should

Code: Select all

 CBeamNode* beam = new CBeamNode( smgr->getRootSceneNode( ), smgr, 200, "laserbeam.bmp" );
beam->SetStartPoint( core::vector3df( -500, 0, 0 ) );
beam->SetEndPoint( core::vector3df( 500, 0, 0 ) );
beam->SetBeamColor( video::SColor( 255, 0, 255, 0 ) );
beam->drop( );
go?

thanks
the first 4 lines when you create it, and the drop() when you decide to get rid of it :)
The Bard sRc

Blog | Twitter
Guest

Post by Guest »

Ok thanks. I know where my problem was now. The line was drawn. It was just to small to see, maybe lol. I just put beam->SetBeamScale(0.5); and it worked :) nice work man
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

cool
very useful thank you :)
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
Saku
Posts: 158
Joined: Wed Jan 05, 2005 8:48 am
Location: Denmark

Post by Saku »

Just a little proposition; why not have the StartPoint, EndPoint and BeamColor as parameters in the CBeam from the start instead of having to call those functions later?
Seems more convinient ..well to me anyways ;)
Call me Wice, Miami Wice!
Midnight
Posts: 1772
Joined: Fri Jul 02, 2004 2:37 pm
Location: Wonderland

Post by Midnight »

what given texture??
afecelis
Admin
Posts: 3075
Joined: Sun Feb 22, 2004 10:44 pm
Location: Colombia
Contact:

Post by afecelis »

Nice work CdBarrett!

you could also upload your test app for us to try or see it in action immediately.

If you need someone to mirror it I could give you a hand with that. :wink:
Guest

Post by Guest »

Alternative suggestion (as the above looks like a lot of code to achieve this, but maybe it's just because other people tend to use comments).

You want a beam, so the widest side of the quad should be facing the camera. How to achieve that? Simple:

It is assumed that you build the beam starting at local origin and stretching along z. The texture is facing along y (considered "up"). The beam is just a a quad with corners
(width, 0, 0)
(-width, 0, 0)
(-width, 0, (end-begin).length)
(width, 0, (end-begin).length)

matrix mat={x,x,x,x, x,x,x,x, (end-begin).normalize, begin}
Meaning, the right and up vector of the matrix don't matter, the will be rebuild when rendering anyway. Forward is the direction of the beam, position is the starting point.

You have start and end point for the beam, that will be your z axis for the transformation. But we still need two more vectors. Actually just one, the third is the cross product.

Code: Select all

   vector3df zdir = end-begin;
   zdir.normalize();
   vector3df beamToCam = activeCamera->getAbsolutePosition().normalize();
//That's the important part. We want the "right" vector of the beam to be //perpendicular to the vector to the cam, so it will face as with maximum width.
   vector3df right = beamToCam.crossProduct(zdir);
   vector3df up = right.crossProduct(zdir);

   //No, you can't do that, but I would strongly suggest adding a constructor to allow exactly that instead of setting everything manually
   matrix4 mat(right.X, right.Y, right.Z, 0, 
                     up.X, up.Y, up.Z, 0,
                     zdir.X, zdir.Y, zdir.Z, 0,
                     position.X, position.Y, position.Z,1);
   setRotation(mat.getRotationDegrees());
Essentially, making a quad face the cam but retaining one of its axes is a matter of two cross products. Of course, if it is still moving directly towards are away from the cam it will still disappear. But you can always add two small quads with a circular texture as caps. You always build that thing like you model any object.. in local space.

The only thing to show how it would look is this:
http://festini.device-zero.de/Programmi ... ads/px.zip

It's old, and not really a game. Just some 50 stupid AI spaceships wildly shooting at each other. W,A,S,D to rotate, tab to accelerate, shift to slow down, strg/cntrl to shoot, t to target next ship. If you quickly turn around you should see enough of these beams to judge the effect.
Mike
Posts: 17
Joined: Wed Dec 14, 2005 6:42 pm

Post by Mike »

Shouldn't there be something like:

Code: Select all

SceneManager->getVideoDriver()->setTransform(irr::video::ETS_WORLD, AbsoluteTransformation); 
in the beginning of render()?
I had some strange issues without that line.
theteapot
Posts: 1
Joined: Mon May 08, 2006 7:14 am
Location: Sydney, Australia
Contact:

Post by theteapot »

I have a problem that if I go too close to the beam (or try to look alongside it), it suddenly disappears. Also, where is "laserbeam.bmp"?

CBeamNode* beam = new CBeamNode( smgr->getRootSceneNode( ), smgr, 200, "laserbeam.bmp" );
beam->SetStartPoint( core::vector3df( -500, 0, 0 ) );
beam->SetEndPoint( core::vector3df( 500, 0, 0 ) );
beam->SetBeamColor( video::SColor( 128, 0, 255, 0 ) );
beam->SetBeamScale(1.0);
beam->drop( );
It's not my fault!
jam
Posts: 409
Joined: Fri Nov 04, 2005 3:52 am

Post by jam »

theteapot wrote:Also, where is "laserbeam.bmp"?
You can just create your own texture for the beam.
doqkhanh
Posts: 158
Joined: Sat Mar 01, 2008 3:14 am
Location: Tokyo, Japan
Contact:

Post by doqkhanh »

Better in Irrlicht 1.4 with 1 line changed:

Code: Select all

      
         //...
         material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
		 material.setTexture(0, mgr->getVideoDriver( )->getTexture( szBeam ));

         // Default to 32 units for the scale
         //....
empirepro
Posts: 71
Joined: Thu Dec 27, 2007 5:41 am

Post by empirepro »

How can I get this to shoot from my ship instead of a set location?
Post Reply