Sign in to follow this  

Rendering a landscape from a Texture

This topic is 4157 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I've been looking through docs, Google, etc. to try and find out how to do this (the whole day) and only got a partial answer. Basically what I want to do is send a texture to the video card in RGB (or FLOAT, doesn't matter) form. Then from the video card, use the texture to render a heightmapped landscape. I know that the new shader stuff has a Vertex Texture Fetch function that does exactly what I want but apparently, you can do this also by using (if I can call it this) before-shader-extensions. IOW, by not using SHADERS, I would like to accomplish just that. I figured that I can make a buffer on my Video Card (yes, I have a nVidia 6-series card) to copy the texture to (I know how to do that [wink]). Then manipulate the texture on the card by expanding it for having 3 coordinates of type float since the texture has only 1 float per pixel which is not enough for rendering a heightmap (don't know how to do that [sad]). Then tell the video card to draw that. Why would I want to do it from a texture? Well textures for heightmaps are 1/3 the size of the vertex equivalents, so its sent faster to the video card. Also, you can perform texture compression to make it even better! Does anyone know how this can be done, even roughly equivalent (to draw a heightmap from a texture in video memory)? Thanks

Share this post


Link to post
Share on other sites
What you could do is the following:

1. Load Heightmap texture. Its best if it is greyscale, with black being low.

2. Create a plane with X*Y number of polygons. I think the easiest way to do this is to have the plane be a multiple of the size of the texture. What I mean is, if the texture is 256x256, then the plane is assigned a step size (the space between the vertices) which multiplies that size. Say, a step size of 10 would mean that the plane would be 2560x2560 units with 10 units between each vertex.

3. For each pixel in the heightmap, set the corresponding vertex's (i.e. pixel (0, 0) will mean vertex at position (0, 0, 0)) height to a value (displacement strength) multiplied by the floating point value of the RGB color on that pixel divided by 3 (average since it is greyscale).

Share this post


Link to post
Share on other sites
I don't think there are any cards can actually "produce" verticies, this may be different in the up and new geometry shader but for the most part I think you're just limited to vertex and pixel manipulation.

Heightmap is the way to go.

(Don't quote me on this, I haven't done much shader work)

Share this post


Link to post
Share on other sites
Ok the thing is, I know how to make a client-side (OpenGL based) version of the whole Heightmap thing. Sorry, my question probably wasn't clear enough.

I would like to tell OpenGL to render a heightmap landscape from a texture found in the video card memory. I don't want to send glVertex3f() commands from the CPU to the GPU the whole time (via OpenGL). So I need some OpenGL commands that could interpret the texture as a heightmap for landscape rendering. Imagine the performance increases one can expect from landscape rendering.

I hope its more clear now [wink].

Share this post


Link to post
Share on other sites
That depends on how you store the image data (pixel data). For example, in my app, I have a Texture class with a dynamic array of unsigned chars (byte, 0-255) that stores each pixel's color (RGB or RGBA depending on bit-depth).

There are some useful tutorials on loading TGA, JPG, BMP and other common formats laying around the net. I recommend TGA or PNG.

Share this post


Link to post
Share on other sites
I *can* load it and assign to a texture, but I need to access a single pixel. Do you know how should i do it?

I use the code from Beginning OpenGL book (http://glbook.gamedev.net/boglgp/) and load it from tga file.

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, heightMap->GetWidth(),heightMap->GetHeight(), 0, heightMap->GetImageFormat() + GL_RGB, GL_UNSIGNED_BYTE, heightMap->GetImage())


Did this help, or should I paste the file loading code?

If not, how would you get the red color in for example your program? Some pseudocode would be helpful

update: is using glGetTexImage a good way to do it? will i be able to receive 1 pixel, divide it into colors and then check their values?

[Edited by - EliteWarriorManTis on July 22, 2006 6:41:13 PM]

Share this post


Link to post
Share on other sites
I am by no means an expert, but I've read that if you use the RAW format, it basically stores each pixel as a byte and then each byte's is stored like 0xRRGGBBAA or something of that sort. Then, you can simply iterate through the byte[] array stored in the RAW file. I don't know any of the details, though, but I'd say [google] the RAW format.

Share this post


Link to post
Share on other sites
As PumpkinPieman said, no current cards can create vertices in a shader. What you can do is send the vertices and use the vertex texture to offset their heights. This is displacement mapping on hardware. Since you still need to send vertices, you are not saving on memory at all, and are actually using more memory than if you just sent the vertices. Also, there are very few texture formats that are currently supported for vertex textures, and I don't believe any of them are compressed formats (that may have changed by now, but I don't think so). Vertex texture fetches are also slower than regular texture fetches in current hardware.

Displacement mapping would really only be useful if you needed a dynamic heightmap (and one that changed very frequently). Even then I'd say there are more efficient methods. Otherwise just sending the vertices in the proper position is much more efficient. If you are still rendering objects using immediate mode calls (glVertex3f, etc) you have a lot of room for improvement without having to worry about displacement mapping or other odd techniques. Just using vertex arrays will speed up your transfer speeds considerably, and with that you are still transferring the vertices to the card every frame. Using display lists or VBOs will speed it up even more by storing the information on the card for you. By using the basic rendering method you also don't have to do the extra work (vertex texture fetch and offsetting) in the vertex shader every frame.

So in summary, forget about using vertex texturing for now and look into using VBOs. There's a lot of information out there (and in here) about it.

Share this post


Link to post
Share on other sites
Thanks for your reply.
Man, what you said is contradictory to what I heard (and I'm not saying you're wrong!).
The Geometric Clipmaps (featured as a chapter in one of the GPU gems II book - Terrain Rendering Using GPU-based Geometry Clipmaps) algo by Hugues Hoppe's team, uses vertex textures for rendering "static" terrains (HUGE ones!) in realtime. As a project, I wish to write my own version thereof and what I heard was that sending a vertex texture to the video card reduces the bandwidth between the CPU and the GPU. Then (with displacement mapping as you've said, just discovered this a few minutes ago [wink]) using the vertex shader, you draw the landscape from the texture color coordinates.

I ran a demo of displacement mapping from this site (http://www.ozone3d.net/tutorials/vertex_displacement_mapping.php) and had a frame rate of 45 fps. I'm not sure how it would have been without displacement mapping. I have a Geforce 6200 with TC.

I got to implement it, but it runs VERY SLOW! I must have done something wrong. Its like 1 frame a minute or something. [lol]

But it does look like it that you cannot implement the same without shaders. If I had to implement a "software" [wink] mode, I should use VBOs. Sure I can send the texture data to the video card but how do you tell OpenGL "draw each pixel as a vertex height position x-units wide and long apart"? I will have a chat with my lecturer again about this. Luckily I should only have the alpha version ready by Thurday. *phew*

Share this post


Link to post
Share on other sites
Well, good news is I managed to get displacement mapping to work and it runs at more than 50 fps (minimum)!
Bad news is it doesn't draw my terrain correctly. You know when you draw an RGB image on screen and you accidently used an RGB instead of an RGBA format? Well that's how my terrain looks like. Misaligned or rather its asif I added or removed a pad byte from a bitmap image.
Anyway, I'll work on it some more to try and get it to display correctly.
I saw that it runs terribly slow if you don't use the GL_RGBA_FLOAT32_ATI (or the LUMINANCE one) texture format or whatever. Thats why I had a render process of 1 frame per "minute". I used the wrong texture without knowing it. I did implement the whole vertex texture process but I was confused as to which texture the vertex shader used to draw from.

EDIT: Ok, I fixed it. The problem I showed above was exactly that. I used RGB instead of RGBA! Man I feel embarresed. [embarrass]
But atleast it now runs at over 200fps!

[Edited by - Last Attacker on July 24, 2006 2:00:48 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Last Attacker
...
The Geometric Clipmaps (featured as a chapter in one of the GPU gems II book - Terrain Rendering Using GPU-based Geometry Clipmaps) algo by Hugues Hoppe's team, uses vertex textures for rendering "static" terrains (HUGE ones!) in realtime...
The Geometry Clipmap algorithm is very much a dynamic algorithm. The only static part of it is the terrain data, which doesn't really need to be static. One of the main reasons for implementing it using vertex textures on the GPU was because updating the vertex and index buffers in the original implementation was too prohibitive. At a very basic level it is just displacement mapping using a vertex buffer for the x and y positions of each vertex and a single-channel vertex texture to access the vertices' heights. The hard part is all the updating. Read section 2.4 of that chapter (it's linked from Hoppe's home page, there's also a link to the original paper there).
Quote:
Original post by Last Attacker
...As a project, I wish to write my own version thereof and what I heard was that sending a vertex texture to the video card reduces the bandwidth between the CPU and the GPU...
Could you explain that? I don't see how sending an extra texture to the card (in addition to the vertices, since you can't create vertices on the card itself) reduces bandwidth. In some cases it could, such as instead of updating an entire VBO you just update a single-channel height map while keeping the x-y positions from the vertex buffer static (like in the GPU Geometry Clipmaps implementation). However if it's a purely static scenario, sending the VBO with the vertex positions to the card once and rendering from that is better than sending the VBO and vertex texture to the card once and then using slow vertex texture fetches every frame to render. And although updating a VBO may not be quite as fast as updating a texture, if you don't have to update it all that often it's probably more efficient to use a dynamic VBO than to update the vertex texture and still have the expensive texture fetches every frame.
Quote:
Original post by Last Attacker
...
EDIT: Ok, I fixed it. The problem I showed above was exactly that. I used RGB instead of RGBA! Man I feel embarresed.
But atleast it now runs at over 200fps!
That's pretty good, but I still maintain that if you used VBOs properly and didn't have those vertex texture fetches every frame it would run even faster. I don't know exactly what you're doing though so I may be wrong.

Again, vertex textures definitely have their uses, but for most cases it's best to avoid them for now (while they are slow and widely unsupported). Of course if this is for research (which I'm starting to think it is) and maximum performance is not required then by all means use vertex textures.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kalidor
Of course if this is for research (which I'm starting to think it is) and maximum performance is not required then by all means use vertex textures.

Well this is a project for my Honours degree. I am implementing the Geometric Clipmaps from Hugues Hoppe as my project. No special applications though, as this is tough enough with all my other project I have to do.

Quote:
Original post by Kalidor
Could you explain that? I don't see how sending an extra texture to the card (in addition to the vertices, since you can't create vertices on the card itself) reduces bandwidth.

What I meant witht the bandwidth between the CPU and the GPU is:
if you had to call glVertex3f() the whole time or send a vertex's {x,y,z} coordinates, for a couple of thousand vertices, then the road between the CPU and the GPU can get crowded.

What I wanted to accomplish is not to send those data at all. Instead, I send a heightmap texture to the GPU and let the GPU decode it into vertex data. I tried to find other ways of doing this but this is the closest I could get to letting the GPU do the heightmap rendering directly off the texture. Vertex-textures is the only solution to that which I could find.

Quote:
Original post by Kalidor
The Geometry Clipmap algorithm is very much a dynamic algorithm. The only static part of it is the terrain data, which doesn't really need to be static.

Well I meant that the landscape doesn't change when rendering. Its not like bombs will explode on a mountain and leave huge craters [wink].

Quote:
Original post by Kalidor
However if it's a purely static scenario, sending the VBO with the vertex positions to the card once and rendering from that is better than sending the VBO and vertex texture to the card once and then using slow vertex texture fetches every frame to render. And although updating a VBO may not be quite as fast as updating a texture, if you don't have to update it all that often it's probably more efficient to use a dynamic VBO than to update the vertex texture and still have the expensive texture fetches every frame.


At this stage, I'm not using VBOs at all. Although I am using a triangle strip to render my terrain. Dunno if it has the same issue. But isn't vertex textures supposed to remain in video memory? I mean, you allocate them like an ordinary texture and free it when you're done with it.

Quote:
Original post by Kalidor
That's pretty good, but I still maintain that if you used VBOs properly and didn't have those vertex texture fetches every frame it would run even faster. I don't know exactly what you're doing though so I may be wrong.


I think I have to use VBOs for my "software" implementation. Software in the sense that its a shader-free version (if I get the time to do that [smile]).

Share this post


Link to post
Share on other sites
But now I have another problem.
My landscape is using the landscape.tga texture for its geometric form. Now how do I render grass.tga over it to let it look more ... a ... better? [lol]
In GL shader language that is!

Here's what I have:

Vertex Shader:

uniform sampler2D displacementMap;
uniform float scale_val;

void main()
{
vec4 newVertexPos;
vec4 dv;
float df;

gl_TexCoord[0] = gl_MultiTexCoord0;

dv = texture2D(displacementMap, gl_MultiTexCoord0.xy);

//df = 0.30 * dv.x + 0.59 * dv.y + 0.11 * dv.z;
//newVertexPos = vec4(gl_Normal * df * 100.0, 0.0) + gl_Vertex;

newVertexPos = vec4(0.0, 0.0, (dv.x + dv.y + dv.z) * scale_val, 0.0) + gl_Vertex;

gl_Position = gl_ModelViewProjectionMatrix * newVertexPos;
}



Pixel Shader:

uniform sampler2D colorMap;

void main(void)
{
gl_FragColor = texture2D(colorMap, gl_TexCoord[0].xy);
}



When I overwrite the colorMap with the grass texture's texture ID, then it renders the first texture I loaded onto it instead. I tried loading the grass texture first, but then it rendered my landscape texture. Aye! Anyone, knows whats going on?

Share this post


Link to post
Share on other sites
Quote:
Original post by Last Attacker
What I meant witht the bandwidth between the CPU and the GPU is:
if you had to call glVertex3f() the whole time or send a vertex's {x,y,z} coordinates, for a couple of thousand vertices, then the road between the CPU and the GPU can get crowded.
That's very true, but immediate mode calls (glVertex*, etc) are the slowest possible way to tell OpenGL what to draw. You don't need to send the data to the video card every frame. See below...
Quote:
Original post by Last Attacker
What I wanted to accomplish is not to send those data at all. Instead, I send a heightmap texture to the GPU and let the GPU decode it into vertex data. I tried to find other ways of doing this but this is the closest I could get to letting the GPU do the heightmap rendering directly off the texture. Vertex-textures is the only solution to that which I could find.
As was said before current cards can't create vertices, so you will always need vertices either sent to the card or in a vertex buffer object (VBO) on the card. What you can do is use the GL_ARB_pixel_buffer_object (PBO) extension to use the texture data as a source for vertex data. However this is really only useful for "rendering to a vertex array." That means you render something to a texture and then use that as vertex data. If you're just loading this data from disk however it's best to just dump it into a regular VBO.
Quote:
Original post by Last Attacker
At this stage, I'm not using VBOs at all. Although I am using a triangle strip to render my terrain. Dunno if it has the same issue. But isn't vertex textures supposed to remain in video memory? I mean, you allocate them like an ordinary texture and free it when you're done with it.
Yes, vertex textures will most likely stay in video memory if you have enough of it. But there are other ways to store vertex data (actual vertex data instead of a texture that represents it) on the video card that are much faster to access; namely, VBOs (or display lists). You really should drop the immediate mode rendering and implement vertex arrays first (read about them in Chapter 2 of the Red Book). Vertex arrays will still send the data every frame, but it is all sent in a few function calls instead of several for each vertex like in immediate mode. That alone is usually a huge increase in speed. Once you have vertex arrays working, implement VBOs. They are easy to use if you know how to use vertex arrays (it uses the same functions) and they will let you store your vertex data on the video card. After that you can worry about using vertex textures if you still feel you should. You should still use a VBO to store the vertex data (since video cards can't create vertices). However, in most cases a pure VBO implementation will be faster than using a VBO and vertex texture.
Quote:
Original post by Last Attacker
I think I have to use VBOs for my "software" implementation. Software in the sense that its a shader-free version (if I get the time to do that [smile]).
You should still use VBOs to store the vertex data because it will (most likely) store it on the video card. And for static vertex data (even for most dynamic vertex data) you definitely don't want to be transferring the vertices every frame.
Quote:
Original post by Last Attacker
When I overwrite the colorMap with the grass texture's texture ID...
Your shader code looks okay but that is wrong. You need to set the uniform variable to the texture unit that the texture you want to use is bound to. So if your grass texture is bound to texture unit 1, you need to set colorMap to 1 in your glUniform* call.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kalidor
Your shader code looks okay but that is wrong. You need to set the uniform variable to the texture unit that the texture you want to use is bound to. So if your grass texture is bound to texture unit 1, you need to set colorMap to 1 in your glUniform* call.


Yeah I did. Thats what bothers me. By using a class I wrote for working with GLSL, I did the following to get it to work. Note that its just a temporary fix, I really want to fix this properly ASAP.

I moved my grass texture to the front of the texture loading queue.
Then I found that if I specify to use another texture's ID instead of the grass texture, then it loads the first texture and maps it onto the terrain and that draws my grassy terrain.


land_sh->setUniform1f("scale_val", 1.5f);

glBindTexture(GL_TEXTURE_2D, TMLOAD("landscape")->id);
land_sh->setUniform1i("colorMap", TMLOAD("font")->id);

glScalef(1000.0f, 1000.0f, 1000.0f);
drawTerrain(128, 128);
glScalef(1.0f, 1.0f, 1.0f);
land_sh->end();



TMLOAD is a MACRO for calling my singleton texture manager and retrieving the texture id.
land_sh is my shader class object.
I just scaled the terrain to make it look larger [wink] but I will enventually do it properly. You will also see (like I explained above) that I loaded a different texture's id instead of my grass texture to let it draw my grassy texture on the terrain.

I still don't know why it won't work. Am I missing something?

Quote:
Original post by Kalidor
You should still use VBOs to store the vertex data because it will (most likely) store it on the video card. And for static vertex data (even for most dynamic vertex data) you definitely don't want to be transferring the vertices every frame.


I am now considdering to also implement VBOs in my current program. I'll try doing it with vertex-textures and then without, just to see what actually happens.

Thanks for your responce Kalidor!

Share this post


Link to post
Share on other sites
Quote:
Original post by Last Attacker
I still don't know why it won't work. Am I missing something?
I think you misunderstood me. You don't send the texture ID to glUniform1i, you want to send the texture unit that the texture you want to use is bound to. So for setting two textures to use in a shader it would be something like this...
//Bind the first texture to texture unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex0ID);
glUniform1i(tex0UniformLocation, 0);

//Bind the second texture to texture unit 1
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex1ID);
glUniform1i(tex1UniformLocation, 1);
Note that I'm not setting the uniform to the texture ID but to the texture unit it is bound to.
Quote:
Original post by Last Attacker
I am now considdering to also implement VBOs in my current program. I'll try doing it with vertex-textures and then without, just to see what actually happens.
Good, you should get quite a large boost in performance over immediate mode rendering. Remember to start with vertex arrays first (here's the Red Book link again) because using VBOs builds on that and it is much easier to first learn to use the vertex array syntax without having to worry about how to send the data to the buffer objects.
Quote:
Original post by Last Attacker
Thanks for your responce Kalidor!
You're welcome, that's what we're here for! [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by Kalidor
Note that I'm not setting the uniform to the texture ID but to the texture unit it is bound to.


Oh, I see now. I was wondering why some code samples used constants instead of texture ids! Now it works!

Thanks and God Bless!

Share this post


Link to post
Share on other sites

This topic is 4157 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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