This is a quick tutorial on creating a “blackhole” shader effect in Unity. This tutorial uses Shader Forge (a popular visual shader scripting tool), which I highly recommend, but otherwise the mapping between the nodes and the code is very straightforward, so it could be a good exercise to try and create this shader in code as you follow along.

In a new scene, I first set a different skybox so that the distortion effect will be more visible. Then, I create a new “Unlit” shader with Shader Forge.

In the editor screen, we then see a single Color node feeding in to the Emission input. The Emission controls the output color regardless of the lighting.

### The Fresnel Node

Remove the Color node, and add in a new Fresnel node (you can hold the letter “F” for “Fresnel” and select the node from the menu that pops up).

The Fresnel node returns a value of 1 when the surface normal is perpendicular to the view direction, and 0 when the surface normal is parallel to the view direction (facing the camera).

The Fresnel effect can also be achieved by taking one minus the dot product of the normal vector and the view vector. Similarly, the length of the cross product of these vectors can also be used (though it will produce a slightly different result because of floating-point precision).

This Fresnel node will be used for: (1) creating the refraction effect, and (2) creating a multiplicative mask for the “hole” part.

### The Refraction Effect

To create the refraction we will be using the Scene Color node to get the image of the rendered scene behind our object.

The Scene Color can be distorted by displacing the scene coordinates (UVs) toward the center of our sphere. To get these displacement amounts we can utilize the surface normal vectors.

To get the displacement values, we will first negate the normals so that they point inward. Next, the normals must be transformed from Local space to View space (relative to the Camera). Otherwise you will get different displacement amounts as you rotate the object. For example, we want a normal vector pointing to the left of the camera to have an X value of -1, rather than the value it would have relative to the object. The last step is to mask out just the X and Y values (as R and G in the component mask), which will be used to displace the U and V scene coordinates.

What we need to do next is to control the amount of displacement using the Fresnel node. We do this by multiplying the displacement values with the Fresnel output before adding them to the Scene UVs.

This is close, but there should be a soft transition into the refraction instead of the hard edge we’re getting. What we need to do is to have the refraction start out strong in the center and fade out toward the edges. This can be done by first inverting the Fresnel values with the One Minus node, and then raising them to a Power. This has the effect of pushing the black area inward more.

### The Black Hole

The next step is to mask out the black hole area, which is relatively simple. First, we’re just going to multiply the Fresnel values by some amount (controllable by a Slider), then Round these values to 0 or 1 so that a hard edge is formed.

As it turns out, the result has values higher than 1 (floating-point math), so we need to clamp the output between 0 and 1.

### All Together

To compose the full effect, we just need to multiply the black hole mask with the distorted Scene Color output.

This produces the final result.