Here's a quick stab at how to convert your shader code to a custom function node we can apply in a Shader Graph.
First, we'll make a new text file to hold the shader code. I called mine "shaderGraphArray.cginc"
const static int maxLayerCount = 8;
const static float epsilon = 1E-4;
int layerCount;
float3 baseColours[maxLayerCount];
float baseStartHeights[maxLayerCount];
float baseBlends[maxLayerCount];
float baseColourStrength[maxLayerCount];
float baseTextureScales[maxLayerCount];
float inverseLerp(float a, float b, float value) {
return saturate((value-a)/(b-a));
}
float3 triplanar(float3 worldPos, float scale, float3 blendAxes, Texture2DArray textures, SamplerState ss, int textureIndex) {
float3 scaledWorldPos = worldPos / scale;
float3 xProjection = SAMPLE_TEXTURE2D_ARRAY(textures, ss, float2(scaledWorldPos.y, scaledWorldPos.z), textureIndex) * blendAxes.x;
float3 yProjection = SAMPLE_TEXTURE2D_ARRAY(textures, ss, float2(scaledWorldPos.x, scaledWorldPos.z), textureIndex) * blendAxes.y;
float3 zProjection = SAMPLE_TEXTURE2D_ARRAY(textures, ss, float2(scaledWorldPos.x, scaledWorldPos.y), textureIndex) * blendAxes.z;
return xProjection + yProjection + zProjection;
}
void layer_terrain_float(float3 worldPos, float heightPercent, float3 worldNormal, Texture2DArray textures, SamplerState ss, int layerCount, out float3 albedo) {
float3 blendAxes = abs(worldNormal);
blendAxes /= blendAxes.x + blendAxes.y + blendAxes.z;
albedo = 0.0f;
for (int i = 0; i < layerCount; i ++) {
float drawStrength = inverseLerp(-baseBlends[i]/2 - epsilon, baseBlends[i]/2, heightPercent - baseStartHeights[i]);
float3 baseColour = baseColours[i] * baseColourStrength[i];
float3 textureColour = triplanar(worldPos, baseTextureScales[i], blendAxes, textures, ss, i) * (1-baseColourStrength[i]);
albedo = albedo * (1-drawStrength) + (baseColour+textureColour) * drawStrength;
}
}
Things to note here:
I refactored the main workhorse of iterating through the layers into a void function that takes all its inputs as arguments and puts its output into an out argument.
I changed the texture-sampling macros from the old, pre-scriptable-render-pipeline UNITY_SAMPLE_TEX2DARRAY to the new D3D11+ style SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index). Based on this thread, I was able to find a list of all these macros here.
These macros now want a sampler state, so I included that as another argument to pass down.
The rest should be a pretty straightforward conversion.
Then I called this custom function from a shader graph as shown here:
