Files
2026-07-13 13:13:17 +08:00

194 lines
5.2 KiB
HLSL

#include "shared/hash-functions.hlsl"
#include "shared/bias-functions.hlsl"
cbuffer ParamConstants : register(b0)
{
float4 GapColor;
float SplitPosition;
float SplitVariation;
float SubdivisionThreshold;
float RandomPhase;
float Padding;
float Feather;
float2 ScrollOffset;
float2 ScrollGainAndBias;
float DirectionBias;
float TextureFx;
float IsTextureValid;
}
#define COLORMODE_DIVISIONS 0
#define COLORMODE_RANDOM 1
// cbuffer Time : register(b1)
// {
// }
cbuffer Resolution : register(b2)
{
float TargetWidth;
float TargetHeight;
}
cbuffer IntParams : register(b4)
{
int UseApectForSplit;
int UseRGSSMultiSampling;
int MaxSubdivisions;
int GradientMode;
int ColorMode;
int RandomSeed;
}
struct vsOutput
{
float4 position : SV_POSITION;
float2 texCoord : TEXCOORD;
};
Texture2D<float4> Image : register(t0);
Texture2D<float4> ImageB : register(t1);
sampler texSampler : register(s0);
sampler clampedSampler : register(s1);
#define fmod(x, y) ((x) - (y) * floor((x) / (y)))
static const float stepOffset = 0.25;
float PhaseHash(uint i)
{
uint pointU = i * _PRIME0;
float particlePhaseOffset = hash11u(pointU);
float phase = abs(particlePhaseOffset + RandomPhase);
int phaseIndex = (int)phase + pointU;
float t = fmod(phase, 1);
t = smoothstep(0, 1, t);
return lerp(hash11u(phaseIndex),
hash11u(phaseIndex + 1),
t);
}
float4 ComputeSubdivision(float2 uv)
{
int steps = (int)clamp(MaxSubdivisions, 1, 30);
int mainSeed = RandomSeed;
int step;
float aspectRatio = TargetWidth / TargetHeight;
float2 size = 1;
float2 uvInCell = uv;
// float hash2 = 0.5;
float phaseHashForCell = (PhaseHash(mainSeed) - 0.5) * SplitVariation + SplitPosition;
int seedInCell = RandomSeed;
uint lastDirection = 0;
[loop] for (step = 0; step < steps; ++step)
{
float aspect = UseApectForSplit == 1 ? size.x / size.y : 1;
if (hash11u(seedInCell) * 2 + DirectionBias < aspect)
{
if (uvInCell.x < phaseHashForCell)
{
uvInCell.x /= phaseHashForCell;
size.x *= phaseHashForCell;
mainSeed += (int)(phaseHashForCell + 2123u);
seedInCell *= 2;
}
else
{
uvInCell.x = (uvInCell.x - phaseHashForCell) / (1 - phaseHashForCell);
size.x *= (1 - phaseHashForCell);
mainSeed = (int)(mainSeed + 213u) % 1251u;
seedInCell *= 3;
}
lastDirection = 0;
}
else
{
if (uvInCell.y < phaseHashForCell)
{
uvInCell.y /= phaseHashForCell;
size.y *= phaseHashForCell;
mainSeed = (int)(mainSeed + _PRIME2) % _PRIME1;
seedInCell *= 5;
}
else
{
uvInCell.y = (uvInCell.y - phaseHashForCell) / (1 - phaseHashForCell);
size.y *= (1 - phaseHashForCell);
mainSeed = (int)(mainSeed + _PRIME1) % _PRIME2;
seedInCell *= 7;
}
lastDirection = 1;
}
float hash = hash11u(seedInCell);
uvInCell = fmod(uvInCell + ScrollOffset * float2(-1, 1) * ApplyGainAndBias(hash, ScrollGainAndBias), 1);
phaseHashForCell = (PhaseHash(mainSeed) - 0.5) * SplitVariation + SplitPosition;
float4 extra = Image.Sample(texSampler, uv - uvInCell * size + size / 2);
float extraGray = (extra.r + extra.g + extra.b) / 3 * extra.a * TextureFx;
if (hash <= SubdivisionThreshold - extraGray)
break;
}
// float splitF = ColorMode == 0 ? hash11u(mainSeed) : step / (float)steps;
float gradientF = GradientMode ? step / (float)steps : hash11u(mainSeed);
float4 gradientColor = ImageB.SampleLevel(clampedSampler, float2(gradientF, 0.5), 0);
float2 dd = (uvInCell - 0.5) * size;
float2 d4 = (size - abs(dd * 2)) * float2(aspectRatio, 1);
float d5 = min(d4.x, d4.y);
float sGap = smoothstep(Padding - Feather, Padding + Feather, d5);
float2 imageUv = uv - uvInCell * size + size / 2;
float4 imageColor = lerp(Image.Sample(texSampler, imageUv), 1, ColorMode == 1) * gradientColor;
return lerp(GapColor, imageColor, sGap);
}
float4 psMain(vsOutput input) : SV_TARGET
{
// return float4(ColorMode, 0, 0, 1);
// float width, height;
// Image.GetDimensions(width, height);
// float imageAspect = width/height;
float2 uv = input.texCoord;
if (UseRGSSMultiSampling > 0.5)
{
// 4x rotated grid
float4 offsets[2];
offsets[0] = float4(-0.375, 0.125, 0.125, 0.375);
offsets[1] = float4(0.375, -0.125, -0.125, -0.375);
float2 sxy = float2(TargetWidth, TargetHeight);
return (ComputeSubdivision(uv + offsets[0].xy / sxy) +
ComputeSubdivision(uv + offsets[0].zw / sxy) +
ComputeSubdivision(uv + offsets[1].xy / sxy) +
ComputeSubdivision(uv + offsets[1].zw / sxy)) /
4;
}
else
{
return ComputeSubdivision(uv);
}
}