GPU Noise in Unity
First, I'd like to show a simple demo I made of various types of noise on the GPU in Unity. You can check out the live demo on the web by clicking on the image below. You need to have a Shader Model 3.0 GPU in order to run the demo.
As you can see, there are 9 different types of noise in the demo and they are all implemented in Cg shaders on the GPU.
- Perlin - "Standard" Perlin Noise (1 octave)
- fBm - fractional Brownian motion summation of Perlin Noise (8 octaves)
- Turbulence - fBm variation that sums the absolute value of the noise result (8 octaves)
- Ridged - fBm variation from the book "Texturing and Modeling: A Procedural Approach" that performs a special ridge function on the noise result (8 octaves)
- Voronoi (F1) - A "noise" type that uses a field of random 3D points and determines the distance to the closest point
- F2 - Voronoi that determines the distance to the second closest point
- F2 - F1 - Voronoi that determines the difference between the first and second closest points
- (F1 + F2) / 2 - Voronoi that averages the distance between the two closest points
- Crater - Voronoi variation that makes crater-like structures
Have fun messing around with the sliders and seeing how the noise can be manipulated on the fly!
After completing the GPU noise demo in Unity (it's actually been done since November), I started proceeding with implementing a procedural planet generator in Unity. It quickly introduced me to some of the issues and limitations that Unity has.
- Cannot disable/control view frustum culling.
This is the worst issue I ran into. The way I implement the planet is to have a small cube that is "blown out" to form a sphere and then offset with noise all on the GPU (à la displacement mapping). Unity has a camera system that determines which objects are inside each camera's view frustum and automatically culls (doesn't draw) any objects that are outside of the view frustum. The problem is, while the small cube is not in the view frustum, the final displaced planet is in the frustum. This causes the planet to suddenly stop rendering if the camera is pointed a certain direction.
I tried several fixes such as blowing the cube up to be the same size of the planet and forcing the view angle to be the maximum value (179 degrees) when Unity does the frustum check. Neither of these got rid of the problem entirely and just reduced how much it happened. In order to fix it, game developers should have control over which objects should be culled, or be able to disable frustum culling entirely.
- Cannot run editor scripts when paused.
This problem stems from another problem in Unity. Unity doesn't send the View matrix (by design) or Projection matrix (current bug) to the shaders, so you need a script to send them manually. Because of this, you need to have this script continually updating the shader variables even when the game is paused. If they are not updated then the objects render in the same place on the screen no matter where you move the camera. This is a horrible problem with no real fix.
- Cannot create a custom collider.
Unity provides no simple way to create your own physics collider object. You can inherit from their built-in Collider class, but you cannot override any methods inside of it. As you can see from the link, I came up with a work-around for what I specifically was trying to accomplish: make a spherical planet collider. It is very similar to what I did in Bullet in the past.
- Cannot write depth in pixel shader. (Also explained here.)
I tried implementing a logarithmic depth buffer, but I was greeted with a Cg compilation error when trying to write to the depth register. This is actually a bug in the Cg compiler. It's been fixed in the compiler, but Unity is still using an old version of the compiler which has the bug. I need to test the latest releases of Unity to see if this is still a problem.