Create a Kuwahara filter that applies to TextureSamples rather than scene textures

I have followed a tutorial to make a directional kuwahara filter. But rather than the kuwuhara filter to apply as a post process, I want it to apply it specific objects, i.e. apply the filter to 2D textures.

This is the code that I followed:
float3 mean[4] = {
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0}
};

float3 sigma[4] = {
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0}
};

float2 offsets[4] = {{-RADIUS.x, -RADIUS.y}, {-RADIUS.x,0}, {0,-RADIUS.y}, {0,0}};

float2 pos;
float3 col;

float gradientX = 0;
float gradientY = 0;

float sobelX[9] = {-1, -2, -1, 0, 0, 0, 1, 2, 1};
float sobelY[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1};

int index = 0;

float2 texelSize = 1.0/VIEWSIZE;

for(int x = -1; x <= 1; x++)
{
for(int y = -1; y <= 1; y++)
{
if(index == 4)
{
index++;
continue;
}
float2 offset = float2(x, y) * texelSize;
float3 pxCol = (UV + offset, 14, false).xyz;
float pxLum = dot(pxCol, float3(0.2126, 0.7152, 0.0722));

	gradientX += pxLum * sobelX[index];
	gradientY += pxLum * sobelY[index];

	index++;
}

}

float angle = 0;
if(abs(gradientX) > 0.001)
{
angle = atan(gradientY/gradientX);
}

float s = sin(angle);
float c = cos (angle);

for(int i=0; i<4;i++)
{
for(int j=0; j<=RADIUS.x;j++)
{
for(int k=0; k<=RADIUS.y; k++)
{
pos = float2 (j,k) + offsets[i];
float2 offs = pos * texelSize;
offs = float2(offs.x * c - offs.y * s, offs.x * s + offs.y * c);
float2 uvpos = UV + offs;
col = SceneTextureLookup(uvpos, 14, false);

		mean[i] += col;
		sigma[i] += col * col;
	}
}

}

float n = (RADIUS.x+1)*(RADIUS.y+1);
float sigma_f;

float min = 1;

for(int i=0; i<4; i++)
{
mean[i] /= n;
sigma [i] = abs(sigma[i]/n - mean[i] * mean [i]);
sigma_f = sigma[i].r + sigma[i].g + sigma[i].b;

if(sigma_f < min)
{
	min = sigma_f;
	col = mean[i];
}

}

return col;

This should work, tested on 5.0:

Code in the custom function node I named Texture.

return Texture2DSample(Tex, TexSampler, UV);

To make the Kuwahara work, replace:
col = SceneTextureLookup(uvpos, 14, false); with col = Texture2DSample(Tex, TexSampler, uvpos);

Hi Elias. Thanks for this but I can’t get it working when I connect to the Kuwahara. I get this:


Is there any way you can tell me what I’m doing wrong? I know nothing of coding…

Don’t worry. I got it.

Hello Cleveland

I’m having the same issue as you how did you manage to fix it ?

How did you manage to solve it?
I take this opportunity to wish you a happy new year

I fixed the code using chat GPT, if it anyone is still interested

// Definition of parameters and variables
float3 mean[4] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
float3 sigma[4] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
float2 offsets[4] = {{-RADIUS.x, -RADIUS.y}, {-RADIUS.x, 0}, {0, -RADIUS.y}, {0, 0}};
float2 texelSize = 1.0 / VIEWSIZE;
float gradientX = 0, gradientY = 0;
int index = 0;

// Definition of Sobel filters for gradient calculation
float sobelX[9] = {-1, -2, -1, 0, 0, 0, 1, 2, 1};
float sobelY[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1};

// Gradient calculation with Sobel filter
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
if (index == 4) {
index++;
continue;
}
float2 offset = float2(x, y) * texelSize;
float3 pxCol = Texture2DSample(Tex, TexSampler, UV + offset).xyz;
float pxLum = dot(pxCol, float3(0.2126, 0.7152, 0.0722));
gradientX += pxLum * sobelX[index];
gradientY += pxLum * sobelY[index];
index++;
}
}

// Determining the gradient angle
float angle = 0;
if (abs(gradientX) > 0.001) {
angle = atan(gradientY / gradientX);
}

float s = sin(angle);
float c = cos(angle);

// Changing the name of the outer index to avoid conflict
for (int k = 0; k < 4; k++) // Changing ‘j’ to ‘k’ in the outer loop
{
for (int i = 0; i <= RADIUS.x; i++) // Using ‘i’ for the inner loop
{
for (int j = 0; j <= RADIUS.y; j++) // Using ‘j’ for the innermost loop
{
float2 pos = float2(i, j) + offsets[k];
float2 offs = pos * texelSize;
offs = float2(offs.x * c - offs.y * s, offs.x * s + offs.y * c); // Applying rotation
float2 uvpos = UV + offs;
float3 col = Texture2DSample(Tex, TexSampler, uvpos).xyz;
mean[k] += col;
sigma[k] += col * col;
}
}
}

// Calculating the mean and variance for each quadrant
float n = (RADIUS.x + 1) * (RADIUS.y + 1);
for (int k = 0; k < 4; k++) {
mean[k] /= n;
sigma[k] = abs(sigma[k] / n - mean[k] * mean[k]);
}

// Finding the quadrant with the lowest variance
float minSigma = 1e10;
int bestIndex = 0;
for (int k = 0; k < 4; k++) {
float sigma_f = sigma[k].r + sigma[k].g + sigma[k].b;
if (sigma_f < minSigma) {
minSigma = sigma_f;
bestIndex = k;
}
}

// Replacing the pixel color with the mean of the region with the lowest variance
return mean[bestIndex]; // Returning the mean color of the region with the lowest variance