Pick 3d objects in a rect !
Blitz3D Forums/Blitz3D Programming/Pick 3d objects in a rect !
| ||
I'm busy with making a strategie game and now i'm building a multiply select Rect. if you run this code you see a cool begin. That's oke but how to select all the object inside that rect? Please edit the code below, I try everything but nothing works, Graphics3D 320,240,32,2 Global cursor SetBuffer BackBuffer() camera=CreateCamera() light=CreateLight() RotateEntity light,90,0,0 ;cursor cursor = LoadImage("cursor.png") MaskImage cursor,0,255,255 ;pickable object 1 cone=CreateCone(20) EntityPickMode cone,2 PositionEntity cone,0,0,5 ;pickable object 2 cone2=CreateCone(5) EntityPickMode cone2,2 PositionEntity cone2,3,3,3 While Not KeyHit(1) RenderWorld UpdateWorld mX =MouseX() mY =MouseY() If MouseHit(1) selectX = MouseX() selectY = MouseY() EndIf ;---+ If MouseDown(1) m_width = mX-selectX m_height= mY-selectY Rect selectX,selectY,m_width,m_height,0 CameraPick(camera,mX,mY) EndIf DrawImage cursor,mX,mY If PickedEntity() Then Text 0,0,"PickedEntity: "+PickedEntity() EndIf Flip Wend End |
| ||
Hi Martijn, You have a pretty good start for doing that, but the only problem with it is that CameraPick() can only pick on entity at a time. To be able to select more than one entity you will need to have a variable for each object telling wheter it was picked or not, and read through and pick from each position inside the rectangle. The only way i can really explain this is with an example, so try this: Graphics3D 640,480,0,2 SetBuffer BackBuffer() Camera=CreateCamera() PositionEntity Camera,0,0,-6 Cube1=CreateCube() PositionEntity Cube1,-3,2,0 EntityColor Cube1,128,0,0 EntityPickMode Cube1,2 Cube2=CreateCube() PositionEntity Cube2,0,0,0 EntityColor Cube2,0,128,0 EntityPickMode Cube2,2 Cube3=CreateCube() PositionEntity Cube3,3,-2,0 EntityColor Cube3,0,0,128 EntityPickMode Cube3,2 Light=CreateLight() AmbientLight 50,50,50 TurnEntity Light,30,50,0 Global Cube1Sel=0 Global Cube2Sel=0 Global Cube3Sel=0 While Not KeyDown(1) Cls If Cube1Sel=1 EntityColor Cube1,255,0,0 Else EntityColor Cube1,128,0,0 EndIf If Cube2Sel=1 EntityColor Cube2,0,255,0 Else EntityColor Cube2,0,128,0 EndIf If Cube3Sel=1 EntityColor Cube3,0,0,255 Else EntityColor Cube3,0,0,128 EndIf UpdateWorld RenderWorld If MouseDown(1) If mouseSet=0 mouseSet=1 mX=MouseX() mY=MouseY() EndIf Rect mX,mY,MouseX()-mX,MouseY()-mY,0 Else If mouseSet=1 mouseSet=0 Cube1Sel=0 Cube2Sel=0 Cube3Sel=0 For x=0 To MouseX()-mX Step 4 For y=0 To MouseY()-mY Step 4 Select CameraPick(Camera,mX+x,mY+y) Case Cube1 Cube1Sel=1 Case Cube2 Cube2Sel=1 Case Cube3 Cube3Sel=1 End Select Next Next EndIf EndIf Flip Wend If you don't quite understand all of this, just ask and I'll explain, otherwise I'll leave it up to you :) Hope that helps you out some. |
| ||
Thanks Todd I test your script and it works good :) The only thing I saw that its very slow :( why is that? When i'm at home i'm going to edit it. Thank You Very Much -- |
| ||
I'm not sure why it would be slow. Is it always slow, or just after you drag over an area. If it is that just try changing 'Step 4' in the code to something higher, like 'Step 8' or something. Of course it may depend on your computer too. |
| ||
H! Todd i'm at home and testing things but when I edit your code a bit the program don't work :( Here is the code "I was only testing to select/deselect cone2" Graphics3D 320,240,16,2 SetBuffer BackBuffer() Global cursor Global Cube1Sel=0 camera=CreateCamera() PositionEntity camera,0,0,-6 light=CreateLight() RotateEntity light,90,0,0 ;cursor ;cursor = LoadImage("images/menu/cursor.png") ;MaskImage cursor,0,255,255 ;pickable object 1 cone=CreateCone(20) EntityPickMode cone,2 PositionEntity cone,0,0,5 ;pickable object 2 cone2=CreateCone(5) EntityPickMode cone2,2 PositionEntity cone2,3,3,3 While Not KeyHit(1) Cls If Cube1Sel=1 EntityColor cone2,0,255,0 Else EntityColor cone2,255,0,0 EndIf UpdateWorld RenderWorld If MouseDown(1) If mouseSet=0 mouseSet=1 mX=MouseX() mY=MouseY() EndIf Rect mX,mY,MouseX()-mX,MouseY()-mY,0 Else If mouseSet=1 mouseSet=0 Cube1Sel=0 Cube2Sel=0 Cube3Sel=0 For x=0 To MouseX()-mX Step 8 For y=0 To MouseY()-mY Step 8 Select CameraPick(camera,mX+x,mY+y) Case Cube1 Cube1Sel=1 Case Cube2 Cube2Sel=1 Case Cube3 Cube3Sel=1 End Select Next Next EndIf EndIf Flip Wend |
| ||
(edit) - ok, I just read the part that said "i was only testing selecting/deselecting cone2" :) In that case all you need to do is change the line "Case Cube1" to "Case cone2". it was still looking for Cube1, but you had renamed it to cone2. I'll leave all the rest of this just in case though Basically what you need to do goes like this: 1: Decide if the user has dragged a rectagle 2: If he has, then decide what objects were inside that rectangle 3: If an object was inside the rectangle, the set it's variable to '1', if not then set it to '0' 4: for all of the objects whose variables are set to '1', do something to make it obvious it is selected (such as making it brighter, white, etc.) Ok, so to do that, first off you should do the rectangle code. What you already had before for dragging a rectangle will work fine, except that we need to know when the user has let go of the mouse button. If he has, then we move on to step 2. To decide if he has, at least in my code, I used a varible (called 'mouseSet'). When the user pressed the button, it was set to 1. Then If the button was not pressed, but 'mouseSet' was equal to 1, then i know the user has realeased the button. So then to decide if the entity was inside the rectangle, we use CameraPick, like you were in your origional code. So before we do anything we reset all of the objects variables to '0'. Then we go through each pixel inside the rect, and use CameraPick on that pixel to see if it is an pickable entity. Since CameraPick will return the entity that was picked I use Select/Case, (If..Endif will work too, just a little differently) if the picked entity was any of the entities i want to be able to select, then we set its varible to '1'. You really don't need to go through each pixel, you can skip most of them, but you lose accuracy. I did this by using 'Step 4', which skipped every 4 pixels. Now in the main loop, we go through all of the variables for our objects. If it is '1', then we do something (maybe highlight it or something), or if it is '0' then we do something else (like darken it). Ok, that's a lot of stuff there. I hope at least some of it is useful, and helps you out. If it's still not making sense, don't give up on it, keep trying stuff til you get it to work. Some of this kind of stuff might be a little hard to understand, especially if you're just starting out. |
| ||
(sorry, double post) |
| ||
Thanks for the good information you give me Todd. I'm still learning now and this helps a lot. I try to edit the code today. |
| ||
Theres a MUCH faster way to do this that doesnt use CameraPick at all. You dont even have to check every pixel, the picking is instantaneous. Ill put you all in suspense as I devise the working(non buggy) algo for yall. Stumbled across this 3 minutes ago :). |
| ||
Got it! now to write a more general implementation of the techniqu and plop it in the archives. [Edit] I dont have time to write that function right now, essentially you use the CameraProject() function on the 3d coods of each entity your trying to pick. Then PrejectedX() and ProjectedY() to find the 2d on screen coordinates, then you check the 2d coordinates to see if they are within your selection rect. If they are, the entity is picked, if not, it isnt picked. Pretty simple really, but FAST. Though it wont be pixel perfect, and will be really innacurate on large large entitys, you can use this, and a combo of "low-res" camerapick's to get the job done. Just remember to NOT camerapick() every pixel in the selection rectangle. That is really slow. Have fun. |