Advertisement

Simple method for implementing terrain collision?

Started by December 14, 2016 01:22 PM
23 comments, last by Norman Barrows 7 years, 11 months ago

bros, can you just give me a hint of what's the way to do it, because I did some research and there seem to be more than one way of doing it.

1st way: Cast a ray down and check intersection with terrain.

2nd way: Divide the terrain to into grids and find the height of the terrain at the specific point I'm standing

3rd way: Screenshot the world from above and use the values from the depth buffer to get some terrain stuff. This is easiest, but it's bad, right?

EDIT: Actually, it's bad if I do it every frame, but I can do it only once and save to some image or something.

And just one more off-topic question, if you have time.

Guys, can't I just start using Unity because it will do most of the hard stuff for me. The reason is that I kind of make this game of mine for 5-6 months now and I don't see any results at all.

I'm kind of a patient person, but I spent all this time bothering with loading models, loading skeletal animation, wasting time with OpenGL API, figuring out how to manage game resources, making simple state machines for animation transition, Implementing aabbs and simple raycasting stuff, tinkering with shaders in order to add shadows and blinn-phong, bothering with quaternions in order to do interpolation, and ultimately my game still sucks 6 months later.

Do the skills I'm learning actually have any value, or I'm just doing all this for fun (not so much fun when debugging).

Terrain is generally implemented as a height map. In that regard, your option #3 is basically correct:

Screenshot the world from above and use the values from the depth buffer to get some terrain stuff. This is easiest, but it's bad, right?

The height map is a simple grid. Your object is at (x,y,z). Ignore the height and look up the height map values directly under the object and compare it against the height of the object. For a small object like a player's collision capsule you probably only have a single contact point. For more complex objects you may have more than one contact point or contact area.

If your terrain changes as a result of your game, you will need to update your height map as well.

Actually, it's bad if I do it every frame

Why do you think that?

Objects that move by physics need to have collisions checked every physics update. Typically if you use a spatial grid you can reduce it down to under 3 objects that need collision tests. Terrain is probably the easiest to collide with since it is a heightmap, you can directly query for the quads directly under the object then do both broad phase and narrow phase detection easily. Other objects you need to compare two potentially complicated physics meshes with both a broad-phase and narrow-phase detection.

Advertisement

Ok, I got the height map loaded and I have a terrain that I generated using that height map in Blender.

Now how do I know exactly what pixel from the map corresponds to the place I'm currently standing at?

I'd hope you have some XY coordinate telling you where in the world you are (assuming XY is the horizontal plane).

The area covered by (xmin, ymin)..(xmax, ymax) in the world maps onto the (0,0)..(xsize, ysize) of your height map.

a hint of what's the way to do it

i use a combo of heightmap and collision map for Caveman 3.0.

the height map handles steep slopes, and the collision map handle things that stick out of the ground, like trees, rock outcroppings, buildings, etc.

when you go to move, you check a short distance ahead, and get the ground height. that combined with the height where you're at lets you compute the slope of the rise / fall in front of you. if its too steep, you "collide", if its drops off too quickly, you slide and fall. if the heightmap doesn't mess you up, then you check for banging into trees etc, using the collision map.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

my heightmap texture is 1801x1801, does it need to be a power of 2?

Advertisement

my heightmap texture is 1801x1801, does it need to be a power of 2?

No, not unless whatever you're using has some special requirements.

Hello to all my stalkers.

This is my function that gets a pixel from the image:


ILubyte getPixelFromImage( int x, int y, Image img )
{
    if( x < 0 || x > img.width || y < 0 || y > img.height )
    {
        return 0;
    }
    return img.data[ y*img.width + x ];
}

the img.data is all the bytes that the .png file contains. But how can I be sure that I use grayscale and not rgb. And I heard somewhere that the human vision is not linear that's why height maps need to be represented linearly, not using sRGB or something like that.

And the function above returns a char that can be from 0 to 255, how do I regulate the height? Because 255.0f above the ground is too much.

EDIT: Problem with the DeviL library, again. It doesn't work with 16-bit png, need to figure out something else. These c++ image libraries are more trouble than they are worth.

EDIT 2: From devil doc:

If an image is in a format that is non-native to DevIL, it is automatically converted to a useable format. All 16-bit images are handled this way, being converted to 24-bit images on load. To use your own functions to load unsupported image formats or to override DevIL's loading functions, read the tutorial on Registering.

Can I somehow read the height map as 24 bit? If I can, what should I read, R, G or B?

Generally a bad idea to use png or jpeg or other lossy formats. They're great for sending compressed images over the internet for human viewing, but they're terrible for most other applications.

Some encoders and decoders can work with them in lossless ways, but because of the way decoders work even a lossless-encoded image can suffer from artifacts on decompression.

The generic standards for this type of data are TIFF and TGA formats that support various compression options. Some engines will just store it as raw data that gets zipped up, or pgm format that gets zipped.

frob, DeviL has some problems with .tga and I don't want to bother with different library now, even if .png is lossy, it's not a big deal, for now I just want to make it work, but I can't, because it converts from 16 to 24.

EDIT: No, the documentation is old. My image is loaded as 1 byte per pixel.

I couldn't find where do I mess up. I will show you the code, in case someone sees something.


Image getDataFromImage( std::string path )
{
    Image img;

    //Generate and set current image ID
    ILuint imgID = 0;
    ilGenImages( 1, &imgID );
    ilBindImage( imgID );

    Check if loading was successful....

    //Put some stuff into my Image struct.
    img.width = ilGetInteger(IL_IMAGE_WIDTH);
    img.height = ilGetInteger(IL_IMAGE_HEIGHT);
    img.data = ilGetData();
    img.bpp = ilGetInteger(IL_IMAGE_BPP);
    printf( "%d\n", img.bpp );

    return img;
}

Getting the pixel from the 8-bit image.



GLuint getPixelFromImage( int x, int y, Image img )
{
    if( x < 0 || x >= img.width || y < 0 || y >= img.height )
    {
        return 0;
    }
    return (GLuint)img.data[ ( y*img.width + x ) ];
}

This topic is closed to new replies.

Advertisement