Terrain Lighting Per Vertex - Looks Terrible

Started by
38 comments, last by Geared 13 years, 3 months ago
Quote:Original post by Geared
Er, no I wasn't applying any filtering to the height map. I was just sampling raw data. I did some searching on bilinear filtering, and didn't find that much. If I'm not scaling the height map, then would this even make a difference?
If you look back at the last set of images, you will see a lot of 'plateaus' in your normals (i.e. small flat areas, with sharp edges). This is generally caused either by performing your normal calculations at too low a precision (i.e. 8-bit integers), or because you are sampling *in-between* heightmap samples, and not filtering the samples.

Bilinear filtering is often used to scale up an image, but that is roughly what you need here. In effect, bilinear filtering provides a way to sample *between* pixels of an image, and have the colour be smoothly interpolated from the colours of the surrounding pixels. In your case, it lets you treat the heightmap as a smooth function, rather than a set of discrete points.

I think if you add bilinear filtering, and sample at fractional locations between heightmap pixels, it should improve the continuity substantially.

***

Actually, ignore that. It seems overcomplicated, and there *shouldn't* be plateaus like that in your normals, as is.

If you are able to output one of those normal generation results as an image (i.e. a normal map, one normal per pixel from the heightmap), along with the source height map, we can take a much more thorough look at what is going on...

[Edited by - swiftcoder on December 30, 2010 9:05:12 AM]

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Advertisement
But how can an image hold normals? Do you use the rgb components as xyz? the longest component is 255 and the others scaled by the same amount as that one?
or I guess you could do xangle, yangle? (but it doesn't seem like you have much precision.)
Quote:Original post by Geared
But how can an image hold normals? Do you use the rgb components as xyz? the longest component is 255 and the others scaled by the same amount as that one?
Yeah, just like that. The formula is as follows:

Color encodeNormal(Vec3 n) {	n.normalise(); // normalise vector to the range [-1,1]	n = n * 0.5 + 0.5; // further rescale vector to the range [0,1]	return Color(n.x * 255, n.y * 255, n.z * 255);}

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Alright I'm working on this now. Also I got interested in bilinear interpolation, and read about it. I hadn't written the function to get the height at any floating point value on the terrain, so I used a bilinear filter to do it. It works pretty nicely. It's smoother than I thought it would be, but I'm sure there is probably a better way to do it.

You've probably noticed my experience in image and graphics programming is pretty sparse. I'm using DevIL, and here's what I was going to try to do to saves this image:

bool Terrain::saveNormalMap(){    ILubyte* data = NULL;    data = new ILubyte[getWidth()*getHeight()];    for (int i = 0; i < getHeight() - 1; i++) {        for (int j = 0; j < getWidth() - 1; j++) {            triangleNormals_[j][2].normalize();            triangleNormals_[j][2] = triangleNormals_[j][2] * 0.5 + 0.5;            data[(getWidth()*i + j)*3] = triangleNormals_[j][2].getX() * 255; //red            data[(getWidth()*i + j)*3+1] = triangleNormals_[j][2].getY() * 255; //green            data[(getWidth()*i + j)*3+2] = triangleNormals_[j][2].getZ() * 255; //blue        }    }    ILuint imageID;    ilGenImages(1, &imageID);    ilBindImage(imageID);    if (!ilSetPixels(0, 0, 0, getWidth(), getHeight(), DEPTH?,IL_RGB, IL_UNSIGNED_BYTE, data)) {        std::cout << "Could not set pixel data when saving normal map." << std::endl;        ilDeleteImages(1, &imageID);        delete [] data;        return false    }    if (!ilSaveImage("normalMap.png") {        std::cout << "Failed to save normal map image." << std::endl;        ilDeleteImages(1, &imageID);        delete [] data;        return false;    }    ilDeleteImages(1, &imageID);    delete [] data;    return true;}


I think it's all dandy except for ilSetPixels(). I'm not really sure what to put for depth. Is that color depth, like 256 colors per pixel? or is it 8 signifying 8 bits per pixel. I'm rather confused about what that should be. Also I haven't looked at this code very carefully (I always have to think about it a lot when I use arrays so I don't get access violations).

Yeah, I think it'll be ready one I figure out what to use for depth. We'll see, haha.

edit:

Quote:Original post by swiftcoder
Quote:Original post by Geared
But how can an image hold normals? Do you use the rgb components as xyz? the longest component is 255 and the others scaled by the same amount as that one?
Yeah, just like that. The formula is as follows:

*** Source Snippet Removed ***

When you add 0.5 there, you mean you adding that much to the magnitude, correct? Otherwise, I'm not sure how that operation would work?
Quote:Original post by Geared
Alright I'm working on this now. Also I got interested in bilinear interpolation, and read about it. I hadn't written the function to get the height at any floating point value on the terrain, so I used a bilinear filter to do it. It works pretty nicely. It's smoother than I thought it would be, but I'm sure there is probably a better way to do it.
There are a number of better filters (i.e. bicubic), but bilinear is often a good trade-off between quality and speed. It is the same filtering provided on the GPU for textures.
Quote:I think it's all dandy except for ilSetPixels(). I'm not really sure what to put for depth. Is that color depth, like 256 colors per pixel? or is it 8 signifying 8 bits per pixel. I'm rather confused about what that should be.
It has been a while since I used DevIL, but it should be bit-depth, i.e. 8.
Quote:When you add 0.5 there, you mean you adding that much to the magnitude, correct? Otherwise, I'm not sure how that operation would work?
Add 0.5 to each component of the vector.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

can this help?

http://www-f9.ijs.si/~matevz/docs/DevIL/il/f00180.htm


Free Image is easier to use though. Try that out.
http://img440.images...gamedevsig.jpg/

I'm not the typical programmer.
Quote:Original post by GMA965_X3100
can this help?
http://www-f9.ijs.si/~matevz/docs/DevIL/il/f00180.htm
Huh, I never would have guessed that from the function signature. 3D image support is cool though.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

OK, I think I got this now.

Here's the high map I'm using:



and here's (hopefully) the normal map:


I can't tell much from it, but maybe you can.
Quote:Original post by Geared
OK, I think I got this now.

I can't tell much from it, but maybe you can.
Looks pretty much perfect! I would say you have most of the kinks ironed out.

There are still small discontinuities, though. If you zoom in on one of the flat areas, you can see faint 'layers' appearing. You probably have to play around with your sobel kernel to correct these.

And now, you are halfway to normal mapping your terrain as well [smile]

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

I went ahead and applied that bilinear filter to the image. It was pretty easy to implement, because of the way that I transfered all the raw data into the 2d std::vector
So I just added a step where I applied a filter on the raw data. I allowed float values in the filtered data.

It did a great job at smoothing the terrain which makes it look a lot nicer in places. I think it made a pretty big difference. I'm going to do some research on that sobel business now. I didn't implement it before because I didn't understand it, and I think it's a pretty good rule not to implement an algorithm that you don't understand.

Thanks again for all the help. I learned a ton of new stuff, and of course I rep't you long ago

This topic is closed to new replies.

Advertisement