- I know this is about Egypt, but I will not make this specific to Egypt... because people coming here may find this question and its answers useful for other desert simulations.
- I am trying to keep this simple, avoiding too complex simulation that may eat too much resources.
- This is mainly based on Wikipedia. However I also had a read of the Slope Stability article from the Tulane University, which covers landslide among other things. And the article Coasts: Sand and Dunes from the U.S. Geological Survey.
- This is all speculative, I have never implement a similar system. I would like to see how it ends ups working, though.
- Also, I'm being a bit sloppy with my writting, sorry about that.
You need them. We will have a static layer ("bedrock"), and one dynamic heightmap (sand). We will do large scale simulations on the dynamic one, to handle dunes et.al. That will be the main focus.
Note: This model does not handle deserts with different sands types.
We also need to handle placement and movement on the sand. Objects placed on the sand will displace it, making the object sink slighly, depending on the properties of the sand and the local geometry. Also they movement of the sand may take the object out (undug).
Which brings me to... we need a wind vector field, that will tell us the wind direction and speed for every position. The wind is supposed to remove small features, we need it to simulate the movement of the desert, the shape of the desert may affect it, and it can blow objects away.
Given that small features are not permament, I would suggest to have a temporal substractive layer for small local features. Foot prints, for example. Just discard old enough ones - for a sensible definition of old enough, do not bother to simulate wind with them. Thus saving memory and processing time. Using a substractive layer for small temporary features also means that the dynamic layer does not need to have a high resolution.
And of course, particle effects, et.al.
This can be - probably - a heightmap, in particular if it is not exposed. However, if you want to have caves, you will have to use full geometry.
Does not need to plain, does not need to rough, does not need to be rendered as rock, or at all. The "bedrock" layer is a static heightmap, predefined for the area. It may serve a way to control how things happen in the upper layer. Since you cannot design the dynamic layer, this is important. I am suggesting to implement it - at least initially - as a smooth heightmap, and tweak as needed.
Remember that not all deserts are made equal, a rocky desert could have a very jaggy "bedrock" and a low dynamic sand layer, for example.
Optional: Since you have wind, and you may have exposed "bedrock", you could simulate erotion on it. Probably not something to be done realtime, unless it is some alien desert where that thing happens fast.
Here is the deal: Sand will not overhang, and will not leave cavities. So you do not really need to simulate voxel or anything like that. A heightmap will do. You will be adding this layer on top of the geometry from the "bedrock", so the effective height is the addition.
Not all sand is made equal. In particular we need to know the density of the sand, and angle of repose of the sand (this depends on the surface area of the grains, the density and the gravitatory acceleration). For you, this are values to tweak.
The repose angle will be the angle of dunes on the slip face. Usual values for the angle of repose on Earth are between 30º and 45º.
Yes, you can use random deposition for the starting position. Perlin noise will also do, and would be cheaper. You would need to teak it to make sure it does not violate the repose angle. Nothing should be steeper than the repose angle.
Optional: You can choose to consider humidity (that is up to you, it makes the model more complex). Low water saturation will make the angle of repose higher (you can build stuff out of wet sand), while high water saturation will lower it (the sand flows better). You would need a humidity map, and a function that gives you the angle of repose from the local humidity. You may consider nearby features (rivers, for example) to decide humidity sources, and use wind to spread it. This may also tell you where the - sporadic - vegetation is more likely to appear.
We need a ramping angle (for the other side of the dunes), that should be a fraction of the repose angle. Also tweak as needed.
Now, wind will move sand. In three different ways:
Tweak the proportions at which these happen.
Creep is easy. We just move values around in the dynamic heightmap, according to the wind vector field, the wind effect factor (so you only move a portion of the sand), and the elapsed time.
Image for reference (the image shows the angle of repose as 34º, Barchan is the type of dune):
Notice that the ramping angle (on the opposing side of the angle of repose) is lower (less steep).
- Creep should not result in a structure steeper than the ramping angle. You can push the excedent ahead.
- Sand should fall to the other side if it making an angle greater than the repose angle.
- Remember to always push in the direction of wind.
Saltation is basically the same thing. The difference is that we pick a landing place for the sand instead. The physics is that of a projectile being launch at the local sand angle. The strength of the launch sould be a function of the local wind vector by a factor you can tweak. Or just ignore saltation.
For Suspension, you add a sand saturation value to the wind. Honestly, I suggest to disregard the effects of suspension in the layer. And even in the wind. And use it instead for particle effects.
Note on sand sources: You can have the wind bring sand from off the map (creep from off the map). You can also have the rivers and sea bring sand. However, I would expect that sand from the wind to be main sand input.
When an object is placed on the sand, it will displace some of it. While the object is sinking, we can pretend sand behaves as a fluid (that is my engineering talking) and use the Archimedes principle.
Any object, wholly or partially immersed in a fluid, is buoyed up by a force equal to the weight of the fluid displaced by the object.
For an object on the surface, yet to displace any sand, this force will be 0. And the object will enter free fall.
An any given instant that the object is sumerged on the sand, we can mock the displaced sand with the depth, the volume of the object, and its density (wich you would need to anotate). I am suggesting to disregard object geometry and fudge it with the density value instead.
Now, that we know the displaced volume, the opposing force is a function of it. Multiply by yet another factor you tweak.
Instead of simulating the whole thing, I suggest to compute, for each object, at what depth these forces are on equilibrium. It is possible that for some object the equilibrium is not reached. You can choose to let the object sink to a given maximun depth (the "bedrock" layer, for example). Once we know the target depth for the object, we can accelerate and decelerate the object in such a way that it reaches that depth (which will be way cheaper).
Note: This requires to be able to quickly query if an object is under sand. You can do that by reading the height from the heightmapon the coordinates on the object and comparing the depth.
As per the effect on the sand... I does not matter if the sand overlaps the geometry of the object (unless we need to worry about transparent objects). If you need it can use the substractive layer to make a hole that fits the object, or even have the sand partially cover it (considering the repose angle). When the object is removed, the hole will be needed. You can simulate it filling up by reducing the feature in the substractive layer.
Optional: You can use the wheigh of the object, the input speed vector, and yet another fector you tweak, to compute an input crater. It would be better to solve the crater on the dynamic heightmap.
Note: Objects doing animations (not just being put on thrown) on the sand should also leave marks. That is the case of footprints. Just add them as features to the substractive layer.
You should also consider the wind pushing objects. You can search how to implement wind and drag.
The wind vector field
Since we only care about the wind on the surface, we can use a 2D vector field. We can represent it as a texture, where a color channel represents direction and another color channel represents magnitud. We can have another color channel for sand saturation, and the last one - if you decide to use - for humidity.
Note: The optional humidity of the air is not the same as the optional humidy map. The optional humidity map is of the and, and affects the repose angle.
This also allows us to upload it to the GPU to be used as input for particle effects, and animations (you can use it animate things moving in the wind in a vertex shader, or animate textures if you need to).
Optional: We can update the wind direction and magnitud with the height map or other relevant obstacles. I would suggest to only do this if a feature reaches a significant height (for a sensible definition of significant). For the method to update it, I suggest to just divert the vectors around the obstacle.
- You would also have to update the wind direction when one such object is removed or its height is lowered enough.
- You can push humidity and sand down to the dynamic layer and the huminidy map, if you choose to simulate suspension and have an humidity map, respectively.
- You could use a 1D perlin noise to decide how to change the intensity of wind over time. I do realize that wind should not be blowing at the same magnitud all the time, and it could be easier to just multiply by a factor that follows a smooth pseudorandom curve (evaluated according to time) than to update the vector field.
It would be interesting to see this integrated into a full wheater system. However, a desert probably does not need that.
The temporary substractive layer
Since features on this layer are not updated all at once, and we need to query features near to the player. I suggest to use a space partitioning structure.
You may also have a suplementary structure that allows to access them as a queue (probably a circular queue is a good idea), that allows a background thread to walk them and remove them as they become old. Also, evidently, when you query them from the space partitioning structure, you can remove any old elements.
Now, when I say it is a substracting layer, I mean you substract the height from its feature (in their appropiate location) from the height map. And that is how this layer allows you to make holes, footprints and similar features.
Addendum: You can also query and remove features on areas that have experienced significant creep (again, for a sensible definition of significant).
Particle effects, et.al.
As I said, the wind will have sand saturation. If you can animate "sand" particles in the direction and speed of the air, around the player (note: you will have to interpolate the surrounding values from the wind vector field), and make these particles more visible as a function of the sand saturation of the wind, you will have the means for sand storms to happen in the simulation. Or, at least, that is the idea.
Aside form that, you can use shaders to animate sand sliding or creeping in the wind. I am aware that this is not often visible, but in some cases it is. So, take your artistic license on this.