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?)
line/plane intersection
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.
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.
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);
-
- Admin
- Posts: 3590
- Joined: Mon Oct 09, 2006 9:36 am
- Location: Scotland - gonnae no slag aff mah Engleesh
- Contact:
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.
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
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
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
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
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:
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
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);
}
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
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;
}
}