Files
KopMap/Assets/NatureManufacture Assets/WorldStreamer/Scritps/Shaders/PaintHeight.shader
2025-09-02 18:55:19 +08:00

508 lines
17 KiB
GLSL

Shader "Hidden/NatureManufacture Shaders/PaintHeight"
{
Properties
{
_MainTex ("Texture", any) = "" {}
}
SubShader
{
ZTest Always Cull Off ZWrite Off
CGINCLUDE
#define PI 3.1415926538
#include "UnityCG.cginc"
#include "TerrainTool.cginc"
sampler2D _MainTex;
float4 _MainTex_TexelSize; // 1/width, 1/height, width, height
sampler2D _BrushTex;
// r- Angle
// g- Concave
// b- Height
sampler2D _MaskTex;
//r -Angle
//g -Power
//b -Height
sampler2D _ParamsTex;
float4 _BrushParams;
float4 _NoiseParams;
float4 _NoiseParamsSecond;
float4 _ConvexParams;
float4 _MainParams;
#define POWER_MULTIPLIER (_MainParams[0])
#define HEIGHT_MULTIPLIER (_MainParams[1])
#define HEIGHT_POWER (_MainParams[2])
#define BRUSH_STRENGTH (_BrushParams[0])
#define BRUSH_NOISE (_BrushParams[1])
#define BRUSH_STAMPHEIGHT (_BrushParams[2])
#define NOISE_MULTIPLIER (_NoiseParams[0])
#define NOISE_SIZE_X (_NoiseParams[1])
#define NOISE_SIZE_Z (_NoiseParams[2])
#define NOISE_MULTIPLIER_OUTSIDE (_NoiseParams[3])
#define NOISE_MULTIPLIER_POWER (_NoiseParamsSecond[0])
#define CONVEX_STEPS (_ConvexParams[0])
#define CONVEX_STEP_SIZE (_ConvexParams[1])
#define CONVEX_STRENGTH (_ConvexParams[2])
#define CONVEX_WORKING (_ConvexParams[3])
//#define BRUSH_ANGLE (_NoiseParams[3])
struct appdata_t
{
float4 vertex : POSITION;
float2 pcUV : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 pcUV : TEXCOORD0;
};
v2f vert(appdata_t v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.pcUV = v.pcUV;
return o;
}
float AddSub(float base, float blend, float opacity)
{
float oneBlend = 1 - blend;
oneBlend -= 0.5;
float blendHalf = blend - 0.5;
float sub = base - oneBlend;
sub += blendHalf;
sub = saturate(sub);
return lerp(base, sub, opacity);
}
//simple noise
inline float unity_noise_randomValue(float2 uv)
{
return frac(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453);
}
inline float unity_noise_interpolate(float a, float b, float t)
{
return (1.0 - t) * a + (t * b);
}
inline float unity_valueNoise(float2 uv)
{
float2 i = floor(uv);
float2 f = frac(uv);
f = f * f * (3.0 - 2.0 * f);
uv = abs(frac(uv) - 0.5);
float2 c0 = i + float2(0.0, 0.0);
float2 c1 = i + float2(1.0, 0.0);
float2 c2 = i + float2(0.0, 1.0);
float2 c3 = i + float2(1.0, 1.0);
float r0 = unity_noise_randomValue(c0);
float r1 = unity_noise_randomValue(c1);
float r2 = unity_noise_randomValue(c2);
float r3 = unity_noise_randomValue(c3);
float bottomOfGrid = unity_noise_interpolate(r0, r1, f.x);
float topOfGrid = unity_noise_interpolate(r2, r3, f.x);
float t = unity_noise_interpolate(bottomOfGrid, topOfGrid, f.y);
return t;
}
void Unity_SimpleNoise_float(float2 UV, float Scale, out float Out)
{
float t = 0.0;
float freq = pow(2.0, float(0));
float amp = pow(0.5, float(3 - 0));
t += unity_valueNoise(float2(UV.x * Scale / freq, UV.y * Scale / freq)) * amp;
freq = pow(2.0, float(1));
amp = pow(0.5, float(3 - 1));
t += unity_valueNoise(float2(UV.x * Scale / freq, UV.y * Scale / freq)) * amp;
freq = pow(2.0, float(2));
amp = pow(0.5, float(3 - 2));
t += unity_valueNoise(float2(UV.x * Scale / freq, UV.y * Scale / freq)) * amp;
Out = t;
}
//perlin noise
float2 unity_gradientNoise_dir(float2 p)
{
p = p % 289;
float x = (34 * p.x + 1) * p.x % 289 + p.y;
x = (34 * x + 1) * x % 289;
x = frac(x / 41) * 2 - 1;
return normalize(float2(x - floor(x + 0.5), abs(x) - 0.5));
}
float unity_gradientNoise(float2 p)
{
float2 ip = floor(p);
float2 fp = frac(p);
float d00 = dot(unity_gradientNoise_dir(ip), fp);
float d01 = dot(unity_gradientNoise_dir(ip + float2(0, 1)), fp - float2(0, 1));
float d10 = dot(unity_gradientNoise_dir(ip + float2(1, 0)), fp - float2(1, 0));
float d11 = dot(unity_gradientNoise_dir(ip + float2(1, 1)), fp - float2(1, 1));
fp = fp * fp * fp * (fp * (fp * 6 - 15) + 10);
return lerp(lerp(d00, d01, fp.y), lerp(d10, d11, fp.y), fp.x);
}
void Unity_GradientNoise_float(float2 UV, float Scale, out float Out)
{
Out = clamp(unity_gradientNoise(UV * Scale) + 0.5, 0, 1);
}
ENDCG
Pass // 0 copy terrain heightmap
{
Name "Copy Heights"
CGPROGRAM
#pragma vertex vert
#pragma fragment RaiseHeight
float4 RaiseHeight(v2f i) : SV_Target
{
//float2 brushUV = PaintContextUVToBrushUV(i.pcUV);
float2 heightmapUV = PaintContextUVToHeightmapUV(i.pcUV);
// out of bounds multiplier
// float oob = all(saturate(brushUV) == brushUV) ? 1.0f : 0.0f;
float height = UnpackHeightmap(tex2D(_MainTex, heightmapUV));
//float brushShape = oob * UnpackHeightmap(tex2D(_BrushTex, brushUV));
return PackHeightmap(clamp(height, 0, 0.5));
}
ENDCG
}
Pass // 1 Carve terrain
{
Name "Carve terrain"
CGPROGRAM
#pragma vertex vert
#pragma fragment StampHeight
float4 StampHeight(v2f i) : SV_Target
{
float2 brushUV = PaintContextUVToBrushUV(i.pcUV);
float2 heightmapUV = PaintContextUVToHeightmapUV(i.pcUV);
// out of bounds multiplier
float oob = all(saturate(brushUV) == brushUV) ? 1.0f : 0.0f;
float height = UnpackHeightmap(tex2D(_MainTex, heightmapUV));
//float brushShape = oob * UnpackHeightmap(tex2D(_BrushTex, brushUV));
float4 brush = tex2D(_BrushTex, brushUV);
float brushShape = oob * brush.r * 0.5;
float brushBlend = oob * brush.a;
float distance = brush.g;
distance = 1 - distance;
distance = distance * 0.5;
float brushChange = lerp(0.5 - distance, distance + 0.5, brush.b);
brushChange = tex2D(_ParamsTex, brushChange).r * 2 - 1;
float x = i.pcUV.x;
float z = i.pcUV.y;
float noise = 1;
float noiseMultiplier = lerp(NOISE_MULTIPLIER_OUTSIDE, NOISE_MULTIPLIER, brush.b);
//Unity_SimpleNoise_float(float2(x * NOISE_SIZE_X, z * NOISE_SIZE_Z), 1, noise);
Unity_GradientNoise_float(float2(x * NOISE_SIZE_X, z * NOISE_SIZE_Z), 1, noise);
if (noiseMultiplier < 0)
noise = 1 - noise;
noise = pow(noise,NOISE_MULTIPLIER_POWER) * abs(noiseMultiplier);
if (BRUSH_NOISE == 0)
noise = 1;
float brushHeight = brushShape + brushChange * 0.5 + brushChange * noise;
//sin ((x+0.5)*\pi )) +1)*0.5
brushBlend = 1 - (sin((brushBlend + 0.5) * PI) + 1) * 0.5;
float brushStrength = lerp(BRUSH_STRENGTH, 1, brush.b);
float targetHeight = lerp(height, brushHeight, pow(brushBlend, brushStrength));
targetHeight = clamp(targetHeight, 0.0, 0.5); // Keep in valid range (0..0.5f)
height = targetHeight;
return PackHeightmap(height);
//return PackHeightmap(brush.b*0.5);
}
ENDCG
}
Pass // 2 Get angle
{
Name "Get angle"
CGPROGRAM
#pragma vertex vert
#pragma fragment SetHeight
float3 NormalFromTexture(float2 UV, float Offset, float Strength)
{
//Offset = pow(Offset, 3) * 0.1;
float2 offsetU = float2(UV.x + Offset, UV.y);
float2 offsetV = float2(UV.x, UV.y + Offset);
float normalSample = UnpackHeightmap(tex2D(_MainTex, UV)); //Texture.Sample(Sampler, UV);
float uSample = UnpackHeightmap(tex2D(_MainTex, offsetU)); //Texture.Sample(Sampler, offsetU);
float vSample = UnpackHeightmap(tex2D(_MainTex, offsetV)); //Texture.Sample(Sampler, offsetV);
float3 va = float3(1, 0, (uSample - normalSample) * Strength);
float3 vb = float3(0, 1, (vSample - normalSample) * Strength);
return normalize(cross(va, vb));
}
float4 SetHeight(v2f i) : SV_Target
{
float2 heightmapUV = PaintContextUVToHeightmapUV(i.pcUV);
float offset = _MainTex_TexelSize.x;
float4 normal = 1;
normal.xyz = NormalFromTexture(heightmapUV, offset, 1000);
// normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
return normal;
}
ENDCG
}
Pass // 3 Mask Generator
{
Name "Mask Generator"
CGPROGRAM
#pragma vertex vert
#pragma fragment GetMask
float3 NormalFromTexture(float2 UV, float Offset, float Strength)
{
//Offset = pow(Offset, 3) * 0.1;
float2 offsetU = float2(UV.x + Offset, UV.y);
float2 offsetV = float2(UV.x, UV.y + Offset);
float normalSample = UnpackHeightmap(tex2D(_MainTex, UV)); //Texture.Sample(Sampler, UV);
float uSample = UnpackHeightmap(tex2D(_MainTex, offsetU)); //Texture.Sample(Sampler, offsetU);
float vSample = UnpackHeightmap(tex2D(_MainTex, offsetV)); //Texture.Sample(Sampler, offsetV);
float3 va = float3(1, 0, (uSample - normalSample) * Strength);
float3 vb = float3(0, 1, (vSample - normalSample) * Strength);
float3 normal = normalize(cross(va, vb));
return normal;
}
float CavityFromTexture(float2 UV, float Offset, float Strength)
{
float height = UnpackHeightmap(tex2D(_MainTex, UV));
Offset = Offset * CONVEX_STEP_SIZE;
half4 blur = 0.0;
float remaining = 1.0;
float coef = 1.0;
float fI = 0;
for (int j = 0; j < CONVEX_STEPS; j++)
{
fI++;
coef *= 0.32;
blur += tex2D(_MainTex, float2(UV.x, UV.y - fI * Offset)) * coef;
blur += tex2D(_MainTex, float2(UV.x - fI * Offset, UV.y)) * coef;
blur += tex2D(_MainTex, float2(UV.x + fI * Offset, UV.y)) * coef;
blur += tex2D(_MainTex, float2(UV.x, UV.y + fI * Offset)) * coef;
blur += tex2D(_MainTex, float2(UV.x + fI * Offset, UV.y + fI * Offset)) * coef;
blur += tex2D(_MainTex, float2(UV.x - fI * Offset, UV.y + fI * Offset)) * coef;
blur += tex2D(_MainTex, float2(UV.x + fI * Offset, UV.y - fI * Offset)) * coef;
blur += tex2D(_MainTex, float2(UV.x - fI * Offset, UV.y - fI * Offset)) * coef;
remaining -= 8 * coef;
}
blur += tex2D(_MainTex, float2(UV.x, UV.y)) * remaining;
//float concave = (height - texcol) * Strength * CONVEX_STRENGTH;
blur = 1 - blur;
float concave = AddSub(height, blur, 0.5);
concave = AddSub(concave, concave, Strength * CONVEX_STRENGTH);
if (CONVEX_WORKING == 0)
concave = 1;
if (CONVEX_WORKING == 1)
{
concave -= 0.5;
}
if (CONVEX_WORKING == 2)
{
concave += 0.5;
concave = 1 - concave;
}
return concave;
}
float CavityFromTextureNormal(float2 heightmapUV, float Offset, float Strength)
{
float3 normal = NormalFromTexture(heightmapUV, Offset, BRUSH_STAMPHEIGHT);
float normalR = NormalFromTexture(heightmapUV + float2(Offset, 0), Offset, BRUSH_STAMPHEIGHT).r;
float normalG = NormalFromTexture(heightmapUV + float2(0, Offset), Offset, BRUSH_STAMPHEIGHT).g;
normalR = normal.r - normalR;
normalR = 0.5 - normalR;
normalG = normal.g - normalG;
normalG = 0.5 - normalG;
float concave = lerp(normalR, normalG, 0.5);
concave = AddSub(concave, concave, CONVEX_STRENGTH);
return concave;
}
float4 GetMask(v2f i) : SV_Target
{
float2 heightmapUV = PaintContextUVToHeightmapUV(i.pcUV);
float height = UnpackHeightmap(tex2D(_MainTex, heightmapUV));
float offset = _MainTex_TexelSize.x;
float3 normal = NormalFromTexture(heightmapUV, offset, BRUSH_STAMPHEIGHT);
float angle = acos(dot(normal, float3(0, 0, 1))) / (PI * 0.5);
float concave = CavityFromTexture(heightmapUV, offset, BRUSH_STAMPHEIGHT);
float concave2 = CavityFromTextureNormal(heightmapUV, offset, BRUSH_STAMPHEIGHT);
float4 mask = 0;
mask.r = angle;
mask.g = concave;
mask.b = height;
mask.a = concave2;
// normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
return mask;
}
ENDCG
}
Pass // 4 paint splat alphamap
{
Name "Paint Texture"
CGPROGRAM
#pragma vertex vert
#pragma fragment PaintSplatAlphamap
float Angle(float3 from, float3 to)
{
float num = sqrt(dot(from, from) * dot(to, to));
return num < 1.0000000036274937E-15 ? 0.0f : acos(clamp(dot(from, to) / num, -1, 1)) * 57.29578;
}
float4 PaintSplatAlphamap(v2f i) : SV_Target
{
float2 brushUV = PaintContextUVToBrushUV(i.pcUV);
// out of bounds multiplier
float oob = all(saturate(brushUV) == brushUV) ? 1.0 : 0.0;
float4 brush = oob * tex2D(_BrushTex, brushUV);
// float brushStrength = BRUSH_STRENGTH * brush.a;
float distance = brush.g;
distance = 1 - distance;
distance = distance * 0.5;
float brushStrength = lerp(0.5 - distance, distance + 0.5, brush.b);
brushStrength = tex2D(_ParamsTex, brushStrength).g * POWER_MULTIPLIER * brush.a;
float x = i.pcUV.x;
float z = i.pcUV.y;
float noise = 1;
float noiseMultiplier = lerp(NOISE_MULTIPLIER_OUTSIDE, NOISE_MULTIPLIER, brush.b);
Unity_GradientNoise_float(float2(x * NOISE_SIZE_X, z * NOISE_SIZE_Z), 1, noise);
if (noiseMultiplier < 0)
noise = 1 - noise;
noise = pow(noise,NOISE_MULTIPLIER_POWER) * abs(noiseMultiplier); // * 2 - NOISE_MULTIPLIER;
if (BRUSH_NOISE == 0)
noise = 1;
float4 mask = (tex2D(_MaskTex, i.pcUV));
float angle = mask.r;
angle = tex2D(_ParamsTex, angle).r;
float concave = mask.g;
float heightMap = tex2D(_ParamsTex, mask.b).b;
heightMap = pow(heightMap,HEIGHT_POWER) * HEIGHT_MULTIPLIER;
float alphaMap = tex2D(_MainTex, i.pcUV).r;
return alphaMap + brushStrength * noise * angle * concave * heightMap;
}
ENDCG
}
}
Fallback Off
}