Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anisotropic Kuwahara Filter #68

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Assets/Examples/Kuwahara.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added Assets/Examples/Kuwahara/Cyberpunk.jpg
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the license of this image?

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
117 changes: 117 additions & 0 deletions Assets/Examples/Kuwahara/Cyberpunk.jpg.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1,445 changes: 1,445 additions & 0 deletions Assets/Examples/Kuwahara/KuwaharaSample.asset

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions Assets/Examples/Kuwahara/KuwaharaSample.asset.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using GraphProcessor;
using UnityEngine;
using UnityEngine.Rendering;

namespace Mixture
{
[System.Serializable][NodeMenuItem("Operators/Anisotropic Kuwahara Filter")]
public class AnisotropicKuwaharaFilter : ComputeShaderNode
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you write a bit of documentation on this node using the [Documentation] attribute?

{
protected override string computeShaderResourcePath => "Mixture/AnisotropicKuwaharaFilter";

public override string name => "Anisotropic Kuwahara Filter";

public override Texture previewTexture => output;
public override bool showDefaultInspector => true;
[Input("Source")] public Texture source;
[Input("TFM")] public Texture tfm;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to avoid using abbreviations in node parameters :)

[Output] public CustomRenderTexture output;
[ShowInInspector] public int passCount = 2;
[ShowInInspector] public int kuwaharaRadius = 5;
[ShowInInspector] public float kuwaharaAlpha = 1.0f;
[ShowInInspector] public int kuwaharaQ = 1;
[ShowInInspector] public float strokeScale = 0.5f;
[ShowInInspector] public bool useZeta;
[ShowInInspector] public float zeta;
[ShowInInspector] public float sharpness = 8;
[ShowInInspector] public float hardness = 8;
[ShowInInspector] public float zeroCrossing = 0.58f;
private RenderTexture inputCopy;

private int kuwaharaComputeKernel;

protected override void Enable()
{
base.Enable();
UpdateTempRenderTexture(ref output);
kuwaharaComputeKernel = computeShader.FindKernel("AnisotropicKuwahara");
}


private void ValidateTempRenderTexture()
{
if (inputCopy == null || inputCopy.width != output.width ||
inputCopy.height != output.height)
{
inputCopy?.Release();
inputCopy = new RenderTexture(output.width, output.height, 0, output.format);
inputCopy.enableRandomWrite = true;
inputCopy.Create();
}
}

protected override void Disable()
{
base.Disable();
inputCopy?.Release();
}

protected override bool ProcessNode(CommandBuffer cmd)
{
if (!base.ProcessNode(cmd) || tfm == null || source == null)
return false;
ValidateTempRenderTexture();
for (int i = 0; i < passCount; i++)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is an acceptable range of value for the pass count? It's to know if it's worth avoiding the copy inside the loop or not.

{
// Copy previous output
cmd.Blit(i == 0 ? source : output, inputCopy);

cmd.SetComputeTextureParam(computeShader, kuwaharaComputeKernel, "_Source", inputCopy);
cmd.SetComputeTextureParam(computeShader, kuwaharaComputeKernel, "_TFM", tfm);
cmd.SetComputeTextureParam(computeShader, kuwaharaComputeKernel, "_Output", output);
cmd.SetComputeIntParam(computeShader, "_KuwaharaRadius", kuwaharaRadius);
cmd.SetComputeFloatParam(computeShader, "_KuwaharaAlpha", kuwaharaAlpha);
cmd.SetComputeFloatParam(computeShader, "_KuwaharaQ", kuwaharaQ);
cmd.SetComputeFloatParam(computeShader, "_StrokeScale", strokeScale);
cmd.SetComputeFloatParam(computeShader, "_Hardness", hardness);
cmd.SetComputeFloatParam(computeShader, "_ZeroCrossing", zeroCrossing);
cmd.SetComputeFloatParam(computeShader, "_Zeta",
useZeta ? zeta : 2.0f / 2.0f / (kuwaharaRadius / 2.0f));
DispatchCompute(cmd, kuwaharaComputeKernel, output.width, output.height, 1);
}

return true;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using GraphProcessor;

namespace Mixture
{
[System.Serializable, NodeMenuItem("Operator/Edge Tengent Flow")]
public class EdgeTengentFlow : FixedShaderNode
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you write a bit of documentation on this node using the [Documentation] attribute?

{
public override string name => "Edge Tengent Flow";
public override string shaderName => "Hidden/Mixture/EdgeTengentFlow";
public override bool displayMaterialInspector => true;
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using GraphProcessor;
using UnityEngine;
using UnityEngine.Rendering;

namespace Mixture
{
[System.Serializable][NodeMenuItem("Operator/Line Integral Convolution")]
public class LineIntegralConvolution : ComputeShaderNode
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here for doc :)

{
protected override string computeShaderResourcePath => "Mixture/LineIntegralConvolution";

public override string name => "Line Integral Convolution";
public override Texture previewTexture => LIC;
[Input("TFM")] public Texture tfm;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

abbreviation

[Input("Noise")] public Texture noise;
[Input("Gaussian Kernel")][SerializeField] private ComputeBuffer gaussianKernel;
[Input("Kernel Radius")][SerializeField] private int kernelRadius;
[Output] public CustomRenderTexture LIC;

private int lic;
protected override void Enable()
{
base.Enable();
lic = computeShader.FindKernel("LIC");
UpdateTempRenderTexture(ref LIC);
}


protected override bool ProcessNode(CommandBuffer cmd)
{
if (!base.ProcessNode(cmd) || tfm == null || noise == null || gaussianKernel == null)
return false;
cmd.SetComputeBufferParam(computeShader, lic, "__Kernel", gaussianKernel);
cmd.SetComputeTextureParam(computeShader, lic, "__TFM", tfm);
cmd.SetComputeTextureParam(computeShader, lic, "__Noise", noise);
cmd.SetComputeTextureParam(computeShader, lic, "_LIC", LIC);
cmd.SetComputeIntParam(computeShader, "__KernelRadius", kernelRadius);

DispatchCompute(cmd, computeShader, lic, tfm.width, tfm.height, 1);
return true;
}
}

}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using UnityEngine;
using GraphProcessor;
using UnityEngine.Rendering;

namespace Mixture
{
[System.Serializable, NodeMenuItem("Utility/Gaussian Kernel")]
public class GaussianKernelNode : MixtureNode
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doc :)

{
[Input] [SerializeField] private int kernelRadius;

[Input] [SerializeField] private float kernelSigma;

[Output] public ComputeBuffer kernelBuffer;
[Output("Kernel Radius")] public int kernelRadiusOutput;

public override string name => "Gaussian Kernel";

public override bool showDefaultInspector => true; // Make the serializable field visible in the node UI.

private int currentRadius;
private float currentSigma;

protected override bool ProcessNode(CommandBuffer cmd)
{
if (!base.ProcessNode(cmd))
return false;

UpdateKernel(kernelRadius, kernelSigma);
kernelRadiusOutput = kernelRadius;
return true;
}

private void UpdateKernel(int newRadius, float newSigma)
{
if (kernelBuffer == null ||
!kernelBuffer.IsValid() ||
!Mathf.Approximately(newRadius, currentRadius) ||
!Mathf.Approximately(newSigma, currentSigma))
{
kernelBuffer?.Dispose();
this.currentRadius = newRadius;
this.currentSigma = newSigma;
kernelBuffer = CreateKernel(newRadius, newSigma);
}
}

private static ComputeBuffer CreateKernel(int gaussianRadius, float gaussianSigma)
{
var kernel = OneDimensinalKernel(gaussianRadius, gaussianSigma);// GenerateGaussianKernel(gaussianRadius, gaussianSigma);
var buffer = new ComputeBuffer(kernel.Length, sizeof(float), ComputeBufferType.Default);
buffer.SetData(kernel);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use CommandBuffer.SetBufferData instead otherwise the execution of the graph and the data will be out of sync.
Alternatively, you can also dispatch a compute that updates this buffer.

return buffer;
}

private static float[] OneDimensinalKernel(int radius, float sigma)
{
float[] kernelResult = new float[radius * 2 + 1];
float sum = 0.0f;
for(int t = 0; t< radius; t++)
{
double newBlurWalue = 0.39894 * Mathf.Exp(-0.5f * t*t / (sigma * sigma)) / sigma;
kernelResult[radius+t] = (float)newBlurWalue;
kernelResult[radius-t] = (float)newBlurWalue;
if(t!=0)
sum += (float)newBlurWalue*2.0f;
else
sum += (float)newBlurWalue;
}
// normalize kernels
for(int k = 0; k< radius*2 +1; k++)
{
kernelResult[k]/=sum;
}
return kernelResult;
}

protected override void Disable()
{
base.Disable();
kernelBuffer?.Dispose();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading