Procedural terrain: What's the best approach to calculate noise in the GPU? A few years ago I started creating a procedural planet engine/renderer for a game in Unity, which after a couple of years I had to stop developing due to lack of time. At the time i didn't know too much about shaders so I did everything on the CPU. Now that I have plenty of time and am more aware of what shaders can do I'd like to resume development with the GPU in mind.

For the terrain mesh I'm using a cubed-sphere and chunked LODs. Since terrain never changes, heights for each chunk need to be calculated just once.The way I calculate heights is rather complex since it's based on a noise tree, which is created from an artist/designer-provided XML for each main planet/asteroid. Leaf nodes in the tree would be noise generators like Simplex, Value, Sine, Voronoi, etc. while branch nodes would be filters and modifiers (FBM, abs, neg, sum, ridged, billow, blender, selectors, etc). 

To calculate the heights for a mesh you'd call void CalcHeights( Vector3[] meshVertices, out float[] heights ) on the noise's root node, somewhere in the game code.

This approach offers a lot of flexibility but also introduces a lot of load in the CPU. The first obvious thing to do would be (I guess) to move all generators to the GPU via compute shaders, then do the same for the rest of the filters. But, depending on the complexity of the noise tree, a single call to CalcHeights could potentially cause dozens of calls back and forth between the CPU and GPU, which I'm not sure it's a good thing.

How should I go about this?
r a similar problem (a tree of combined noise functions, evaluated on the GPU), I found a good method is to generate a shader from the expression tree.  Each predefined node corresponds to a single shader function, e.g.

float simplexNode(vec3 pos) {
  // ... implementation of simplex noise
}


or

float sumNode(float val1, float val2) {
  return val1 + val2;  // ... possibly clipped or whatever
}


You'd then create a shader like

#version 300 core
// ... include node definitions here
in vec3 vertexPos;
out float vertexHeight;
void main() {
  float f1 = simplexNode(vertexPos);
  float f2 = worleyNode(vertexPos);
  float f3 = sumNode(f1,f2);
  // .. a bunch more
  vertexHeight = f76;
}


Constant parameters could either be uniforms, or just pasted straight into the code.

One limitation of this method is that the noise functions and methods have to be local, i.e. the evaluation can be done pointwise.  In my case, some nodes were blends and convolutions, so I had to evaluate pieces of the expression tree into textures, blend or convolve the textures into new textures, then use these textures as leaves for the rest of the expression tree.  All of the combinators you mentioned seem to be local, so this may not be a problem for you.