New terrain system - please test!


[size=150]Shader Terrain Mesh[/size]

With one of the latest commits, a new terrain implementation has been added to Panda3D.

It performs most of the rendering on the GPU, which is why its very fast. Heightfields up to 16k should be renderable in reasonable time. You can find more information about the usage here:

I also added a sample showing how to use it:

It would be nice if you could test the sample, and give me some feedback.

And finally, heres a screenshot of the ShaderTerrainMesh in the Render Pipeline (Sample can be found here:

Loading Terrain in Panda3D

Can you write a bit more about how the mesh is made ( it’s using instancing and some sort of chunked LOD system from what I can tell from looking at the shader)?
What are the hardware requirements?
How is is better then a terrain made from multiple individual meshes where one could use LODs and let panda cull the chunks outside the camera frustum?
How is it better then just one giant mesh deformed in the vert shader using a heightmap?
Can the mesh be used for collisions? (I remember seeing some info on the git updates about matching the triangles to what Bullet uses for it’s heighfield shape)
Can the heightmap be a texture buffer so that deformable terrain or editors could also use this system?

Maybe I’ll think of some more questions once I get to use it, the sdk is still currently building itself on my pc…


It uses a quadtree, which is subdivided based on the projected size of the triangles of the chunks. Basically the algorithm tries to make every triangle a fixed size, e.g. 10 pixels.
If the triangles of a chunk match the requirements, its added to the list of instanced chunks, otherwise it is subdivided further.

You could do that, but it’d be very annoying to setup, and you would also have a lot of transform states, which would slow down the entire thing. Besides of that, you don’t have the advantage of hardware instancing then.

If you have a heightmap of 8192*8192 for example, then that would be 67.108.864 vertices, which will be much slower.

You should use a BulletHeightfieldShape for that, juzzuj added a patch so the triangles match up.

The heightmap can be any texture object, however since the culling happens on the CPU, one would have to regenerate the terrain areas which changed (the terrain caches each chunk average, min and max height for culling, those would have to get recomputed). Probably something for future versions, feel free to make a patch.


Looks good, works fast, I’m definitely going to use it.

The only thing I found is that when I set the triangle width to a large number (100+ in the demo) the terrain shape changes very much when moving the camera, but I can’t think why someone would set it like that, so it’s hardly a bug.


Currently it is difficult to test.

For example there is no information about the geometry,
accordingly not possible to calculate collisions.
Yes, fast, but … that’s all that can be checked.


Quick questions:

  • Does the new terrain shader support splat maps?
  • Can i blend textures as in … tures.html ?
  • Are you using World Machine to create those terrains? If so, could you ellaborate on your pipeline from WM to Panda?


The terrain requires you to modify the default shader to add your materials, which you can either do based on a splat map or procedurally then.
Since you have full controll how materials are distributed, you can also blend them the way you want (for example using detailmaps).
Exporting from WorldMachine is simple, just export the heightfield to 16-bit png, and copy it to your application. (Notice the size should be a power of two).


Is the current shader working with splatmap channel association or some custom painting that you did? As for detail maps, is that built into the system or a separate shader per-material would be needed?

Also, which culling system are you using? A simple quad tree, octrees or CDLOD?


The default terrain shader does not come with any splatmap or procedural splatting. The reason for this is that you usually want to customize it anyway, and so you have to write the material distribution yourself.

The same applies for detailmaps, since there are a lot of possibilities.

Right now the terrain itself does provide any collision mesh, but you can use the BulletHeightfieldMesh for collisions.


What about culling?


The terrain automatically does frustum culling, as every other panda node - Internally a quadtree is used, so it should also be quite fast.

(Sorry, I did misread “collisions”, not “culling” in my last reply )


Amazing work! What happens if we want VERY big terrain? Can multiple smaller terrains be stitched together and not have seams?


Thanks, yeah, of course your heightfields need to match up, but if they do, they will fit.


Hey Tobias!

I’m playing with your terrain system, and it seems that there is some sort of problem in the way it is computing the mesh inside/outside of the field of view:

Investigating a bit, i reach the conclusion (I can be completely wrong, by the way) that it is some sort of precision problem. It seems to be related with the absolute position of the camera


P.S. You can check it with the following example:
(It is integrating the terrain system with mapzen)


It seems you are modifying the heightfield procedurally. The problem is that the terrain precomputes the chunks average, min and max height to perform efficient culling.
Try calling generate() after you modify the heightfield (I guess in after line 153 or so).

Right now this will regenerate all chunks (which can get slow depending on your heightfield size), but I think juzzuj made a patch to only update the min/max heights and only update the changed region (not sure if its in yet).


I’m afraid it is not helping at all… Moreover, it is failing even from the very beginning (before the procedural regeneration, or the camera movement). You can check that using your shader terrain example with the following height field image:

And setting the following scale and position of the terrain:

self.terrain.set_scale(7337.9547153767198, 7337.9547153767198, 1041.62109375)
self.terrain.set_pos(-3668.9773576874286, -3668.9773576883599, 750.8125)

Camera position and angle:
0.0, 0.0, 1500.0
-90.0, 0.0, 0.0



You were right, as usual… The bug was a combination of 8bit heightfield image and the missing generate() call. FIXED!


I tested the terrain demo in RenderPipeline. It starts at twilight but changes to day when I launch the day time editor. There are horizontal lines in the mist near the horizon. Occasional artifacts (black spots) on the terrain and some white artifacts in the distance (z-fighting?)

Lighting bugs in some of the other demos. Reflections only reflect the skybox, not other objects.

Ubuntu 16.04 64 bit

[>] CORE Using native core module
[>] RenderPipeline Using Python 2.7 with architecture linux_amd64
[>] RenderPipeline Using Panda3D 1.10.0 built on Aug 25 2016 21:36:34
[>] RenderPipeline Driver Version = 4.5.0 NVIDIA 361.42
[>] RenderPipeline Driver Vendor = NVIDIA Corporation
[>] RenderPipeline Driver Renderer = GeForce GTX 660/PCIe/SSE2

edit: There are also gaps in the terrain, it looks like the terrain is divided in 4 big tiles and there is a gap between each tile. There’s something weird going on with the sun and the shadows too.


It needs a better name. Suggestions ? How about Tobspears Terrain ?


Hi, I have a mobile (laptop) with the card AMD Radeon HD 7470M, issues a warning.

:pnmimage:png(warning): iCCP: known incorrect sRGB profile
Vertex shader was successfully compiled to run on hardware.
Fragment shader was successfully compiled to run on hardware.
:display:gsg:glgsg(warning): Shader skybox.frag.glsl produced the following warn
Vertex shader(s) linked, fragment shader(s) linked.

Vertex shader was successfully compiled to run on hardware.
Fragment shader was successfully compiled to run on hardware.
:display:gsg:glgsg(warning): Shader terrain.frag.glsl produced the following war
Vertex shader(s) linked, fragment shader(s) linked.