Game Development Community

Need help with ray casting

by Nicolai Dutka · in Torque Game Engine · 10/01/2007 (1:55 pm) · 14 replies

I am trying to "get" the name of the terrain texture my character is currently standing on using a ray cast. The problem is, I never learned ANYTHING about ray casting, so I have no idea where to begin.

Basically, I need a ray to start 1m or more above the controlObject's head and point straight down at his feet, ignoring the player, and returning a value equal to the name of the terrain texture he is standing on.

Here is what I have so far:
NOTHING!!

So... since I know absolutely nothing about how to set this up, I could use some help. :P

BTW, this post started with wanting to have brush based triggers, but someone told me the ray cast would be a good idea and it seems like a lot less work than setting up a billion triggers. Here is the 'brush based trigger' thread I had: garagegames.com/mg/forums/result.thread.php?qt=67797

#1
10/01/2007 (4:12 pm)
There's a couple of ways you could do this, one example follows:-

First off, grab a pointer to the TerrainBlock

TerrainBlock *terrBlock = isServerObject() ? gServerSceneGraph->getCurrentTerrain() :
                                                                        gClientSceneGraph->getCurrentTerrain();
   if (!terrBlock)
      return;

Next you want to grab the material on the square at the players current position. You can ignore (afaik) the Z coordinate and thus avoid having to get the terrain height via a terrain block call, or a raycast, which allows you to just use the players current position.

Depending upon where you're putting this code, you might be able to use getPosition() directly, either way, you want the position of the player.

S32 mapIndex = terrBlock->getTerrainMapIndex( playerObj->getPosition() ); 
      if (mapIndex != -1)
      {
         MaterialPropertyMap* pMatMap = 
                                  static_cast<MaterialPropertyMap*>(Sim::findObject("MaterialPropertyMap"));
         const MaterialPropertyMap::MapEntry* pEntry = pMatMap->getMapEntryFromIndex(mapIndex);

          // access any of MapEntry variables here and do whatever you wish, E.G name, detailMapName, sound...
       }

Hope that points you in the right direction.
#2
10/01/2007 (4:28 pm)
That is definitely engine code and not Torque script, so which engine file should I use, or should I make a new one?

I have never done any engine coding and was never taught how. I am only familiar with Torque Script. Honestly, I don't know what to do with what you just gave me, although I can see the logic behind it and 'generally' understand what it is doing. Unfortunately, I do not have the knowledge with engine code to make it work. If anyone has any time or maybe wants to trade off some work for it, let me know. I can do 3d models in Max, texturing (tiling or not, alpha channeled or not) in photoshop, and I am one of the best in my class (if not 'the' best) with Torque Script.
#3
10/01/2007 (4:55 pm)
Sorry, I didn't realise you were trying to do this in script. In script you'll probably want to use the "containerRayCast" method.

// assuming start is your player pos + a meter or two Z and end is player pos - say 500m
   %info = ContainerRayCast(%start, %end,$TypeMasks::TerrainObjectType, %player);

%info will contain a space separated list of Point X/Y/Z and Normal X/Y/Z where point is the position the ray hit the terrain, and Normal, is the surface normal at that location.

However, that will only give you a position, not the material the player is stood above. I'm not sure if there's a method exposed to torque script for obtaining the material from a position. Assuming I've not missed anything obvious, your best bet may be to read up on ConsoleMethods/ConsoleFunctions and expose the material engine code posted previously to script.
#4
10/01/2007 (5:01 pm)
Sweet! This helps a bunch! I am sure I am going to have more questions about this though. I'll work on it for a day or two and see what I can come up with. THANKS!

Now I just need to figure out how to expose that material stuff so I can use it in script....

Just to clarify though:

"%info will contain a space separated list of Point X/Y/Z and Normal X/Y/Z"

So would I get 2 '3 point vectors' back to back essentially making a '6 point vector'? (6 point vector being my own unofficial term. As in "transform" is a '7 point vector')
#5
10/02/2007 (1:16 pm)
@Gary

You said:
// assuming start is your player pos + a meter or two Z and end is player pos - say 500m

Why -500m on the %end position? If the ray is starting only 2m above the player, the ray only needs to go down about 5m to hit the ground. It starts 2m above the player, player is 2m tall, that's 4m. Add an extra 1m to be safe and 5m should reach the ground, no?

Also, in that code:
%info = ContainerRayCast(%start, %end,$TypeMasks::TerrainObjectType, %player);

What is %player? Is that the player's ID, or position, or do I have to determine what it is on my own?
#6
10/02/2007 (2:25 pm)
-500 is just an arbitrary figure that you know will be the opposite side of the object you're after. -5 to -10 would probably be fine too.

%player is the object been controlled. It's not really needed in the raycast as the cast is only going to look for TerrainObject types. So excluding the player doesn't really accomplish anything.

Quote:So would I get 2 '3 point vectors' back to back essentially making a '6 point vector'? (6 point vector being my own unofficial term. As in "transform" is a '7 point vector')

Yes. If you echo(%info) you'll see the return type.
#8
10/02/2007 (3:03 pm)
Cool!

I wrote a function as follows:
function getTexture()
{
    %p = $leader.getPosition();
    %x = getWord( %p, 0 );
    %y = getWord( %p, 1 );
    %z = getWord( %p, 2 );
    %z += 3;
    %start = %x SPC %y SPC %z;
    %z -= 10;
    %end = %x SPC %y SPC %z;

    $texture = ContainerRayCast( %start, %end, $TypeMasks::TerrainObjectType, $leader);
}

If I echo that function in console, I get the Terrain's ID number, then the position the ray hit the terrain, then "surface normal" as you called it.

What is the 'surface normal'? The value returned was: 0.415141 0.399174 0.817508

And of course, I still need to have some kind of value I can use to determine what texture the player is on. 'Surface Normal' isn't it, but I'll keep working on it.
#9
10/03/2007 (2:10 pm)
@Peter

I implemented the resource you linked to me and it is a bit confusing. I set aside what it was intended for (creating replicators with the ability to exclude replication based on terrain textures) and concentrated on simply trying to get the name of the texture the player is standing on and I just can't seem to figure it out...

The author of that resource says that the function 'GetTerrainTextures' was added, but I cannot call it from script.

@Everyone
I have tried all I can think of with my limited coding knowledge and everything I could think of with my, intermediate/almost advanced, scripting knowledge and I cannot figure out how to get the name of the texture I am standing or the name of the texture my rayCast is pointing at. I am so close I can taste it, but I can't figure out this last hurdle! :(
#10
08/01/2008 (1:39 am)
Did somebody find a solution for this?
#11
08/01/2008 (8:15 am)
First - collision normals. A normal is a vector of 1 unit in length parallel to the point your ray hits. So if you hit a terrain triangle, the normal vector is a line pointing directly out of that triangle. It's not really useful for you.

The getTerrainTextures function in that resource will return a bunch of alpha values for each terrain texture at the point you're looking at. Most of these will just be 0, since you're usually only going to have one or two terrain textures visible at any one point.
There is already a function in the terrainBlock class for this - you can see that the getTerrainTextures function just ends up calling getMaterialAlpha on the terrain block.
What I would do is make that function open to script and call it on the terrain object after casting a ray to find the terrain.

Quote:You said:
// assuming start is your player pos + a meter or two Z and end is player pos - say 500m
I believe that 500m is a nice safe distance. It depends on the behaviour you want - if the player should always be able to find the terrain, or if you don't want the functionality to be available in mid-air.
#12
08/12/2008 (5:37 am)
Can the same work for interiorinstances too?
#13
08/21/2008 (12:45 pm)
Any help guys?
#14
08/23/2008 (1:35 am)
The material names are stored inside of each detail level of the InteriorResource. Each Interior has it's own Zones, which contain Surfaces, which have textureIndices.

I worked on this for a bit, but had no luck figuring it out.

I tried using Interior::getZoneForPoint, pulling the surface from that, texture ID from the surface, and lastly, the texture name from the MaterialList. I would always get a texture. It was just never the right one. I felt as though i was forgetting something small, but am opting to sleep instead of figure it out. I'm thinking that I forgot to unwind the lists.

If you do get a solution, please post. Hopefully my information helps some.