awww, i could use a gun right now

Started by
23 comments, last by earl 15 years, 1 month ago
yeah yeah i know what you might think, 'what didnt that asshole solve his problem already?' i have to agree, i am an asshole for still not being able to solve my collision problem. well, i thought i solved the hard part(the part where i create a function that shoots a ray into a triangle), even if i did solve this the right way , i still cant manage to check collision. here's what i am trying to do to make my collision work : 1)i retrieve the vertex and index lists from the buffers 2)i make a loop, length is number of vertices /3 3)i pass three vertices,direction of my movement and the origin point of the player to the function that checks collision. 4)if there's a collision, i just add it's information to a list(so that if there's more than one collision point, i'll check which is the closest). 5)after the loop is over, i make a check if there was collision at all, if there was not, i let my player move, if there was i just do nothing(for now). **)right now i only check collision if i move toward the collision object, and not if i hit it. but it still gives odd results, sometimes it finds collision with some parts of the collision model, while on some other parts or directions it will not find collision(same thing for when i am not moving toward the collision object). so i try to do that like this: get vertex & index lists from buffers:

void GetLists()
{
VerticesNum = new D3DXVECTOR3[Mesh->GetNumVertices()];
IndexNum = new short[Mesh->GetNumFaces()*3];
DWORD stride = Mesh->GetNumBytesPerVertex();
BYTE* vbptr = NULL;
BYTE* ibptr = NULL;
DWORD Istride = sizeof(short);
Mesh->LockIndexBuffer(0,(LPVOID*)&ibptr);
Mesh->LockVertexBuffer(0, (LPVOID*)&vbptr);
D3DXVECTOR3 *pos = VerticesNum;
short *pos2 = IndexNum;

for (DWORD i = 0; i < Mesh->GetNumVertices(); i++)
{
   memcpy(pos, vbptr, sizeof(D3DXVECTOR3));
   vbptr += stride; 
   pos++;
}
for (DWORD k = 0; k < Mesh->GetNumFaces()*3; k++)
{
   memcpy(pos2, ibptr, sizeof(short));
   ibptr += Istride; 
   pos2++;
}
Mesh->UnlockIndexBuffer();
Mesh->UnlockVertexBuffer();

up until here everything's fine? then here's the part when i press forward

 velx=-(float)cos(MainPlayer->rotz+rad_90)*sin(MainPlayer->rotx+rad_90) *10.5;
		 vely=-(float)sin(MainPlayer->rotz+rad_90) *sin(MainPlayer->rotx+rad_90) *10.5;
		 velz=-(float)sin(MainPlayer->rotx) *10.5;
		 D3DXVECTOR3 dir(velx,vely,velz);D3DXVECTOR3 origin(MainPlayer->x,MainPlayer->y,MainPlayer->z);
		 CollisionInfo lengthcount[3];short count =0;CollisionInfo max;max.length =0;bool cold=false;int countertwo=0;
//lengthcount holds  the information if there's a collision
//count is not important here. cold is false if there was no collision.
//true data(defined globaly) just makes sure the vertices' are transformed to world space.
		
		 
		 for(int i=0;i<rock->Mesh->GetNumVertices()/3;i++)
		 {
			 if(truedata == false){
rock->VerticesNum[rock->IndexNum[countertwo]].x+=rock->x;
rock->VerticesNum[rock->IndexNum[countertwo]].y+=rock->y;
rock->VerticesNum[rock->IndexNum[countertwo]].z+=rock->z;
rock->VerticesNum[rock->IndexNum[countertwo+1]].x+=rock->x;
rock->VerticesNum[rock->IndexNum[countertwo+1]].y+=rock->y;
rock->VerticesNum[rock->IndexNum[countertwo+1]].z+=rock->z;
rock->VerticesNum[rock->IndexNum[countertwo+2]].x+=rock->x;
rock->VerticesNum[rock->IndexNum[countertwo+2]].y+=rock->y;
rock->VerticesNum[rock->IndexNum[countertwo+2]].z+=rock->z;

			 }
//code block above transforms the list into world space from model space.
 CollisionInfo col = Intersect(&rock->VerticesNum[rock->IndexNum[countertwo]],&rock->VerticesNum[rock->IndexNum[countertwo+1]],rock->VerticesNum[rock->IndexNum[countertwo+2]],dir,origin);
		 if (col.intersected == true)
		 {
			//unimportant stuff
                 }
		   countertwo+=3;
			
		 }
	       
                    truedata = true;
		    if(cold)
			   {
                          //unimportant stuff
               			}else{

             MainPlayer->y+=vely;
	     MainPlayer->x+=velx;
	     MainPlayer->z+=velz;
	     SecondPlayer->y+=vely;
	     SecondPlayer->x+=velx;
	     SecondPlayer->z+=velz;
			}

whew, alot of code, i tryed to clean it a bit of unimportant stuff so it would look smaller. now the last part is the function that checks collision which is :

CollisionInfo Intersect(D3DXVECTOR3 *vVertex1, D3DXVECTOR3 *vVertex2, D3DXVECTOR3 vVertex3,D3DXVECTOR3 dir,D3DXVECTOR3 origin)
{

    D3DXVECTOR3 vNormal;
	D3DXVECTOR3 vNormal2;
    D3DXVECTOR3 v1;
    D3DXVECTOR3 v2;
	D3DXVECTOR3 r1;
    D3DXVECTOR3 r2;
    D3DXVECTOR3 r3;
	float d1;
	float d2;
    CollisionInfo cola;
	float arr[3];//will hold information to check if point is inside triangle
    D3DXVECTOR3 lol;
    D3DXVec3Subtract(&v1, vVertex2, vVertex1);
    D3DXVec3Subtract(&v2, &vVertex3, vVertex1);
 
    D3DXVec3Cross(&vNormal, &v1, &v2);

    D3DXVec3Normalize(&vNormal, &vNormal);
//above is a code to calculate normal
	float DotProduct = D3DXVec3Dot(&vNormal,&dir);
	if(DotProduct<=0){
		
		cola.intersected = false;return cola;}
	float d = -(vVertex2->x*vNormal.x+vVertex2->y*vNormal.y+vVertex2->z*vNormal.z);//plane equation
    cola.length = -((D3DXVec3Dot(&origin,&vNormal)+d)/DotProduct);//t = -(Rayorigin*planeNormal+d)\(planenormal*direction)
	
	
    D3DXVECTOR3 dirT = dir;
    dirT.x*=cola.length;dirT.y*=cola.length;dirT.z*=cola.length;
	D3DXVec3Add(&lol,&origin, &dirT);
    D3DXVECTOR3 IntersectionPoint =lol;//calculate where is the intersection point
//now to calculate if the point is inside the triangle

    D3DXVec3Subtract(&r1, vVertex1, &IntersectionPoint);
    D3DXVec3Subtract(&r2, vVertex2, &IntersectionPoint);
    D3DXVec3Subtract(&r3, &vVertex3, &IntersectionPoint);
    origin.x*=-1; origin.y*=-1; origin.z*=-1;//invert the origin for the 'point in triangle' check.
 //calculate side 1
    D3DXVec3Cross(&vNormal2, &r1, &r2);
 D3DXVec3Normalize(&vNormal2, &vNormal2);
    d1=D3DXVec3Dot( &vNormal2, &origin);
    d2=3DXVec3Dot( &vNormal2, &IntersectionPoint);
    arr[0] = d1+d2;
//calculate side 2
    D3DXVec3Cross(&vNormal2, &r3, &r2);
    D3DXVec3Normalize(&vNormal2, &vNormal2);
    d1=D3DXVec3Dot(&vNormal2, &origin);
    d2=D3DXVec3Dot( &vNormal2, &IntersectionPoint);
    arr[1] = d1+d2;
//calculate side 3
    D3DXVec3Cross(&vNormal2, &r1, &r3);
    D3DXVec3Normalize(&vNormal2, &vNormal2);
    d1=D3DXVec3Dot( &vNormal2, &origin);
    d2=D3DXVec3Dot( &vNormal2, &IntersectionPoint);
    arr[2] = d1+d2;

	if(arr[0]<0 || arr[1]<0 || arr[2]<0 ){cola.intersected=false;return cola;}else{
		cola.intersected=true;
		
		cola.normal=vNormal;
	return cola;
}
}
yes, code is not clean. i've been debugging this for almost 2 weeks and i still didnt manage to find out what i did wrong there. does anyone see something wrong here? i'll appreciate help very much, i cant wait to be done with this already. thanks in advance, Bru. [Edited by - Bru on March 16, 2009 11:47:22 AM]
Advertisement
Use [source] tags please.

Looks like you are checking whether the ray caused by the player's movement will collide, not just the line segment that he is actually trying to move along. Try adding an argument to Intersect for how far along the ray to check for collisions. Or, check the value of cola.Length (which I think is the distance to a collision?).

Quote:if(DotProduct<=0){ cola.intersected = false;return cola;}

This test looks wrong way round to me ... you would expect to collide with faces with a normal pointing towards the ray origin, where this product will be negative.
Quote:Original post by Bob Janova
Use source-tags please.


Not only source-tags, but also tools like astyle (man). Additionally, you might be careful with statements containing things like "could use a gun now" these days, but maybe you have missed recent RL.
source tags, so that's what i've been lookin for.
on the subject, yes cola.length is the length between the origin and the intersection point. right now it is more important for me to check if the player is moving toward the collision object rather than check if there is collision, which is easy and i'll take care of it later.

you say this check is not right? i thought it is to make sure the ray direction is into the plane and not parallel to it or moving in a direction that will never intersect the plane.
anyway, without the check the collision function always returns true(atleast for most directions).
People, do not quote Bob Janova [smile]
Quote:Original post by phresnel
People, do not quote Bob Janova [smile]


eh... commenting bob makes it source?
Wait, what?

And yeah, the code is not well written, but at least with a [source] tag it doesn't give me a horizontal scrollbar :p
Don't bang your head on the wall. Collision detection ain't that easy if you try for the first time. Without reading all of your code due to the wierd formatting and the disturbing commenting of code blocks behind a block you should check for collisions like so

D3DXVECTOR3 cam_pos = ... whatever your camera position isD3DXVECTOR3 cam_dir = ... whatever your camera direction isFLOAT u = 0.0f;FLOAT v = 0.0f;FLOAT distance = 0.0f;BOOL intersection = FALSE;for (uint i=0; i<Mesh->getNumIndices () / 3; ++i){   ushort i0 = rock->IndexNum[i*3];   ushort i1 = rock->IndexNum[i*3+1];   ushort i2 = rock->IndexNum[i*3+2];   intersection = D3DXIntersectTri(&rock->VerticesNum[i0], // IN the triangle                                   &rock->VerticesNum[i1],                                   &rock->VerticesNum[i2],                                   &cam_pos,              // IN the camera                                   &cam_dir,                                   &u, &v,                // OUT texture coordinates of intersection                                   &distance);            // OUT distance of intersection from camera   if ((intersection == TRUE) && distance < cam_radius))   {      break;   }   else   {      intersection = FALSE;   }}if (intersection){   ... then handle it!}

Again, you get the idea. Do not implement ray triangle intersection yourself for now. The DX SDK has a lot of functionality. Use that until it works and you can name a valid reason to replace it!

Using this code you would have a valid and functional collision detection. Just make sure that the camera and the vertices are in the same coordinate system (preferably world) and that you do not apply a transformation matrix when rendering (unless you apply this matrix as well to rock's vertices for the purpose of collision detection).

If this still does not work then your camera information (position and direction) is not correct.

Finally note that you would need some hierarchical collision detection when dealing with a lot of geometry. Looping through all of your triangles in your 3d scene would be too slow if your scene becomes more complex.
------------------------------------I always enjoy being rated up by you ...
Quote:Original post by Waterwalker
Don't bang your head on the wall. Collision detection ain't that easy if you try for the first time. Without reading all of your code due to the wierd formatting and the disturbing commenting of code blocks behind a block you should check for collisions like so

D3DXVECTOR3 cam_pos = ... whatever your camera position isD3DXVECTOR3 cam_dir = ... whatever your camera direction isFLOAT u = 0.0f;FLOAT v = 0.0f;FLOAT distance = 0.0f;BOOL intersection = FALSE;for (uint i=0; i<Mesh->getNumIndices () / 3; ++i){   ushort i0 = rock->IndexNum[i*3];   ushort i1 = rock->IndexNum[i*3+1];   ushort i2 = rock->IndexNum[i*3+2];   intersection = D3DXIntersectTri(&rock->VerticesNum[i0], // IN the triangle                                   &rock->VerticesNum[i1],                                   &rock->VerticesNum[i2],                                   &cam_pos,              // IN the camera                                   &cam_dir,                                   &u, &v,                // OUT texture coordinates of intersection                                   &distance);            // OUT distance of intersection from camera   if ((intersection == TRUE) && distance < cam_radius))   {      break;   }   else   {      intersection = FALSE;   }}if (intersection){   ... then handle it!}

Again, you get the idea. Do not implement ray triangle intersection yourself for now. The DX SDK has a lot of functionality. Use that until it works and you can name a valid reason to replace it!

Using this code you would have a valid and functional collision detection. Just make sure that the camera and the vertices are in the same coordinate system (preferably world) and that you do not apply a transformation matrix when rendering (unless you apply this matrix as well to rock's vertices for the purpose of collision detection).

If this still does not work then your camera information (position and direction) is not correct.

Finally note that you would need some hierarchical collision detection when dealing with a lot of geometry. Looping through all of your triangles in your 3d scene would be too slow if your scene becomes more complex.

wow, this is like the best reply i ever got! i am used to answers that are so complex and sound all einstein that i bearly understand the point. but your post cleared two things for me :
1)yeah, probably should use built in functions to do my work. i just felt like learning doing it myself.
2)something i didnt think about is the applying matrix transformation to the rock's vertices(only thing i did was manulay translating the coordinates), it sounds reasonble that this might be causing the problem, should i have also applied scale and rotation?.

i would like to ask another question if its not too rude. what are those u and v variables? i do know they are texture coordinates but this is nothing graphical, why do i need texture coordinates in this function?

also, i rate you as extremly helpfull :)

1) First things first. Use build in functionality to make things work. If you are sure your program works as it should then start replacing those functions with your own implementation for the sake of learning how to do things.

2) It does not matter in which coordinate system you check for a collision as long as camera and vertices are in the same coodinate system. That means either apply the vertices' world transformation to the vertices when checking for collision (because that results in the position where your geometry is actually rendered and perceived) or apply inverse transformation to your camera position and direction. The latter is obviously faster since its just transformation two vectors as opposed to getNumVertices(). However, take care when transforming the camera direction vector. Do not apply translation or scaling, just rotation. If you go and transform all vertices apply the very same transformation matrix as you set for rendering.

3) thanks for rating me up :)

editThe u and v coordinates are more or less just garbage ... well not really. You could use this information for changing the triangles texture (if any) at this particular pixel. Its just that the algorithm used for the intersection detection does calculate u and v anyway so they are provided as output result, too. Just because they are already there and some people might used them for further analysing the collision.
------------------------------------I always enjoy being rated up by you ...

This topic is closed to new replies.

Advertisement