HeavenStudioPlus/Assets/Shaders/OilPainting/OilPainting.shader

193 lines
7.3 KiB
GLSL

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Unlit/Oil Painting"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_NormalMap ("Normal Map", 2D) = "bump" {}
_NormalWeight ("Normal Weight", Range(0, 10)) = 0.5
_Radius ("Radius", Range(0, 10)) = 0
[KeywordEnum(Low, Medium, High)] _Samples ("Sample amount", Float) = 0
_BlurSize("Blur Size", Range(0, 0.1)) = 0
_StandardDeviation("Standard Deviation", Range(0, 0.1)) = 0.02
_VignetteIntensity("Vignette Intensity", Range(0, 1)) = 0.5
_VignetteSmoothness("Vignette Smoothness", Range(0, 1)) = 0.2
}
SubShader
{
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#include "UnityCG.cginc"
#define PI 3.14159265359
#define E 2.71828182846
#pragma multi_compile _SAMPLES_LOW _SAMPLES_MEDIUM _SAMPLES_HIGH
float _BlurSize;
float _StandardDeviation;
float _VignetteIntensity;
float _VignetteSmoothness;
float _NormalWeight;
#if _SAMPLES_LOW
#define SAMPLES 10
#elif _SAMPLES_MEDIUM
#define SAMPLES 30
#else
#define SAMPLES 100
#endif
struct v2f
{
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
};
sampler2D _MainTex;
sampler2D _NormalMap;
float4 _MainTex_ST;
float vignette(float2 uv, float intensity, float smoothness)
{
float2 position = uv - 0.5;
float distance = length(position);
float vignette = smoothstep(smoothness, smoothness - intensity, distance);
return vignette;
}
v2f vert(appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
int _Radius;
float4 _MainTex_TexelSize;
float4 frag(v2f i) : SV_Target
{
float3 normal = UnpackNormal(tex2D(_NormalMap, i.uv));
half2 uv = i.uv;
float3 col;
float4 color = tex2D(_MainTex, uv);
//kuwahara with normal influence
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 start[4] = {{-_Radius, -_Radius}, {-_Radius, 0}, {0, -_Radius}, {0, 0}};
float2 pos;
float normalInfluence;
for (int k = 0; k < 4; k++)
{
for (int i = 0; i <= _Radius; i++)
{
for (int j = 0; j <= _Radius; j++)
{
float2 kernelDirection = float2(i - 1, j - 1);
kernelDirection = normalize(kernelDirection);
normalInfluence = dot(normal, kernelDirection);
//float weightedVariance = variance + normalInfluence * _NormalWeight;
pos = float2(i, j) + start[k];
col = tex2Dlod(_MainTex, float4(
uv + float2(pos.x * _MainTex_TexelSize.x, pos.y * _MainTex_TexelSize.y),
0., 0.)).rgb;
mean[k] += col;
sigma[k] += col * col;
}
}
}
float sigma2;
float n = pow(_Radius + 1, 2);
float min = 1;
for (int l = 0; l < 4; l++)
{
mean[l] /= n;
sigma[l] = abs(sigma[l] / n - mean[l] * mean[l]);
sigma2 = sigma[l].r + sigma[l].g + sigma[l].b;
if (sigma2 < min + normalInfluence * _NormalWeight)
{
min = sigma2;
color.rgb = mean[l].rgb;
}
}
// blur
//failsafe so we can use turn off the blur by setting the deviation to 0
if (_StandardDeviation != 0)
{
float invAspect = _ScreenParams.y / _ScreenParams.x;
float sum = SAMPLES;
float sum2 = SAMPLES;
float3 col2;
//iterate over blur samples
for (float index = 0; index < SAMPLES; index++)
{
//get the offset of the sample
float offset = (index / (SAMPLES - 1) - 0.5) * _BlurSize;
//get uv coordinate of sample
float2 uv = i.uv + float2(0, offset);
//calculate the result of the gaussian function
float stDevSquared = _StandardDeviation * _StandardDeviation;
float gauss = (1 / sqrt(2 * PI * stDevSquared)) * pow(
E, -((offset * offset) / (2 * stDevSquared)));
//add result to sum
sum += gauss;
//multiply color with influence from gaussian function and add it to sum color
col += tex2D(_MainTex, uv) * gauss;
}
//divide the sum of values by the amount of samples
color.rgb = lerp(color.rgb, col / sum, 0.5);
for (float index = 0; index < SAMPLES; index++)
{
//get the offset of the sample
float offset = (index / (SAMPLES - 1) - 0.5) * _BlurSize * invAspect;
//get uv coordinate of sample
float2 uv = i.uv + float2(offset, 0);
//calculate the result of the gaussian function
float stDevSquared = _StandardDeviation * _StandardDeviation;
float gauss = (1 / sqrt(2 * PI * stDevSquared)) * pow(
E, -((offset * offset) / (2 * stDevSquared)));
//add result to sum
sum2 += gauss;
//multiply color with influence from gaussian function and add it to sum color
col2 += tex2D(_MainTex, uv) * gauss;
}
//divide the sum of values by the amount of samples
color.rgb = lerp(color.rgb , col2 / sum2, 0.5);
}
float vignetteEffect = vignette(i.uv, _VignetteIntensity, _VignetteSmoothness);
color.rgb = color.rgb * vignetteEffect;
return color;
}
ENDCG
}
}
}