Page 1 of 1
line/plane intersection
Posted: Thu Dec 20, 2007 10:14 am
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?)
Posted: Thu Dec 20, 2007 10:28 am
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.
Posted: Thu Dec 20, 2007 10:58 am
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);
Posted: Thu Dec 20, 2007 11:25 am
by rogerborg
WTF... someone figured out the answer to their own problem? Whoa... feeling dizzy... need to sit down...
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.
Posted: Thu Dec 20, 2007 2:18 pm
by MasterGod
Sorry but I didn't understood what you're trying to achieve?
Posted: Thu Dec 20, 2007 2:58 pm
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
Posted: Fri Dec 21, 2007 3:53 am
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
Posted: Fri Dec 21, 2007 4:11 am
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;
}
}