Material parameter inputs
- Angle of Layer 01 - Threshold angle for layer with a slight slope
- Angle of Layer 02 To - Threshold angle for layer with some slope
- Angle of Layer 03 - Threshold angle for layer with a medium slope
- Angle of Layer 04 - Threshold angle for layer with a large slope
- Angle of Layer 05 - Threshold angle for layer with extreme slope (cliff faces)
- Border of Layer 01 - Blurriness of border of layer with slight slope
- Border of Layer 02 - Blurriness of border of layer with some slope
- Border of Layer 03 - Blurriness of border of layer with a medium slope
- Border of Layer 04 - Blurriness of border of layer with a large slope
- Border of Layer 05 - Blurriness of border of layer with extreme slope
- Detail Blend - Inputs for detail texture node at end of material pipeline
- Detail Scale - Inputs for detail texture node at end of material pipeline
- Height blend in Layer Sand - Threshold height for Layer Sand
- Height blend in Layer Snow - Threshold height for Layer Snow
- Height Level in Layer Sand - Blurriness of border of layer Sand
- Height Level in Layer Snow - Blurriness of border of layer Snow
- Line Blends - How much to turn on sediment layer effect.
- Line Blends Hill - How much Layer 04 and 05 contribute to sediment layer effect
- Metallic Multiply - How much Layer 04 and 05 contribute to metallic effect
- Metallic Multiply 2 - How much snowy cliffs contribute to metallic effect
- Metallic Snow Multiply - How much Snow Layer contributes to metallic effect
- Roughness - Final roughness tweak
- Roughness Multiply - How much Layer 04 and 05 contribute to roughness input
- Roughness Snow Multiply - How much Snow layer contributes to roughness input
- Snow Multiply - How much Snow Layer contributes to specular input
- Specular Multiply - How much Layer 04 and 05 contribute to specular input
Reverse Engineering Design Notes
I counted 8 main layers. 1 Sand layer, 4 grassy layers of varying degrees of 'grassiness', 1 snow layer and 2 stone like layers. Each one of this layers has a corresponding base color texture map and a normal map. Moreover, the texture maps are modulated by different base colors that are set up as input parameters at the beginning of the shader. Also, both the base texture maps and normal maps are at times linearly interpolated between two versions of themselves. 1 version has one UV scaling and the other has a different (larger) UV scaling. I understand that is done to provide macro variation for the textures or normal maps. In other words, this technique is meant to hide the repeating pattern of some of these texture maps and normal maps.
Also, its worth noting that linear interpolation plays a huge role in this shader. Specially true for the Base Color and Normal Inputs. Base color, for example, is the result of a cascade (daisy-chain) of lerp nodes in between layers in which the previous result of one lerp node is plug in as the first input of the next and so on. Because of this cascade setup each pixel color is exposed to the influence of potentially more than one layer at a time. Reason also being that the alpha inputs driving this lerp nodes are at times based on world height of the pixel (Sand layer and snow) and in other times based on the vector world space normal angle (all the different layers not sand nor snow). The Normal Input of the material is blended in the exact same way of cascaded lerp nodes. Except that this time the lerp nodes are linearly interpolating between normal maps as opposed to texture maps.
Finally, the final results of the cascaded lerp nodes, for both base color and normal, are not directly connected to their respective inputs, no... Instead, they are connected to a Detail Texturing node as diffuse and normal inputs. One special purpose texture map meant to provide a detail diffuse pattern is connected to the detailed diffuse input and similarly a special purpose normal map is connected to the detail normal input. Detail texturing node allows for a texture to look good and detailed when viewed from up close. More details about that node explaining how its other inputs such as 'scale' and 'diffuse intensity' affect the result can be found here. The diffuse and normal outputs of that node are in turn plugged into the final material node as the base color and normal inputs respectively.
Actually, what I said in the paragraph above is technically incorrect. The final result of the base color cascaded lerp nodes is not connected directly to the Detail Texturing node but rather modulated (multiplied) with an input parameter color called 'Base color multiply'. After this fact is then connected into the Detail Texturing node. A similar situation occurs with the resulting normal except specifics are more elaborate. The normal result from the cascaded lerp nodes is further processed before it can be used in the Detail Texturing node: it is optionally blended with a special purpose normal map with the intent of providing a nice sediment layer effect. I said optionally because this blend, which is achieved through a built in Blend Angle Corrected Normals node, is controlled by a lerp between the original normal result and the new processed angle produced by the Blend Angle Corrected Normals node. Furthermore, the alpha controlling this blend is produced by a series of nodes that modulate the influence of Layer 04 and Layer 05 with an input parameter called 'Line Blends Hill'. The result of this is added to the influence of the layer sand and then added to the influence of Layer 01. Final result is modulated by another input parameter called 'Line blends'. It is here that the optional normal blend to create sediment layer lighting effect can be shut off by setting this parameter to zero. One more interesting thing about the sediment layer lighting effect is that the special purpose normal map used by the Blend Angle Corrected Normals node is 64x2048. This makes sense when one considers that its UV cords are mapped to as YZ (as opposed to the more usual XY for height maps UVs).
Sand Layer: Sand layer has the macro variation technique applied to it where two versions of itself, each one using a different UV scaling, are linearly interpolated. The linear interpolation alpha input is driven by a special macro variation purpose texture (texture looks like somebody had made random splashes of colors in canvas). For driving this interpolation (alpha input of lerp node) only the green channel of the macro variation special purpose texture is used. Sand Layer is linearly interpolated with Layer 0001. Layer 0001 is the result of linearly interpolating between Layer 00 and Layer 01 using a macro macro variation texture for driving this lerp. I called it macro macro variation texture because this is the same special macro variation texture mentioned before (the one that looked as if somebody had made random splashes of colors in a canvas) but it has been added with another version of itself that uses a larger UV scale in order to achieve even more of a variation effect. Now this macro macro variation texture's red channel is negated (1-x) and clamped (0 to 1) and then used to drive the lerp between Layer 00 and Layer 01 to produce Layer 0001 as mentioned above. Now, because Layer 00 and Layer 01 are the same texture map (green grassy one) but modulated (multiplied) by different base input parameter colors, the resulting Layer 0001 is basically a grassy texture with random patches of light green and dark green laid out in a macro variation pattern.
The linear interpolation between Sand Layer and Layer 0001 is controlled (through an alpha input in the lerp node) by two input parameters: "Height Level in Layer Sand", aka "height of layer", and "Height Blend in Layer Sand", aka "blurriness of layer". If we name the first parameter A and the second B then the alpha for the lerp node is calculated as follows:
clamp( 0,1, (PixelWorldZ - (A - B/2)) / B )
When PixelWorldZ = A, clamp (0, 1, 0.5) = 0.5
When PixelWorldZ <= (A - B/2), clamp( 0, 1, <= 0) <= 0
When PixelWorldZ >= (A + B/2), clamp( 0, 1, >= 1) >= 1
This math set up means that the sand layer only has full lerp influence on pixel (1) when pixel is above the threshold and none influence (0) when is below the threshold. Therefore, a (1-x) node is connected to this result to reverse the situation: full influence on pixel when pixel is below threshold and none when pixel is above threshold. Partial influence when its within threshold range. Although the linear interpolation between current value and Snow Layer happens further down in the cascade of lerp nodes its worth mentioning here that its alpha input driving its lerp node its calculated in the exact same way as shown above for the sand layer. Only difference been that A and B are called "Height Level in Snow" and "Height Blend in Snow Sand" instead. And also the (1-x) at the end of the computation is not used for snow because in this case we want full influence when the pixel is above the threshold and none when pixel is below the threshold.
Next lerp node down the cascade of lerp nodes is between previous result and Layer 01. Result of that is linearly interpolated with Layer 02. Result of that is linearly interpolated with Layer 03. Result of that is linearly interpolated with layer Snow (so that snow influence propagates to upper layers from here on). Result of that is linearly interpolated with Layer 04. Finally, result of that is linearly interpolated with Layer 05 after Layer has been modulated by a new special purpose macro variation texture. From here on the result of that is connected to the base color input of the Detail Texture node as explained earlier.
Now, the alpha inputs driving the cascading lerp nodes involving Layer 01 through Layer 05, excluding Snow Layer, are all calculated with the formula shown below. Formula is function of the VertexNormalWorldZ and two input parameters. The "Layer angle', lets call it A, and the 'Border of Layer', aka layer blurriness, let's call it B. Because VertexNormalWorldZ represents the z component of a normalized normal, 1 means a normal of 0 degrees and 0 means a normal of 90 degrees. Layers from 01 to 05 are set up so that their layer angle is incremental. In other words, layer angle of Layer 02 is larger than the one for Layer 01 and so on and so forth. This is why Layer 01 is grassy while Layer 05 is stony. Without further ado here is the formula.
F(VertexNormalWorldZ, A) = 1 - (clamp( 0, 1, VertexNormalWorldZ - A) * (1 / (1 - A)))
The easiest way to understand this is by looking at how a given layer angle can influence a given vertex normal angle. In this example we are simplifying a bit and assuming there are only three layers with a layer angle of 0.9 (close to zero degrees), 0.7 (between zero and 45 degrees) and 0.4 (greater than 45 degrees) respectively.
F(0.9, 0.9) = 1.0
F(0.9, 0.7) = 0.333333
F(0.9, 0.4) = 0.166667
F(0.5, 0.9) = 1.0
F(0.5, 0.7) = 1.0
F(0.5, 0.4) = 0.833333
F(0.3, 0.9) = 1.0
F(0.3, 0.7) = 1.0
F(0.3, 0.4) = 1.0
The first set of results make the most sense. First layer has the most influence because it has an angle that is the closes to the given vertex normal angle. On the second set and third set its not clear what is going on. Well it becomes clear after knowing what happens next: The results of this formula are set up so that the result from the next layer down the pipeline (with a larger angle) is always subtracted from the current one. An exception is made for the last layer of course. Applying this knowledge, the results from the example actually are:
F(0.9, 0.9) = 0.666667
F(0.9, 0.7) = 0.166667
F(0.9, 0.4) = 0.166667
F(0.5, 0.9) = 0.0
F(0.5, 0.7) = 0.166667
F(0.5, 0.4) = 0.8333333
F(0.3, 0.9) = 0.0
F(0.3, 0.7) = 0.0
F(0.3, 0.4) = 1.0
We can now appreciate the true intent of the formula engineered by the author: Make the layer with the angle closest to the vertex normal angle influence the most but at the same time soften this influence by subtracting influence of neighboring layers.
Before moving on to the next step consider what happens to a vertex with a normal of 1 (completely flat terrain). This is a special case as the formula in this case produces
F(1.0, 0.9) = 0.0
F(1.0, 0.7) = 0.0
F(1.0, 0.4) = 0.0
Doing the subtraction of the next layer in this case doesn't change anything. What this means is that layers that are blended based on an angle have no influence on pixels belonging to flat terrain. In other words, only the Sand Layer or the Snow layer could have any influence on a pixel like this.
I should mention that so far in my discussion of the angle blend formula I skipped over one component for simplification sake: the power node component. Right before subtracting the result from the result of the next layer down the pipeline the formula in the shader actually performs a Power(result, border of Layer). Where border of layer is the exponent and is an input parameter specifying the blurriness of the given layer. Because result at this point is a decimal number, elevating it to any power only makes the decimal smaller and this offers yet another way to tweak the influence of each layer other than its specified angle.
The results of the angle dependent layers explained above are not used directly as the alpha inputs driving the cascaded lerp nodes. Before they are used there they are modulated (multiplied) by the macro macro variation texture mentioned earlier in order to provide another visual cue of variation between angle dependent layers and avoid banding artifacts.
Finally the result of the last lerp node in the cascade setup of daisy chained lerp nodes is multiplied by a final base color input parameter (yet another way to tweak things) and sent to the detail texture node as described earlier.
Each layer's normal map is blended together in the exact same fashion as the layer's base color explained above. They too are linearly interpolated using a cascade of daisy chained lerp nodes each one driven by the influence a layer has on them, be it height base as in the Sand and Snow layer case or be it angle base as in Layer 01 - 05 case. All the texture maps are connected to the lerp nodes without modification, the only exception being the normal map for Layer 05 which is blended with another version of itself that uses a larger UV scaling. The blending is achieved using a BlendAngleCorrectedNormals node. The result of the last lerp node in the cascade of daisy chained lerp node is then optionally blended with the sediment layer normal map before is sent to the detail texture as explained earlier.
Because in PBS (physically based shader) roughness of 0 is equivalent to a mirror and roughness of 1 is equivalent to rock, the material is set up so that the snow layer has the least roughness while the flat terrain has the most. The terrain with steep inclination like the sides of mountain peaks are set up to have a roughness in between assuming that wind erosion has been at play. Therefore, the final influence results of Layer 04 and 05, the layers with the steeper angles in degrees, are added together and modulated (multiplied) by an input parameter called 'Roughness multiply'. Next this result is added to the result of taking the final influence value of the snow layer and modulating it with an input parameter called 'Roughness Snow multiply'. The idea here being that cliff sides that are snowy should be especially less rough and more mirror like due to freezing effects. Because so far in this result we have being adding together the modulated influences of the last three layers: Snow, Layer 04 and Layer 05 we'd like to translate a high result value to a low roughness value and vice versa, a (1-x) node does the trick here. The overall idea being that snowy cliffs should be the least rough. But before plugging this value to the roughness input of the PBS material an extra layer of customization/tweaking is added by passing the result though a power node where the exponent input is another input parameter this time called 'Roughness'.
Specular follows the exact same ideas described in the Roughness section. Basically the specular is high for snowy cliffs and low for flat surfaces. The only difference to the roughness logic is that this time there is no need for the (1-x) node because a high result value correlates with a high desired secularity. The other difference being that for some reason the author didn't deem necessary to add another layer of customization and the end by passing the result though a power node like it was done in the roughness logic.
Metallic follows the Specular logic described above very closely. The difference here being that the calculated result is further processed by adding to it the difference resulting from subtracting the influence of the last layer from the influence of the snow layer. This result is then modulated by another input parameter called "Metallic Multiply 2". Finally this result is clamped against [0,1] range. Because this "Metallic Multiply 2" is always a negative number this tells me that the only time the clamp node will produce anything other than zero is when the result right before being modulated by "Metallic Multiply 2" is negative. Furthermore, this will only happen when the difference from subtracting the influence of the last layer from the snow layer is negative and large. Putting all together, including the fact that "Metallic Multiply 1" is always zero, I believe this means the metallic is only turned on for snowy cliffs.