Rendering a landscape from a Texture

Started by
18 comments, last by Last Attacker 17 years, 8 months ago
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.
Advertisement
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*

"Take delight in the Lord and He will give you your heart's desires" - Psalm 37:4My Blog
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]
"Take delight in the Lord and He will give you your heart's desires" - Psalm 37:4My Blog
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.
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]).
"Take delight in the Lord and He will give you your heart's desires" - Psalm 37:4My Blog
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?
"Take delight in the Lord and He will give you your heart's desires" - Psalm 37:4My Blog
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.
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!
"Take delight in the Lord and He will give you your heart's desires" - Psalm 37:4My Blog
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 0glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, tex0ID);glUniform1i(tex0UniformLocation, 0);//Bind the second texture to texture unit 1glActiveTexture(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]
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!

"Take delight in the Lord and He will give you your heart's desires" - Psalm 37:4My Blog

This topic is closed to new replies.

Advertisement