picking an object

Previous topic - Next topic

Richard Rae

I have 9 objects on screen(3D being used).How would I go about picking one with the mouse.I am assuming I could use the raytrace command.

Kitty Hello

Correct.
Use the X_SCREEN2WORLD to transform your mousepointer to 3D coordinates. Then use X_COLLISIONRAY to test, if you hit it.

Richard Rae

Can't get it.Any chance of an example? :)

Kitty Hello

Code (glbasic) Select
// --------------------------------- //
// Project:
// Start: Saturday, July 20, 2002


// First we need an object. Here: a simple paper plane
// We assume Z is down, as most 3d programs will export
// The converter should be able to convert this one day...

// Also we assume the x axis (positive) is the direction
// the plane will fly forwards, so in a right hand system
// y will be left side of plane.

// Triangle Strips will be drawn:
//
//  1---2---5
//   \ / \ /|
//    3---4 |
//         \|
//          6

LOADSPRITE "News.bmp", 0

col = RGB(0xff, 0xff, 0xff)
X_OBJSTART 0 // PlaneID = 0
// Right wing:                 side updown
X_OBJADDVERTEX -7,  5,  0,     1.0, 1.0, col // Outer point
X_OBJADDVERTEX -7,  1,  0,     1.0, 0.5, col // Inner edge
X_OBJADDVERTEX  7,  0,  0,     0.0, 1.0, col // Top
// Right body:
X_OBJADDVERTEX -7,  0,  3,     0.0, 1.0, col
X_OBJNEWGROUP
// Left wing:
X_OBJADDVERTEX -7, -5,  0,     0.0, 0.0, col
X_OBJADDVERTEX -7, -1,  0,     0.0, 0.5, col
X_OBJADDVERTEX  7,  0,  0,     1.0, 0.0, col
// Left body:
X_OBJADDVERTEX -7,  0,  3,     0.0, 1.0, col
X_OBJEND

X_SAVEOBJ "plane.ddd", 0
X_LOADOBJ "plane.ddd", 0

LIMITFPS -1
WHILE TRUE

MOUSESTATE mx, my, mb1, mb2

DRAWRECT mx-8,my-8,16,16, RGB(255,0,0)

X_MAKE3D 1, 1000, 45 // Turn to 3D Viewport
X_CAMERA   200*SIN(mx*360/640), my*2-100, 200*COS(mx), 0,0,0 // Rotate CAMERA with mouse
dtime = GETTIMER()
psi=psi+(dtime/64); IF psi>=360 THEN psi=0
FOR phi = 0 TO 360 STEP 30
X_DRAWAXES 0,0,0 // Draw global axes (red=x, green=y, blue=z)

alpha = (phi+psi)*4
LOCAL px=200*SIN(phi+psi),py=SIN(alpha)*20,pz=100*COS(phi+psi)
X_MOVEMENT px,py,pz

X_SCALING 2,2,2
X_ROTATION 90,1,0,0 // Make plane body point down global y
X_ROTATION 45*COS(alpha),0,0,1 // make plane look up/down with mouse
X_ROTATION phi+psi, 0,1,0 // Rtoation due to position in circle

X_SETTEXTURE 0, -1
X_DRAWOBJ 0, 0 // Draw Object#0. Frame# is always 0 with user def. objects


// PICKING PART!
LOCAL x,y,z, x2,y2,z2
X_SCREEN2WORLD mx, my,  0, x, y, z
X_SCREEN2WORLD mx, my, -1, x2,y2,z2
IF X_COLLISIONRAY(0,0, x,y,z, x2-x, y2-y, z2-z)<>0
X_PRINT "PICK", px,py,pz, 0
ENDIF

NEXT

fps = ((1000/dtime)+fps)/2
delay=delay+dtime
IF delay>1000 // 1/2 sec
delay=0
showfps=fps
ENDIF
X_MAKE2D
PRINT "FPS: " +INTEGER(showfps), 100, 100 // + dtime, 0,0
SHOWSCREEN
WEND
Move the mouse over a paper plane.

Richard Rae

Thanks for that Gernot.I can get it to work in my programme no problem.Can I get the pick command to return the actual world co-ordinates(x,y,z)of the object picked?

Kitty Hello

uhm... you need the x,y,z position of the object for the x_collisionray test. Thus, uhm... you know them.

Richard Rae

How come the following code is only picking one cube

Code (glbasic) Select
// --------------------------------- //
// Project: 3d test
// Start: Thursday, November 08, 2007
// IDE Version: 5.069


X_LOADOBJ "cube.ddd",1

LOADSPRITE "rub_cube.bmp",1
LOADSPRITE "back.bmp",2
LOADSPRITE "reflect.bmp",3

LOADSPRITE "../../pointers.png",4




leng=50

x=0
y=0
WHILE TRUE
ALPHAMODE -.999
STRETCHSPRITE 2,0,0,640,480

MOUSESTATE mxx,myy,b1,b2

IF b2
mx=mx+MOUSEAXIS(0)
my=my+MOUSEAXIS(1)
ENDIF




X_MAKE3D 1,1000,45


camx=(400*COS(mx))*COS(my)
camy=(400*SIN(mx))*COS(my)
camz=400*SIN(my)

camx1=(300*COS(mx))*COS(my)
camy1=(300*SIN(mx))*COS(my)
camz1=300*SIN(my)






X_CAMERA camx,camz,camy,0,0,0

INC phi,2
INC pi,1

FOR z=0 TO 2
FOR y=0 TO 2
FOR x=0 TO 2
X_MOVEMENT (x*48)-50,(y*48)-50,(z*48)-50

X_SETTEXTURE 1,-1

X_DRAWOBJ 1,0

LOCAL wx,wy,wz, wx2,wy2,wz2
        X_SCREEN2WORLD mxx, myy,0, wx, wy, wz
        X_SCREEN2WORLD mxx, myy, -1, wx2,wy2,wz2
        IF X_COLLISIONRAY(1,0,wx,wy,wz,wx2-wx,wy2-wy,wz2-wz)<>0
           
            picked=1
            ELSE
            picked=0



        ENDIF



NEXT
NEXT
NEXT





X_MAKE2D
DRAWSPRITE 4,mxx,myy
IF picked=1
PRINT "object picked",10,0
ELSE
PRINT "No object picked",10,0
ENDIF

SHOWSCREEN

WEND
I know it's probably something I am doing wrong.

Full programme and media available here

//www.rrae.pwp.blueyonder.co.uk/my%20prog.zip

Kitty Hello

Hehehe!
Du setzt "picked=0" wenn Du nicht in einem Block bist und überschreibst damit picked=1 von vorherigen Block.
Nimm's vor die Schleife:
Code (glbasic) Select
picked=0
FOR z=0 TO 2
FOR y=0 TO 2
FOR x=0 TO 2
LOCAL obx=(x*48)-50, oby=(y*48)-50, obz=(z*48)-50
X_MOVEMENT obx, oby, obz
X_SETTEXTURE 1,-1

X_DRAWOBJ 1,0

LOCAL wx,wy,wz, wx2,wy2,wz2
        X_SCREEN2WORLD mxx, myy,  0, wx, wy, wz
        X_SCREEN2WORLD mxx, myy, -1, wx2,wy2,wz2
        IF X_COLLISIONRAY(1,0,wx,wy,wz,  (wx2-wx)*1000,(wy2-wy)*1000,(wz2-wz)*1000)<>0

            picked=1
        ENDIF



NEXT
NEXT
NEXT

Richard Rae

Don't understand German !Sorry
Tried the new code and it works fine:)Another question ,If three cubes are in a line one behind the other,all three show as being hit(modified code slightly to use x_print).How can I find which one is the closest to the camera?Thank you for all your help,it is really appreciated.

Kitty Hello

Oh! Silly me.
Well, if the X_COLLISIONRAY returns <>0, then the object you're just drawing (or would draw at current X_MOVEMENT) is under the mouse.

Richard Rae

Sorry for being thick,but what if the one furthest away is drawn first.Won't it be the one under the mouse?I am looking for the one that is closest to the camera.

Kitty Hello

then also store the distance from camera to the object, and change the picked index, when you're closer. The distance is the retun value from X_COLLISIONRAY

JohnnyB

What would be the best way to calculate the point where the ray first hits an object?