I need some help/advice on how to blend textures in a shader
I have been working on a shader to make all my caves in my 3d generated terrains. So far I have gotten it working that the top is being smoothed from stone to grass, just the under side I have no clue how to fix.
I have been working on it for a few days now and I am completely clueless on what to do next.
https://www.screencast.com/t/0AOdymtNqAyy Here is an image, the top is being smoothed but the underside isn't yet.
Here the shader I use:
Shader "Custom/TerrainFragment" {
SubShader{
Tags { "RenderType" = "Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Standard fullforwardshadows
#pragma target 3.0
const static int maxLayerCount = 8;
const static float epsilon = 1E-4;
int layerCount;
float3 baseColors[maxLayerCount];
float baseStartHeights[maxLayerCount];
float baseBlends[maxLayerCount];
float baseColorStrength[maxLayerCount];
float baseTextureScales[maxLayerCount];
int tileSize;
const static int maxTileSize = 32;
float maxHeightMap[1024]; // maxTileSize * maxTileSize
UNITY_DECLARE_TEX2DARRAY(baseTextures);
struct Input {
float3 worldPos;
float3 worldNormal;
};
float inverseLerp(float a, float b, float value) {
return saturate((value - a) / (b - a));
}
float3 triplanar(float3 worldPos, float scale, float3 blendAxes, int textureIndex) {
float3 scaledWorldPos = worldPos / scale;
float3 xProjection = UNITY_SAMPLE_TEX2DARRAY(baseTextures, float3(scaledWorldPos.y, scaledWorldPos.z, textureIndex)) * blendAxes.x;
float3 yProjection = UNITY_SAMPLE_TEX2DARRAY(baseTextures, float3(scaledWorldPos.x, scaledWorldPos.z, textureIndex)) * blendAxes.y;
float3 zProjection = UNITY_SAMPLE_TEX2DARRAY(baseTextures, float3(scaledWorldPos.x, scaledWorldPos.y, textureIndex)) * blendAxes.z;
return xProjection + yProjection + zProjection;
}
void surf(Input IN, inout SurfaceOutputStandard o) {
float posX = abs(IN.worldPos.x) % tileSize;
float posZ = abs(IN.worldPos.z) % tileSize;
float index = int(posX) + (int(posZ) * tileSize);
float maxHeight = maxHeightMap[index];
float heightPercent = inverseLerp(0,maxHeight, IN.worldPos.y);
float3 blendAxes = abs(IN.worldNormal);
blendAxes /= blendAxes.x + blendAxes.y + blendAxes.z;
for (int i = 0; i < layerCount; i++) {
float drawStrength = inverseLerp(-baseBlends[i] / 2 - epsilon, baseBlends[i] / 2, heightPercent - baseStartHeights[i]);
float3 baseColor = baseColors[i] * baseColorStrength[i];
float3 textureColor = triplanar(IN.worldPos, baseTextureScales[i], blendAxes, i) * (1 - baseColorStrength[i]);
o.Albedo = o.Albedo * (1 - drawStrength) + (baseColor + textureColor) * drawStrength;
}
}
ENDCG
}
FallBack "Diffuse"
}
this is how the settings i use that is being applied on the shader looks: https://www.screencast.com/t/DqmFrrBgJ
Any help is appreciated
Answer by craysboy42 · May 30, 2019 at 10:14 AM
With some help from the unity discord I fixed the shader, removed the heightmap and implemented the perlin noise library i used into the shader.
Here is the shader, I hope someone else can use it as well :)
Shader "Custom/TerrainFragment" {
Properties{
}
SubShader{
Tags { "RenderType" = "Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
const static int maxLayerCount = 8;
const static float epsilon = 1E-4;
int layerCount;
float3 baseColors[maxLayerCount];
float baseStartHeights[maxLayerCount];
float baseBlends[maxLayerCount];
float baseColorStrength[maxLayerCount];
float baseTextureScales[maxLayerCount];
int seed;
int tileSize;
int maxTileHeight;
int minTileHeight;
int heightMapCount;
float heightMapScales[maxLayerCount];
float weightScales[maxLayerCount];
UNITY_DECLARE_TEX2DARRAY(baseTextures);
float perm[257];
struct Input {
float3 worldPos;
float3 worldNormal;
};
float Fade(float t)
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
float Lerp(float t, float a, float b)
{
return a + t * (b - a);
}
float Grad(uint hash, float x, float y)
{
return ((hash & 1) == 0 ? x : -x) + ((hash & 2) == 0 ? y : -y);
}
float noise(float x, float y)
{
uint X = (uint)floor(x) & 0xff;
uint Y = (uint)floor(y) & 0xff;
x -= floor(x);
y -= floor(y);
float u = Fade(x);
float v = Fade(y);
uint A = (uint)(perm[X ] + Y) & 0xff;
uint B = (uint)(perm[X+1] + Y) & 0xff;
return Lerp(v, Lerp(u, Grad(perm[A ], x, y ), Grad(perm[B ], x-1, y )),
Lerp(u, Grad(perm[A+1], x, y-1), Grad(perm[B+1], x-1, y-1)));
}
float inverseLerp(float a, float b, float value) {
return saturate((value - a) / (b - a));
}
float3 triplanar(float3 worldPos, float scale, float3 blendAxes, int textureIndex) {
float3 scaledWorldPos = worldPos / scale;
float3 xProjection = UNITY_SAMPLE_TEX2DARRAY(baseTextures, float3(scaledWorldPos.y, scaledWorldPos.z, textureIndex)) * blendAxes.x;
float3 yProjection = UNITY_SAMPLE_TEX2DARRAY(baseTextures, float3(scaledWorldPos.x, scaledWorldPos.z, textureIndex)) * blendAxes.y;
float3 zProjection = UNITY_SAMPLE_TEX2DARRAY(baseTextures, float3(scaledWorldPos.x, scaledWorldPos.y, textureIndex)) * blendAxes.z;
return xProjection + yProjection + zProjection;
}
void surf(Input IN, inout SurfaceOutputStandard o) {
float maxHeightPercentage = 0;
for (int i = 0; i < heightMapCount; i++) {
float scale = heightMapScales[i];
float xPos = (seed + IN.worldPos.x) / tileSize * scale;
float zPos = (seed + IN.worldPos.z) / tileSize * scale;
maxHeightPercentage += (noise(xPos, zPos) + 0.6) * weightScales[i];
}
float maxHeight = ((maxTileHeight - minTileHeight) * maxHeightPercentage) + minTileHeight - 1;
float heightPercent = inverseLerp(0,maxHeight, IN.worldPos.y);
float3 blendAxes = abs(IN.worldNormal);
blendAxes /= blendAxes.x + blendAxes.y + blendAxes.z;
for (int li = 0; li < layerCount; li++) {
float drawStrength = inverseLerp(-(baseBlends[li] / 2) - epsilon, baseBlends[li] / 2, heightPercent - baseStartHeights[li]);
float3 baseColor = baseColors[li] * baseColorStrength[li];
float3 textureColor = triplanar(IN.worldPos, baseTextureScales[li], blendAxes, li) * (1 - baseColorStrength[li]);
o.Albedo = o.Albedo * (1 - drawStrength) + (baseColor + textureColor) * drawStrength;
}
}
ENDCG
}
FallBack "Diffuse"
}
Your answer
![](https://koobas.hobune.stream/wayback/20220612201750im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Fixing terrain tiling 1 Answer
Unity Terrain as a instantiated tile 0 Answers
Sampling a noise texture in a shader results in a low resolution output 1 Answer
How do I set a Render Texture as the HeightMap for a Terrain? 0 Answers
DetailPrototype becomes white quads instead of texture on build, but works in editor 2 Answers