Without custom code, this would be very cumbersome. The material editor doesn’t offer an easy way to do loops, and you need to sample lots of pixels. Here’s a morphological dilation material I made a few months ago. Top one is rectangular, bottom one is circular. Paste this code in the corresponding custom node.

```
\\DilationRect
float2 UVPixSize=1/TextureSize;
float2 PixUV=(floor(UV*TextureSize)+0.5)/TextureSize;
float PixValue=0;
for(int i=int(-DilationPixels.x);i<DilationPixels.x;i++)
{
for(int j=int(-DilationPixels.y);j<DilationPixels.y;j++)
{
PixValue+=Texture2DSampleLevel(MaskTex,MaskTexSampler,float2(PixUV.x+i*UVPixSize.x,PixUV.y+j*UVPixSize.y),0);
}
}
return ceil(clamp(PixValue,0,1));
\\DilationCirc
float2 UVPixSize=1/TextureSize;
float2 PixUV=(floor(UV*TextureSize)+0.5)/TextureSize;
float PixValue=0;
for(int i=int(-DilationPixels);i<DilationPixels;i++)
{
for(int j=int(-DilationPixels);j<DilationPixels;j++)
{
PixValue+=lerp(0,1,sqrt(pow(i,2)+pow(j,2))<DilationPixels)*Texture2DSampleLevel(MaskTex,MaskTexSampler,float2(PixUV.x+i*UVPixSize.x,PixUV.y+j*UVPixSize.y),0);
}
}
```

If you want to combine this with a blur, it gets a little trickier. You could do something like: Create a second variable like PixValue, which adds all pixels in the kernel, but divides by the number of pixels in the kernel to get an average. Then lerp in favor of the second value as the distance((i,j),(0,0))/radius approaches 1.