line/plane intersection

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
pippy
Posts: 49
Joined: Sun Jul 08, 2007 11:31 pm

line/plane intersection

Post by pippy »

I'm trying intersect a line with a plane. The line is the camera position to the mouse position, and to the plane is the where X and Z equal 0. The result is a 3d position

The desired effect would be the user to drag over units in a 3d space and form a square to where the mouse is on the plane in 3d



What would be the best way to do this?

So far I have thought of 3 possible options:

1) use smgr->getSceneCollisionManager ()->getRayFromScreenCoordinates(), then work out where the line returned intersects with the plane

2) Use the same method as used in the number 07 tutorial, but write a hack to offset the mouse position. (easy to write, but would cause mayhem if the user changes screen resolution)

3) write my own function (7th form maths anyone?)
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

1) and 2) are exactly the same i would think... not sure why you'd want to hack your own version of getRayFromScreenCoordinates when it's provided for you!

I guess you'd have to do 4 ray casts, one for each corner of the box you're drawing on the screen with the mouse in order to calculate the box's dimensions in 3D space.
Image Image Image
pippy
Posts: 49
Joined: Sun Jul 08, 2007 11:31 pm

Post by pippy »

JP Thanks for your response. I had a few beers and got cracking on the problem and ended up with much what you said. For those who where wondering this is my code. (Selector is just an extension of scene node, position is where its at)

Code: Select all

if(selector == NULL){
						selector = new Selector(mysmgr->getRootSceneNode(), mysmgr, 100000);
					}
					// where the mouse is from the camers (forms line)
					core::line3d< f32 > lol = mysmgr->getSceneCollisionManager()->
						getRayFromScreenCoordinates(from, camera);
					
					// plane, first position, second normal
					core::plane3d< f32 > ground(core::vector3d<f32>(0, 0, 0), core::vector3d<f32>(0, 10, 0));

					// where the line hits the ground
					core::vector3d< f32 >intersection(0,2,0);

					// if it intersects, it will return true and store intersetion where the line meets
					if(ground.getIntersectionWithLimitedLine(lol.start,lol.end,intersection)){
						intersection.Y += 2; // so it sticks above the ground
					}
                    selector->setPosition (intersection);
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

WTF... someone figured out the answer to their own problem? Whoa... feeling dizzy... need to sit down... :P

Heh, you actually posted your solution as I was composing a reply suggesting exactly that solution, based on this previous answer.

Your solution looks great, although if I have to nitpick (and I must, I really must!) you might as well pass 0, 1, 0 as the plane normal, and use getIntersectionWithLine() rather than getIntersectionWithLimitedLine() as the actual end points of the ray returned from getRayFromScreenCoordinates() probably aren't meaningful for the purposes of this test (although they will be if your camera ever goes below your ground plane).

Still, kudos for that solution; I think you're on the success path. ;)
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

Sorry but I didn't understood what you're trying to achieve?
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
cdrwolfe
Posts: 100
Joined: Thu Nov 15, 2007 5:38 pm
Location: Cranfield University

Post by cdrwolfe »

My guess would be,

That in a normal RTS you drag the mouse to create a selection box which is represented/displayed to the screen coordinates.

While here you have a 3D plane i.e flat ground where your unit may be situated and when drawing the selection box it is represented on the world? coordinates or what ever it is called, and essentially it is mapped to the plane.

damn thats a bad explanation by me :)

Regards Wolfe
pippy
Posts: 49
Joined: Sun Jul 08, 2007 11:31 pm

Post by pippy »

rogerborg: Thanks for your reply, any help is great, it improves my coding style (I've been coding c++ for only half a year)

Here's my function as of now:

Code: Select all

// User over units
void DragFrom(scene::ICameraSceneNode* camera, 
	core::position2d<s32> from){
	
	if(selector == NULL){
		selector = new Selector(mysmgr->getRootSceneNode(), mysmgr, 100000);
	}
	// line from the camera to the mouse (technically its a ray)
	core::line3d< f32 > lol = mysmgr->getSceneCollisionManager()->
		getRayFromScreenCoordinates(from, camera);
	
	// plane, first position, second normal
	core::plane3d< f32 > ground(core::vector3d<f32>(0, 0, 0), core::vector3d<f32>(0, 1, 0));

	// where the line hits the ground
	core::vector3d< f32 >intersection(0,2,0);

	// if it intersects, it will return true and store intersetion where the line meets
	if(ground.getIntersectionWithLine(lol.start,lol.end,intersection)){
		intersection.Y += 2; // so it sticks above the ground
	}
    selector->setPosition (intersection);
}
In order to make it so that the user can select over units I'll need to:
1) take where the mouse started dragging and where its draggin to now
2) stretch the square to fit over the unit

I'll post back in 20 minutes with the code =D
pippy
Posts: 49
Joined: Sun Jul 08, 2007 11:31 pm

Post by pippy »

Here's my 1337 code:

Code: Select all

				// Calculates where the line intersects the ground plane
				core::vector3d< f32 > IntersectPlane(core::line3d< f32 > myLine){
					core::vector3d< f32 >intersection(0, 0, 0);

				   // plane, first position, second normal. 
				   // You can of course replace it with your own plane
				   core::plane3d< f32 > ground(
					   core::vector3d<f32>(0, 0, 0), 
					   core::vector3d<f32>(0, 1, 0)); 

					// calculates the intersection
					ground.getIntersectionWithLine(myLine.start,myLine.end,intersection);

					return intersection; // so it sticks above the ground
				}

				// User drags from X to Y
				void DragFrom(scene::ICameraSceneNode* camera, 
					core::position2d<s32> from, core::position2d<s32> to){

					// create new selector class 
					// (extends ISceneNode with custom function strechPosition) 
					if(selector == NULL){
						selector = new Selector(mysmgr->getRootSceneNode(), mysmgr, 100000);
					}

					// line from the camera to the mouse (technically its a ray)
					core::line3d< f32 > cameraRay = mysmgr->getSceneCollisionManager()->
						getRayFromScreenCoordinates(to, camera);
					
					// where the line hits the ground
					core::vector3d< f32 > intersection = IntersectPlane(cameraRay);

					// line from the camera to the mouse (technically its a ray)
					core::line3d< f32 > cameraRayTo = mysmgr->getSceneCollisionManager()->
						getRayFromScreenCoordinates(from, camera);
					
					// where the line hits the ground
					core::vector3d< f32 >intersectionTo = IntersectPlane(cameraRayTo);

					// Strech the selector unit
					selector->strechPosition(intersection,intersectionTo);
				}

				// deletes the draginging thing
				void removeDrag(){
					if(selector != NULL){
						selector->remove();
						selector->drop();
						selector= NULL;
					}
				}
Post Reply