#pragma kernel CSMain RWTexture2D Result; float Width; float Height; float Rotation; float Hue; float Saturation; float Brightness; float2 Scale; float2 Offset; Texture2D R_Input_0; Texture2D R_Input_1; Texture2D R_Input_2; Texture2D R_Input_3; SamplerState sampler_R_Input_0; SamplerState sampler_R_Input_1; SamplerState sampler_R_Input_2; SamplerState sampler_R_Input_3; int R_Channel_0; int R_Channel_1; int R_Channel_2; int R_Channel_3; int R_Count; int R_BlendMode; float R_Fallback; bool R_Invert; Texture2D G_Input_0; Texture2D G_Input_1; Texture2D G_Input_2; Texture2D G_Input_3; SamplerState sampler_G_Input_0; SamplerState sampler_G_Input_1; SamplerState sampler_G_Input_2; SamplerState sampler_G_Input_3; int G_Channel_0; int G_Channel_1; int G_Channel_2; int G_Channel_3; int G_Count; int G_BlendMode; float G_Fallback; bool G_Invert; Texture2D B_Input_0; Texture2D B_Input_1; Texture2D B_Input_2; Texture2D B_Input_3; SamplerState sampler_B_Input_0; SamplerState sampler_B_Input_1; SamplerState sampler_B_Input_2; SamplerState sampler_B_Input_3; int B_Channel_0; int B_Channel_1; int B_Channel_2; int B_Channel_3; int B_Count; int B_BlendMode; float B_Fallback; bool B_Invert; Texture2D A_Input_0; Texture2D A_Input_1; Texture2D A_Input_2; Texture2D A_Input_3; SamplerState sampler_A_Input_0; SamplerState sampler_A_Input_1; SamplerState sampler_A_Input_2; SamplerState sampler_A_Input_3; int A_Channel_0; int A_Channel_1; int A_Channel_2; int A_Channel_3; int A_Count; int A_BlendMode; float A_Fallback; bool A_Invert; // blendmodes // 0 = add // 1 = multiply // 3 = max // 4 = min float SampleTexture(Texture2D tex, SamplerState texSampler, int channel, float2 uv) { float4 pixelColor = tex.SampleLevel(texSampler,uv,0); if (channel == 0) return pixelColor.r; else if (channel == 1) return pixelColor.g; else if (channel == 2) return pixelColor.b; else if (channel == 3) return pixelColor.a; else return max(pixelColor.r, max(pixelColor.g, pixelColor.b)); } float SampleAndBlendTexture(float value, Texture2D tex, SamplerState texSampler, int blendMode, int channel, float2 uv) { float newValue = SampleTexture(tex, texSampler, channel, uv); if (blendMode == 0) return value + newValue; else if (blendMode == 1) return value * newValue; else if (blendMode == 2) return max(value, newValue); else if (blendMode == 3) return min(value, newValue); else return newValue; } float SampleAndBlendTextures(Texture2D tex1, Texture2D tex2, Texture2D tex3, Texture2D tex4, int channel1, int channel2, int channel3, int channel4, SamplerState texSampler1, SamplerState texSampler2, SamplerState texSampler3, SamplerState texSampler4, int count, int blendMode, float2 uv) { float value = SampleTexture(tex1, texSampler1, channel1, uv); if(count > 1) value = SampleAndBlendTexture(value, tex2, texSampler2, blendMode, channel2, uv); if(count > 2) value = SampleAndBlendTexture(value, tex3, texSampler3, blendMode, channel3, uv); if(count > 3) value = SampleAndBlendTexture(value, tex4, texSampler4, blendMode, channel4, uv); return value; } float SampleInput(Texture2D tex1, Texture2D tex2, Texture2D tex3, Texture2D tex4, int channel1, int channel2, int channel3, int channel4, SamplerState texSampler1, SamplerState texSampler2, SamplerState texSampler3, SamplerState texSampler4, int count, int blendMode, float fallback, bool doInvert, float2 uv) { float value = fallback; if(count > 0) { value = SampleAndBlendTextures(tex1, tex2, tex3, tex4, channel1, channel2, channel3, channel4, texSampler1, texSampler2, texSampler3, texSampler4, count, blendMode, uv); if(doInvert) value = 1 - value; } return value; } float3 rgb2hsv(float3 rgb){ float4 p = (rgb.g < rgb.b) ? float4(rgb.bg, -1.0, 2.0/3.0) : float4(rgb.gb, 0.0, -1.0/3.0); float4 q = (rgb.r < p.x) ? float4(p.xyw, rgb.r) : float4(rgb.r, p.yzx); float d = q.x - min(q.w, q.y); float e = 1.0e-10; return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); } float3 hsv2rgb(float3 hsv){ float4 K = float4(1.0, 2.0/3.0, 1.0/3.0, 3.0); float3 p = abs(frac(hsv.xxx + K.xyz) * 6.0 - K.www); return hsv.z * lerp(K.xxx, saturate(p - K.xxx), hsv.y); } float4 ApplyHSV(float4 pixel, float hue, float saturation, float value){ float3 hsv = rgb2hsv(pixel.rgb); hsv.r += hue; hsv.g *= saturation; hsv.b *= value; return float4(hsv2rgb(hsv.rgb), pixel.a); } [numthreads(8, 8, 1)] void CSMain(uint3 id : SV_DispatchThreadID) { float2 uv = float2(id.x / Width, id.y / Height) + Offset; // Rotate uv by Rotation around 0.5 0.5 and scale by Scale float2 center = float2(0.5, 0.5); float2 rotated = float2(0, 0); rotated.x = (uv.x - center.x) * cos(Rotation) - (uv.y - center.y) * sin(Rotation); rotated.y = (uv.x - center.x) * sin(Rotation) + (uv.y - center.y) * cos(Rotation); uv = rotated * Scale + center; float4 pixel = float4(1, 1, 1, 1); pixel.r = SampleInput(R_Input_0, R_Input_1, R_Input_2, R_Input_3, R_Channel_0, R_Channel_1, R_Channel_2, R_Channel_3, sampler_R_Input_0, sampler_R_Input_1, sampler_R_Input_2, sampler_R_Input_3, R_Count, R_BlendMode, R_Fallback, R_Invert, uv); pixel.g = SampleInput(G_Input_0, G_Input_1, G_Input_2, G_Input_3, G_Channel_0, G_Channel_1, G_Channel_2, G_Channel_3, sampler_G_Input_0, sampler_G_Input_1, sampler_G_Input_2, sampler_G_Input_3, G_Count, G_BlendMode, G_Fallback, G_Invert, uv); pixel.b = SampleInput(B_Input_0, B_Input_1, B_Input_2, B_Input_3, B_Channel_0, B_Channel_1, B_Channel_2, B_Channel_3, sampler_B_Input_0, sampler_B_Input_1, sampler_B_Input_2, sampler_B_Input_3, B_Count, B_BlendMode, B_Fallback, B_Invert, uv); pixel.a = SampleInput(A_Input_0, A_Input_1, A_Input_2, A_Input_3, A_Channel_0, A_Channel_1, A_Channel_2, A_Channel_3, sampler_A_Input_0, sampler_A_Input_1, sampler_A_Input_2, sampler_A_Input_3, A_Count, A_BlendMode, A_Fallback, A_Invert, uv); pixel = ApplyHSV(pixel, Hue, Saturation, Brightness); Result[id.xy] = pixel; } #pragma kernel CS_Kernel Texture2D Kernel_Input; float4 Kernel_X[25]; float4 Kernel_Y[25]; bool Kernel_Grayscale; bool Kernel_TwoPass; float4 Kernel_Channels; [numthreads(8, 8, 1)] void CS_Kernel(uint3 id : SV_DispatchThreadID) { float4 pixel_x = float4(0, 0, 0, 0); float4 pixel_y = float4(0, 0, 0, 0); for (int x = -2; x <= 2; x++) { for (int y = -2; y <= 2; y++) { float4 p = Kernel_Input.Load(int3(id.xy + int2(x,y), 0)); [branch] if(Kernel_Grayscale) { float gray = dot(p.rgb, float3(0.2126, 0.7152, 0.0722)); pixel_x += float4(gray * Kernel_X[x + 2 + (y + 2) * 5].x, 0, 0, 0); [branch] if(Kernel_TwoPass) { pixel_y += float4(gray * Kernel_Y[x + 2 + (y + 2) * 5].x, 0, 0, 0); } }else { pixel_x += p * Kernel_X[x + 2 + (y + 2) * 5].x; [branch] if(Kernel_TwoPass) { pixel_y += p * Kernel_Y[x + 2 + (y + 2) * 5].x; } } } } float4 color = Kernel_Input.Load(int3(id.xy, 0)); float4 res = color; [branch] if(Kernel_Grayscale) { color = float4(dot(color.rgb, float3(0.2126, 0.7152, 0.0722)), 0, 0, color.a); [branch] if(Kernel_TwoPass) { res = sqrt((pixel_x * pixel_x + pixel_y * pixel_y)).x; } else { res = pixel_x.x; } }else { [branch] if(Kernel_TwoPass) { res = sqrt((pixel_x * pixel_x + pixel_y * pixel_y)); } else { res = pixel_x; } } color.r = lerp(color.r, res.r, Kernel_Channels.x); color.g = lerp(color.g, res.g, Kernel_Channels.y); color.b = lerp(color.b, res.b, Kernel_Channels.z); color.a = lerp(color.a, res.a, Kernel_Channels.w); Result[id.xy] = color; } #pragma kernel CS_ChannelLerper Texture2D Unpacker_Input; float4 Channels_Strength_R; float4 Channels_Strength_G; float4 Channels_Strength_B; float4 Channels_Strength_A; [numthreads(8, 8, 1)] void CS_ChannelLerper(uint3 id : SV_DispatchThreadID) { float4 color = Unpacker_Input.Load(int3(id.xy, 0)); float4 res = color; res.r = lerp(0, color.r, Channels_Strength_R.x) + lerp(0, color.g, Channels_Strength_R.y) + lerp(0, color.b, Channels_Strength_R.z) + lerp(0, color.a, Channels_Strength_R.w); res.g = lerp(0, color.r, Channels_Strength_G.x) + lerp(0, color.g, Channels_Strength_G.y) + lerp(0, color.b, Channels_Strength_G.z) + lerp(0, color.a, Channels_Strength_G.w); res.b = lerp(0, color.r, Channels_Strength_B.x) + lerp(0, color.g, Channels_Strength_B.y) + lerp(0, color.b, Channels_Strength_B.z) + lerp(0, color.a, Channels_Strength_B.w); res.a = lerp(0, color.r, Channels_Strength_A.x) + lerp(0, color.g, Channels_Strength_A.y) + lerp(0, color.b, Channels_Strength_A.z) + lerp(0, color.a, Channels_Strength_A.w); Result[id.xy] = res; }