Problems with Picking (Ray intersection)

Started by
12 comments, last by Darker_Rage 19 years, 3 months ago
Hi, I'm trying to create a Dungeon-Keeper like game in C++ and DirectX. I have a map created of meshes loaded from x-files, each 20*20 pixels. To save memory, I have only loaded each of these meshes once, and my render function calls "DrawSubset()" on the relevent mesh, decided via a switch statement. Nothing keeps a handle on the meshes as they are rendered, as all the 2D arrays I tried to create of ID3DXMesh* caused errors when I tried to run the program (although compiled fine). All the above is largely irrelevent, all I need (absolutely desperately, this is my final year, 30 credit project for Uni!) is a picking algorithm that A> deals with squares not spheres and B> Deals with multiple objects, preferabally at render time. Once I have this, I can adapt it to suit my nefarious purposes... I looked 4 pages deep on this forum, didn't see anything ("Search is temporarily disabled") and all the other resources I have found deal in bounding spheres. I can provide any bits of code anyone may want / screenshots as required. Very very grateful for any help anyone can offer me, Darker_Rage
Advertisement
Do a search for "AABB ray intersection" (Axis Aligned Bounding Box). You should find enough algorithms. What do you mean by "being able to handle multiple objects"?

Unfortunately, I did :-S The stuff I turned up is next to useless to me.

At render time, the program selects from one of 3 ID3DXMesh* to render, renders one and moves 20 pixels on, then repeats. After 50 have been rendered, it moves 20 to the right and back to the beginning, then continues. It doesn't render from a 2D array, because I get exceptions whenever I try to write to the array. This means that there are no handles on the 1000 meshes that have been rendered.

All the algorithms I found select a single mesh, and only a single mesh is rendered. Any algorithm I use needs to select a single mesh from 1000 rendered
Quote:Original post by Darker_Rage
At render time, the program selects from one of 3 ID3DXMesh* to render, renders one and moves 20 pixels on, then repeats. After 50 have been rendered, it moves 20 to the right and back to the beginning, then continues. It doesn't render from a 2D array, because I get exceptions whenever I try to write to the array. This means that there are no handles on the 1000 meshes that have been rendered.

I didn't understand anything. But, getting exceptions on writing to an array means you've been doing something wrong.

Quote:All the algorithms I found select a single mesh, and only a single mesh is rendered. Any algorithm I use needs to select a single mesh from 1000 rendered

You have a 'basic' building-block algorithm that checks for ray-AABB intersection. Run it on the 1000 meshes, and you'll get the selected meshes. Or am I misunderstanding something here?

Did you mean you want to drag a rectangle (RTS style) and pick the meshes it covers?

Quote:
You have a 'basic' building-block algorithm that checks for ray-AABB intersection. Run it on the 1000 meshes, and you'll get the selected meshes. Or am I misunderstanding something here?

Yeah, I agree with Coder.

Have you looked at the DirectX PickMesh sample? I don't think it is in the latest SDKs unfortunately. I use managed DX, but try something like the D3DXPickMesh function.

Hope that helps,
Hookay, i'm confusing myself now :S I'm going to try and ASCII what i'm doing... My ASCII art sux a bit, so please bear with me. [] represents a tile, the number represents what it is a tile of

[1][1][1][1][1][1][1][1][1][1]
[1][1][1][1][1][1][1][1][1][1]
[1][1][1][1][1][1][1][1][1][1]
[1][1][1][2][2][2][2][2][1][1]
[1][1][1][2][3][3][3][2][1][1]
[1][1][1][2][3][3][3][2][1][1]
[1][1][1][2][2][2][2][2][1][1]
[1][1][1][1][1][1][1][1][1][1]
[1][1][1][1][1][1][1][1][1][1]
[1][1][1][1][1][1][1][1][1][1]

I have a 2D array storing those numbers, just as ints. A switch statement in my "render" function reads the number at [x][y] and renders the mesh that corresponds to that number.

Quote:You have a 'basic' building-block algorithm that checks for ray-AABB intersection. Run it on the 1000 meshes, and you'll get the selected meshes. Or am I misunderstanding something here?


There is NOTHING that keeps track of the meshes once they are rendered. Anything I try to make to do this takes the form of a 2D array, and always generates
"Unhandled exception at 0x0011fc98 in Damien.exe:
0xC0000005: Access violation reading location 0x0011fc98."

no matter what I try (i've made the array bigger, changed the number being fed to the statement that puts the meshes into the array, all for naught). The errors show up in the most bizarre places when I debug however, usually in the font code.

I have just managed to get the program so that it changes a random, single block of type [1] to type [2], where before the best I had managed was to make _everything_ change. All I _think_ I need now is a way to store a 2D array of ID3DXMesh* without causing exceptions.

Still very grateful for any help anyone can offer, and for that that which has already been offered, Darker_Rage
Quote:There is NOTHING that keeps track of the meshes once they are rendered. Anything I try to make to do this takes the form of a 2D array, and always generates
"Unhandled exception at 0x0011fc98 in Damien.exe:
0xC0000005: Access violation reading location 0x0011fc98."

no matter what I try (i've made the array bigger, changed the number being fed to the statement that puts the meshes into the array, all for naught). The errors show up in the most bizarre places when I debug however, usually in the font code.

Well, that indicates you've been writing/reading incorrectly to/from the array. If you still have the old code, you can post it to find out what's wrong.

Anyway, now I understand the problem. One way to solve it, given the ray:
For every tile in your grid:    Based on tile type, construct AABB    Translate AABB based on tile position    Intersect AABB with ray


However, this is horribly inefficient. A better way to do it would be to use a quad-tree whose leaves are the tiles. You intersect the ray with the 4-top level AABBs (quads), and this saves you 3/4 of the intersection checks. Then do the same for the 4 children of the intersected top-level AABB, and so on, until you reach a leaf - that's your tile.

I _think_ that's what i've managed to achieve last night. Now, on left mouse click, a single tile changes, rather than the whole map, but it seems to be completely random. Anyway, here's the array code:

int const static X_VALUE = 50; //The maps X axis
int const static Y_VALUE = 50; //The maps Y axis

ID3DXMesh* meshes[X_VALUE][Y_VALUE];

ID3DXMesh* MR = 0;
std::vector<D3DMATERIAL9> MRMtrls(0);
std::vector<IDirect3DTexture9*> MRTextures(0);

//code to load MR, materials and textures from x-file

for(int i=0; i<=X_VALUE; i++)
{
for(int j=0; j<=Y_VALUE; j++)
{
switch (tracker.getCompAt(i,j)) //Returns what type of tile belongs at [j]
{
case 0:
meshes[j] = MR;
break;
//Other identical cases for other tile types
}
}
}

Now to go look up quad trees.... Thanks again for any help you can offer!
Quote: i<=X_VALUE

This should be 'i < X_VALUE'. For an array of length N, you have indices [0, N-1]. Same goes for 'j<=Y_VALUE'

Berrrr.... and i've been coding for nigh on 6 years! And I didn't spot that.

OK, i've put a workaround in place now for that problem. However, I'm still in trouble. As the meshes in my newly created 2D array are all identical, I can't use the D3DXIntersect macro (it always chooses the tile at 0,0 in the array, although it's stopped picking ones at random now).

I am using this code:

struct BoundingBox{	BoundingBox();	D3DXVECTOR3 min;	D3DXVECTOR3 max;	bool intersect(const Ray &) const;};BoundingBox* MRBB; //will not compile if declared any other way, errors at                    //MRBB->min and MRBB->maxif( d3d::gDInput->mouseButtonDown(0))	{		ray = CalcPickingRay((int)d3d::gDInput->mouseDX(), (int)d3d::gDInput->mouseDY());		D3DXMATRIX v;		d3d::gd3dDevice->GetTransform(D3DTS_VIEW, &v);		D3DXMATRIX viewInverse;		D3DXMatrixInverse(&viewInverse, 0 , &v);		TransformRay(&ray, &viewInverse);		for(int i=0; i<X_VALUE; i++)		{			for(int j=0; j<Y_VALUE; j++)			{				D3DXVECTOR3* raf; //Should be BYTE *, but fails				MR->LockVertexBuffer(0,(void**)&raf);				HRESULT hr = D3DXComputeBoundingBox(				raf, //Should be(D3DXVECTOR3*)raf				MR->GetNumVertices(),				D3DXGetFVFVertexSize(MR->GetFVF()),				&MRBB->min,				&MRBB->max);				MR->UnlockVertexBuffer();				if(FAILED(hr))				{					::MessageBox(0, "Twatit", 0,0);				}			}		}	}


I'll leave off listing the CalcPickingRay and TransformRay methods for now. The problem is that the HRESULT from D3DXComputeBoundingBox is always fail (at least, that's what the message box says). No bounding box means no using the shiny Intersect method on my ray :-(

Help is appreciated, as ever! Darker_Rage

EDITED to change the "should be's"

Edited by Coder: source tags. Check GDNet Forums FAQ

[Edited by - Coder on January 4, 2005 3:49:31 AM]

This topic is closed to new replies.

Advertisement