Sign in to follow this  
PaperFace

Finding out where a ray hits the ground.

Recommended Posts

Hello again chaps, I've implemented a picking system where I can select my little tanks by clicking the screen, which creates a ray then performs an D3DXIntersect on all the tanks and selects any which are clicked on. Nice and easy! I'm now trying to do it, so when it doesn't hit any tanks, it flags all the currently selected tanks to move to that spot. The problem I'm having is how can I take the ray used for the picking, and cast it on my terrain map to work out the x z and y co-ords the little tanks should move to (as in, what spot on the ground I've clicked on) the terrain map is just stored in index and vertex buffers so I can't simply run D3DXIntersect on it, and even if i could, it wouldn't get me the positions I need. An easier way might be to just get the x and z position by just finding where the ray hits 0 on the y axis, then calculating the 'move to' y myself from the heightmap, but as the maps can be pretty hilly that wouldn't be ideal and would end up selecting behind the hills rather than on top of the hill. Any suggestions? or has anybody found a decent way of doing this they could share with me? I'm stumped :( Many thanks!

Share this post


Link to post
Share on other sites
A quick idea:

Trace some steps along your ray, get the minimum y of each step and compare to the heights of the appropriate quads. Ideally your step length should be equal or a bit smaller than the quad size. This would require to check at most 4 quads per step.

Then once you have a step where the step y is lower that the quads' height you have the candidates to perform ray-triangle tests.

To choose a good starting point you might get the point of the ray where y = max_y_of_terrain.

Share this post


Link to post
Share on other sites
Thanks for the reply.

I wouldn't know the "appropriate quads" as I don't have the X or Z values either :(

I followed this tutorial to do the object picking:

http://www.toymaker.info/Games/html/picking.html

if any kind soul can tell me how I can work from that, to calculate the Z and X points in world space of where i'm clicking (lets assume the ground is always level and at y=0) that would be super!

Regards

[Edited by - PaperFace on August 15, 2007 7:12:14 AM]

Share this post


Link to post
Share on other sites
You might keep the heightmap in memory for accessing the height information.
Then you need to transform your ray to the terrain's space for you calculation. Provided that in terrain space your vertices have integer x and z coordinates you might use step length 1 (on x and z) and from that get the appropriate quads.

Example:

Your ray segment starts is AB with A = (9, 8, 0) and B = (10, 7.5, 0).
Now you know the x and z coordinates involved: 9 and 10 for x and 0 for z.
From this you can get the appropriate quad(s): Since you'd want to just check for the interval [A,B[ you'd only have to check for quad 9/0.
With those indices you read the height from the heightmap, let's say 7.7.

7.7 > 7.5 -> there might be an intersection, do a ray-triangle test on both the quad's triangles.

That's a basic outline of my idea. There might be better ones but I didn't investigate that topic yet.

Share this post


Link to post
Share on other sites
How about a technique similar to parallax mapping? Intersect the ray with a plane located on the zero xz-axis, and use the heightmap and the viewDirection (intersecting ray) to find the actual intersection. This seems like a workable solution, anything I'm missing?

Share this post


Link to post
Share on other sites
Thats what my first thought was, but i'm pretty new to C++ and my engine is a frankenstein of tutorials merged together :) Could somebody be so kind as to set me off in the right direction as to how I do it?

Share this post


Link to post
Share on other sites
If you are after a ray hit plane method:-

float distanceRayToPlane(RAY ray,PLANE plane) // will give negative Values! be warned....
{
//cos angle between ray and plane
float cosA = D3DXVec3Dot(&ray.direction,&plane.normal);
//check its not 0 or get /0 error!
if(cosA > -0.01f && cosA < 0.01f)
return (-1.0f);
//find distance from relative distance to origin
float d = plane.Dvalue - (D3DXVec3Dot(&ray.start,&plane.normal));
float dRtP = d/cosA;
return(dRtP);
}



With this and the x/y plane you have a reference to look on the height map. I dont know how your map is stored/accessed/arranged so you will have to figure that bit out. Also you might want to put a check in to stop negative numbers and the 0.01f may need to be changed to a more suitable epsilon(error margin).

-------------------

Like you said before though if there is a mountain in front and the ray is shallow the result may be very wrong.

You said you could not hit test the terrain itself? I think you probably could but it may involve some nasty bits and bobs like vertex array transforms etc.

The tanks used hit boxes? if so have big hit boxes for parts of the map. Each has same height (the highest mountain peak) depth bredth etc and you can use the same tank test method for these map boxes. If nothing else it will vastly narrow down your terrain hit testing.

Share this post


Link to post
Share on other sites
Thanks for the source, i'll give it a shot.

The reason I can do it with the entity models are because they are mesh's loaded from x files. I tried converting my terrain into a mesh (creating a mesh, setting the FVF, copying the vertex's across etc) but couldn't get that to work :( Plus even if it did, it wouldn't tell me what point it hit.

Share this post


Link to post
Share on other sites
I may not fully understand your situation but if your terrain was stored as a mesh you could use it in the D3DXIntersect() function and it would return exactly where it hit.
I know you said your terrain was stored in vertex and index buffers.

Steve

Share this post


Link to post
Share on other sites
Bumpity!

Managed to convert my whole terrain system so it produces a mesh which is now rendering perfectly, hurrar!

So I've started using the D3DXIntersect system, assuming the U and V values it spits out would be relative to the object space co-ords..

(so for example, If I click half way across the terrain, I expected the U and V values it returned to be whatever the dimensions of the terrain are * 0.5)

wrong :( It looks like the U and V values it returns, are barycentric coordinates which I assume are based around the 'FaceIndex' vertices, it's not very well documented so thats just an assumption and if anybody could set me straight, that'd be great!

If I'm right - any idea how I can turn them into the values I'd like to use? I'm guessing I'd need to get the vertex positions for the faceindex it talks about, and then + the barycentric cords onto it.. but how would I work out which vertex's make up that face :(

UPDATE: I figured it out! I took out the mesh optimize so that the faces would be kept in the order they were made in, then come up with some code which takes the face number and then calculates which 'tile' of the height map it comes under, and from which of the two triangles, and then concludes which 3 vertex's make it up. YAY! I'm getting better at this at long last ;)

nightmare! sometimes i think directx doesn't want me to use it ;)

[Edited by - PaperFace on August 21, 2007 5:30:50 AM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this