-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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,91 @@ | ||
#include "UnityCG.cginc" | ||
|
||
RWStructuredBuffer<uint4> _Histogram; | ||
Texture2D<float4> _Source; | ||
|
||
CBUFFER_START (Params) | ||
uint _IsLinear; | ||
float4 _Res; | ||
uint4 _Channels; | ||
CBUFFER_END | ||
|
||
groupshared uint4 gs_histogram[256]; | ||
|
||
#define GROUP_SIZE 16 | ||
|
||
#pragma kernel KHistogramGather | ||
[numthreads(GROUP_SIZE, GROUP_SIZE,1)] | ||
void KHistogramGather(uint2 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID) | ||
{ | ||
const uint localThreadId = groupThreadId.y * GROUP_SIZE + groupThreadId.x; | ||
|
||
if (localThreadId < 256) | ||
gs_histogram[localThreadId] = uint4(0, 0, 0, 0); | ||
|
||
GroupMemoryBarrierWithGroupSync(); | ||
|
||
if (dispatchThreadId.x < (uint)_Res.x && dispatchThreadId.y < (uint)_Res.y) | ||
{ | ||
// We want a gamma histogram (like Photoshop & all) | ||
float3 color = saturate(_Source[dispatchThreadId].xyz); | ||
if (_IsLinear > 0) | ||
color = LinearToGammaSpace(color); | ||
|
||
// Convert color & luminance to histogram bin | ||
uint3 idx_c = (uint3)(round(color * 255.0)); | ||
uint idx_l = (uint)(round(dot(color.rgb, float3(0.2125, 0.7154, 0.0721)) * 255.0)); | ||
|
||
// Fill the group shared histogram | ||
if (_Channels.x > 0u) InterlockedAdd(gs_histogram[idx_c.x].x, 1); // Red | ||
if (_Channels.y > 0u) InterlockedAdd(gs_histogram[idx_c.y].y, 1); // Green | ||
if (_Channels.z > 0u) InterlockedAdd(gs_histogram[idx_c.z].z, 1); // Blue | ||
if (_Channels.w > 0u) InterlockedAdd(gs_histogram[idx_l].w, 1); // Luminance | ||
} | ||
|
||
GroupMemoryBarrierWithGroupSync(); | ||
|
||
// Merge | ||
if (localThreadId < 256) | ||
{ | ||
uint4 h = gs_histogram[localThreadId]; | ||
if (_Channels.x > 0u && h.x > 0) InterlockedAdd(_Histogram[localThreadId].x, h.x); // Red | ||
if (_Channels.y > 0u && h.y > 0) InterlockedAdd(_Histogram[localThreadId].y, h.y); // Green | ||
if (_Channels.z > 0u && h.z > 0) InterlockedAdd(_Histogram[localThreadId].z, h.z); // Blue | ||
if (_Channels.w > 0u && h.w > 0) InterlockedAdd(_Histogram[localThreadId].w, h.w); // Luminance | ||
} | ||
} | ||
|
||
// Scaling pass | ||
groupshared uint4 gs_pyramid[256]; | ||
|
||
#pragma kernel KHistogramScale | ||
[numthreads(16,16,1)] | ||
void KHistogramScale(uint2 groupThreadId : SV_GroupThreadID) | ||
{ | ||
const uint localThreadId = groupThreadId.y * 16 + groupThreadId.x; | ||
gs_pyramid[localThreadId] = _Histogram[localThreadId]; | ||
|
||
GroupMemoryBarrierWithGroupSync(); | ||
|
||
// Parallel reduction to find the max value | ||
UNITY_UNROLL | ||
for(uint i = 256 >> 1; i > 0; i >>= 1) | ||
{ | ||
if(localThreadId < i) | ||
gs_pyramid[localThreadId] = max(gs_pyramid[localThreadId], gs_pyramid[localThreadId + i]); | ||
|
||
GroupMemoryBarrierWithGroupSync(); | ||
} | ||
|
||
// Actual scaling | ||
float4 factor = _Res.y / (float4)gs_pyramid[0]; | ||
_Histogram[localThreadId] = (uint4)round(_Histogram[localThreadId] * factor); | ||
} | ||
|
||
#pragma kernel KHistogramClear | ||
[numthreads(GROUP_SIZE, GROUP_SIZE, 1)] | ||
void KHistogramClear(uint2 dispatchThreadId : SV_DispatchThreadID) | ||
{ | ||
if (dispatchThreadId.x < (uint)_Res.x && dispatchThreadId.y < (uint)_Res.y) | ||
_Histogram[dispatchThreadId.y * _Res.x + dispatchThreadId.x] = uint4(0u, 0u, 0u, 0u); | ||
} |
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,141 @@ | ||
Shader "Hidden/Post FX/Monitors/Histogram Render" | ||
{ | ||
SubShader | ||
{ | ||
ZTest Always Cull Off ZWrite Off | ||
Fog { Mode off } | ||
|
||
CGINCLUDE | ||
|
||
#pragma fragmentoption ARB_precision_hint_fastest | ||
#pragma target 5.0 | ||
#include "UnityCG.cginc" | ||
|
||
StructuredBuffer<uint4> _Histogram; | ||
float2 _Size; | ||
uint _Channel; | ||
float4 _ColorR; | ||
float4 _ColorG; | ||
float4 _ColorB; | ||
float4 _ColorL; | ||
|
||
float4 FragSingleChannel(v2f_img i) : SV_Target | ||
{ | ||
const float4 COLORS[4] = { _ColorR, _ColorG, _ColorB, _ColorL }; | ||
|
||
float remapI = i.uv.x * 255.0; | ||
uint index = floor(remapI); | ||
float delta = frac(remapI); | ||
float v1 = _Histogram[index][_Channel]; | ||
float v2 = _Histogram[min(index + 1, 255)][_Channel]; | ||
float h = v1 * (1.0 - delta) + v2 * delta; | ||
uint y = (uint)round(i.uv.y * _Size.y); | ||
|
||
float4 color = float4(0.1, 0.1, 0.1, 1.0); | ||
float fill = step(y, h); | ||
color = lerp(color, COLORS[_Channel], fill); | ||
return color; | ||
} | ||
|
||
float4 FragRgbMerged(v2f_img i) : SV_Target | ||
{ | ||
const float4 COLORS[3] = { _ColorR, _ColorG, _ColorB }; | ||
|
||
float4 targetColor = float4(0.1, 0.1, 0.1, 1.0); | ||
float4 emptyColor = float4(0.0, 0.0, 0.0, 1.0); | ||
|
||
float remapI = i.uv.x * 255.0; | ||
uint index = floor(remapI); | ||
float delta = frac(remapI); | ||
|
||
for (int j = 0; j < 3; j++) | ||
{ | ||
float v1 = _Histogram[index][j]; | ||
float v2 = _Histogram[min(index + 1, 255)][j]; | ||
float h = v1 * (1.0 - delta) + v2 * delta; | ||
uint y = (uint)round(i.uv.y * _Size.y); | ||
float fill = step(y, h); | ||
float4 color = lerp(emptyColor, COLORS[j], fill); | ||
targetColor += color; | ||
} | ||
|
||
return saturate(targetColor); | ||
} | ||
|
||
float4 FragRgbSplitted(v2f_img i) : SV_Target | ||
{ | ||
const float4 COLORS[3] = {_ColorR, _ColorG, _ColorB}; | ||
|
||
const float limitB = round(_Size.y / 3.0); | ||
const float limitG = limitB * 2; | ||
|
||
float4 color = float4(0.1, 0.1, 0.1, 1.0); | ||
uint channel; | ||
float offset; | ||
|
||
if (i.pos.y < limitB) | ||
{ | ||
channel = 2; | ||
offset = 0.0; | ||
} | ||
else if (i.pos.y < limitG) | ||
{ | ||
channel = 1; | ||
offset = limitB; | ||
} | ||
else | ||
{ | ||
channel = 0; | ||
offset = limitG; | ||
} | ||
|
||
float remapI = i.uv.x * 255.0; | ||
uint index = floor(remapI); | ||
float delta = frac(remapI); | ||
float v1 = offset + _Histogram[index][channel] / 3.0; | ||
float v2 = offset + _Histogram[min(index + 1, 255)][channel] / 3.0; | ||
float h = v1 * (1.0 - delta) + v2 * delta; | ||
uint y = (uint)round(i.uv.y * _Size.y); | ||
|
||
float fill = step(y, h); | ||
color = lerp(color, COLORS[channel], fill); | ||
return color; | ||
} | ||
|
||
ENDCG | ||
|
||
// (0) Channel | ||
Pass | ||
{ | ||
CGPROGRAM | ||
|
||
#pragma vertex vert_img | ||
#pragma fragment FragSingleChannel | ||
|
||
ENDCG | ||
} | ||
|
||
// (1) RGB merged | ||
Pass | ||
{ | ||
CGPROGRAM | ||
|
||
#pragma vertex vert_img | ||
#pragma fragment FragRgbMerged | ||
|
||
ENDCG | ||
} | ||
|
||
// (2) RGB splitted | ||
Pass | ||
{ | ||
CGPROGRAM | ||
|
||
#pragma vertex vert_img | ||
#pragma fragment FragRgbSplitted | ||
|
||
ENDCG | ||
} | ||
} | ||
FallBack off | ||
} |
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,76 @@ | ||
Shader "Hidden/Post FX/Monitors/Parade Render" | ||
{ | ||
SubShader | ||
{ | ||
ZTest Always Cull Off ZWrite Off | ||
Fog { Mode off } | ||
|
||
CGINCLUDE | ||
|
||
#pragma fragmentoption ARB_precision_hint_fastest | ||
#pragma target 5.0 | ||
#include "UnityCG.cginc" | ||
|
||
StructuredBuffer<uint4> _Waveform; | ||
float4 _Size; | ||
float _Exposure; | ||
|
||
float3 Tonemap(float3 x, float exposure) | ||
{ | ||
const float a = 6.2; | ||
const float b = 0.5; | ||
const float c = 1.7; | ||
const float d = 0.06; | ||
x *= exposure; | ||
x = max((0.0).xxx, x - (0.004).xxx); | ||
x = (x * (a * x + b)) / (x * (a * x + c) + d); | ||
return x * x; | ||
} | ||
|
||
float4 FragParade(v2f_img i) : SV_Target | ||
{ | ||
const float3 red = float3(1.8, 0.03, 0.02); | ||
const float3 green = float3(0.02, 1.3, 0.05); | ||
const float3 blue = float3(0.0, 0.45, 1.75); | ||
float3 color = float3(0.0, 0.0, 0.0); | ||
|
||
const uint limitR = _Size.x / 3; | ||
const uint limitG = limitR * 2; | ||
|
||
if (i.pos.x < (float)limitR) | ||
{ | ||
uint2 uvI = i.pos.xy; | ||
color = _Waveform[uvI.y + uvI.x * _Size.y].r * red; | ||
} | ||
else if (i.pos.x < (float)limitG) | ||
{ | ||
uint2 uvI = uint2(i.pos.x - limitR, i.pos.y); | ||
color = _Waveform[uvI.y + uvI.x * _Size.y].g * green; | ||
} | ||
else | ||
{ | ||
uint2 uvI = uint2(i.pos.x - limitG, i.pos.y); | ||
color = _Waveform[uvI.y + uvI.x * _Size.y].b * blue; | ||
} | ||
|
||
color = Tonemap(color, _Exposure); | ||
color += (0.1).xxx; | ||
|
||
return float4(saturate(color), 1.0); | ||
} | ||
|
||
ENDCG | ||
|
||
// (0) | ||
Pass | ||
{ | ||
CGPROGRAM | ||
|
||
#pragma vertex vert_img | ||
#pragma fragment FragParade | ||
|
||
ENDCG | ||
} | ||
} | ||
FallBack off | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.