场景效果提交
This commit is contained in:
parent
69fd693765
commit
4113906db5
|
@ -0,0 +1,64 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!850595691 &4890085278179872738
|
||||
LightingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: New Lighting Settings
|
||||
serializedVersion: 4
|
||||
m_GIWorkflowMode: 1
|
||||
m_EnableBakedLightmaps: 1
|
||||
m_EnableRealtimeLightmaps: 0
|
||||
m_RealtimeEnvironmentLighting: 1
|
||||
m_BounceScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_UsingShadowmask: 1
|
||||
m_BakeBackend: 2
|
||||
m_LightmapMaxSize: 1024
|
||||
m_BakeResolution: 40
|
||||
m_Padding: 2
|
||||
m_LightmapCompression: 3
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAO: 0
|
||||
m_MixedBakeMode: 2
|
||||
m_LightmapsBakeMode: 1
|
||||
m_FilterMode: 1
|
||||
m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_RealtimeResolution: 2
|
||||
m_ForceWhiteAlbedo: 0
|
||||
m_ForceUpdates: 0
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherRayCount: 256
|
||||
m_FinalGatherFiltering: 1
|
||||
m_PVRCulling: 1
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 512
|
||||
m_PVREnvironmentSampleCount: 256
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_PVRBounces: 2
|
||||
m_PVRMinBounces: 1
|
||||
m_PVREnvironmentMIS: 1
|
||||
m_PVRFilteringMode: 1
|
||||
m_PVRDenoiserTypeDirect: 1
|
||||
m_PVRDenoiserTypeIndirect: 1
|
||||
m_PVRDenoiserTypeAO: 1
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_PVRTiledBaking: 0
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 780a9f934420a1b4fb1b1fa2691b50d9
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 4890085278179872738
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5af07a3b6e1f41f479ec379816096dfa
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 83715878d3a8db441aa5636641db69a3
|
||||
folderAsset: yes
|
||||
timeCreated: 1476176392
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e7358848dd8737c459f4636f1c075835
|
||||
folderAsset: yes
|
||||
timeCreated: 1460361782
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 51b7e4b4448c98f4a849081110fd6212
|
||||
timeCreated: 1459956391
|
||||
licenseType: Store
|
||||
ComputeShaderImporter:
|
||||
currentAPIMask: 4
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 965efa32cf2345647a1c987546e08f86
|
||||
timeCreated: 1459956391
|
||||
licenseType: Store
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5ae1bfc1dd20ac04e8b74aa0f2f12eea
|
||||
timeCreated: 1459956391
|
||||
licenseType: Store
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,49 @@
|
|||
#include "UnityCG.cginc"
|
||||
|
||||
RWStructuredBuffer<uint> _Vectorscope;
|
||||
Texture2D<float4> _Source;
|
||||
|
||||
CBUFFER_START (Params)
|
||||
uint _IsLinear;
|
||||
float4 _Res;
|
||||
CBUFFER_END
|
||||
|
||||
#define GROUP_SIZE 32
|
||||
|
||||
float3 RgbToYUV(float3 c)
|
||||
{
|
||||
float Y = 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;
|
||||
float U = -0.169 * c.r - 0.331 * c.g + 0.500 * c.b;
|
||||
float V = 0.500 * c.r - 0.419 * c.g - 0.081 * c.b;
|
||||
return float3(Y, U, V);
|
||||
}
|
||||
|
||||
#pragma kernel KVectorscope
|
||||
[numthreads(GROUP_SIZE,GROUP_SIZE,1)]
|
||||
void KVectorscope(uint2 dispatchThreadId : SV_DispatchThreadID)
|
||||
{
|
||||
if (dispatchThreadId.x < (uint)_Res.x && dispatchThreadId.y < (uint)_Res.y)
|
||||
{
|
||||
float3 color = saturate(_Source[dispatchThreadId].xyz);
|
||||
if (_IsLinear > 0)
|
||||
color = LinearToGammaSpace(color);
|
||||
|
||||
float3 yuv = RgbToYUV(color);
|
||||
|
||||
if (length(yuv.yz) > 0.49)
|
||||
yuv.yz = normalize(yuv.yz) * 0.49;
|
||||
|
||||
yuv.yz += (0.5).xx;
|
||||
uint u = (uint)floor(yuv.y * _Res.x);
|
||||
uint v = (uint)floor(yuv.z * _Res.y);
|
||||
InterlockedAdd(_Vectorscope[v * _Res.x + u], 1);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma kernel KVectorscopeClear
|
||||
[numthreads(GROUP_SIZE,GROUP_SIZE,1)]
|
||||
void KVectorscopeClear(uint2 dispatchThreadId : SV_DispatchThreadID)
|
||||
{
|
||||
if (dispatchThreadId.x < (uint)_Res.x && dispatchThreadId.y < (uint)_Res.y)
|
||||
_Vectorscope[dispatchThreadId.y * _Res.x + dispatchThreadId.x] = 0u;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 45de9ff58691e934c9810dc23de2ba50
|
||||
timeCreated: 1459956391
|
||||
licenseType: Store
|
||||
ComputeShaderImporter:
|
||||
currentAPIMask: 4
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,101 @@
|
|||
Shader "Hidden/Post FX/Monitors/Vectorscope 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<uint> _Vectorscope;
|
||||
float2 _Size;
|
||||
float _Exposure;
|
||||
|
||||
float Tonemap(float 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, x - 0.004);
|
||||
x = (x * (a * x + b)) / (x * (a * x + c) + d);
|
||||
return x * x;
|
||||
}
|
||||
|
||||
float3 YuvToRgb(float3 c)
|
||||
{
|
||||
float R = c.x + 0.000 * c.y + 1.403 * c.z;
|
||||
float G = c.x - 0.344 * c.y - 0.714 * c.z;
|
||||
float B = c.x - 1.773 * c.y + 0.000 * c.z;
|
||||
return float3(R, G, B);
|
||||
}
|
||||
|
||||
float4 FragBackground(v2f_img i) : SV_Target
|
||||
{
|
||||
i.uv.x = 1.0 - i.uv.x;
|
||||
float2 uv = i.uv - (0.5).xx;
|
||||
float3 c = YuvToRgb(float3(0.5, uv.x, uv.y));
|
||||
|
||||
float dist = sqrt(dot(uv, uv));
|
||||
float delta = fwidth(dist);
|
||||
float alphaOut = 1.0 - smoothstep(0.5 - delta, 0.5 + delta, dist);
|
||||
float alphaIn = smoothstep(0.495 - delta, 0.495 + delta, dist);
|
||||
|
||||
uint2 uvI = i.pos.xy;
|
||||
uint v = _Vectorscope[uvI.x + uvI.y * _Size.x];
|
||||
float vt = saturate(Tonemap(v, _Exposure));
|
||||
|
||||
float4 color = float4(lerp(c, (0.0).xxx, vt), alphaOut);
|
||||
color.rgb += alphaIn;
|
||||
return color;
|
||||
}
|
||||
|
||||
float4 FragNoBackground(v2f_img i) : SV_Target
|
||||
{
|
||||
i.uv.x = 1.0 - i.uv.x;
|
||||
float2 uv = i.uv - (0.5).xx;
|
||||
|
||||
float dist = sqrt(dot(uv, uv));
|
||||
float delta = fwidth(dist);
|
||||
float alphaOut = 1.0 - smoothstep(0.5 - delta, 0.5 + delta, dist);
|
||||
float alphaIn = smoothstep(0.495 - delta, 0.495 + delta, dist);
|
||||
|
||||
uint2 uvI = i.pos.xy;
|
||||
uint v = _Vectorscope[uvI.x + uvI.y * _Size.x];
|
||||
float vt = saturate(Tonemap(v, _Exposure));
|
||||
|
||||
float4 color = float4((1.0).xxx, vt + alphaIn * alphaOut);
|
||||
return color;
|
||||
}
|
||||
|
||||
ENDCG
|
||||
|
||||
// (0)
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vert_img
|
||||
#pragma fragment FragBackground
|
||||
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// (1)
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vert_img
|
||||
#pragma fragment FragNoBackground
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
FallBack off
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1c4298cd35ef7834e892898e49d61ecd
|
||||
timeCreated: 1461756159
|
||||
licenseType: Store
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,42 @@
|
|||
#include "UnityCG.cginc"
|
||||
|
||||
RWStructuredBuffer<uint4> _Waveform;
|
||||
Texture2D<float4> _Source;
|
||||
|
||||
CBUFFER_START (Params)
|
||||
uint _IsLinear;
|
||||
uint4 _Channels;
|
||||
CBUFFER_END
|
||||
|
||||
#define COLUMNS 384
|
||||
|
||||
#pragma kernel KWaveform
|
||||
[numthreads(1,COLUMNS,1)]
|
||||
void KWaveform(uint2 dispatchThreadId : SV_DispatchThreadID)
|
||||
{
|
||||
// We want a gamma corrected colors
|
||||
float3 color = _Source[dispatchThreadId].rgb;
|
||||
if (_IsLinear > 0u)
|
||||
color = LinearToGammaSpace(color);
|
||||
|
||||
color = saturate(color);
|
||||
|
||||
// Convert color & luminance to histogram bins
|
||||
const float kColumnsMinusOne = COLUMNS - 1.0;
|
||||
uint3 idx_c = (uint3)(round(color * kColumnsMinusOne));
|
||||
uint idx_l = (uint)(round(dot(color.rgb, float3(0.2126, 0.7152, 0.0722)) * kColumnsMinusOne));
|
||||
|
||||
// A lot of atomic operations will be skipped so there's no need to over-think this one.
|
||||
uint j = dispatchThreadId.x * COLUMNS;
|
||||
if (_Channels.x > 0u && idx_c.x > 0u) InterlockedAdd(_Waveform[j + idx_c.x].x, 1u); // Red
|
||||
if (_Channels.y > 0u && idx_c.y > 0u) InterlockedAdd(_Waveform[j + idx_c.y].y, 1u); // Green
|
||||
if (_Channels.z > 0u && idx_c.z > 0u) InterlockedAdd(_Waveform[j + idx_c.z].z, 1u); // Blue
|
||||
if (_Channels.w > 0u) InterlockedAdd(_Waveform[j + idx_l].w, 1u); // Luminance
|
||||
}
|
||||
|
||||
#pragma kernel KWaveformClear
|
||||
[numthreads(1, COLUMNS, 1)]
|
||||
void KWaveformClear(uint2 dispatchThreadId : SV_DispatchThreadID)
|
||||
{
|
||||
_Waveform[dispatchThreadId.x * COLUMNS + dispatchThreadId.y] = uint4(0u, 0u, 0u, 0u);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9d9b886f7a8fe7b4baf56624c42e3420
|
||||
timeCreated: 1459956392
|
||||
licenseType: Store
|
||||
ComputeShaderImporter:
|
||||
currentAPIMask: 4
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,65 @@
|
|||
Shader "Hidden/Post FX/Monitors/Waveform 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;
|
||||
float2 _Size;
|
||||
float4 _Channels;
|
||||
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 FragWaveform(v2f_img i) : SV_Target
|
||||
{
|
||||
const float3 red = float3(1.4, 0.03, 0.02);
|
||||
const float3 green = float3(0.02, 1.1, 0.05);
|
||||
const float3 blue = float3(0.0, 0.25, 1.5);
|
||||
float3 color = float3(0.0, 0.0, 0.0);
|
||||
|
||||
uint2 uvI = i.pos.xy;
|
||||
float4 w = _Waveform[uvI.y + uvI.x * _Size.y]; // Waveform data is stored in columns instead of rows
|
||||
|
||||
color += red * w.r * _Channels.r;
|
||||
color += green * w.g * _Channels.g;
|
||||
color += blue * w.b * _Channels.b;
|
||||
color += w.aaa * _Channels.a * 1.5;
|
||||
color = Tonemap(color, _Exposure);
|
||||
color += (0.1).xxx;
|
||||
|
||||
return float4(saturate(color), 1.0);
|
||||
}
|
||||
|
||||
ENDCG
|
||||
|
||||
// (0)
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vert_img
|
||||
#pragma fragment FragWaveform
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
FallBack off
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8b3e43c50424ab2428a9c172843bc66d
|
||||
timeCreated: 1459956391
|
||||
licenseType: Store
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: df37d60cc69b7b04d9705a74938179e7
|
||||
folderAsset: yes
|
||||
timeCreated: 1460627771
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,63 @@
|
|||
Shader "Hidden/Post FX/UI/Curve Background"
|
||||
{
|
||||
CGINCLUDE
|
||||
|
||||
#pragma target 3.0
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
float _DisabledState;
|
||||
|
||||
float3 HsvToRgb(float3 c)
|
||||
{
|
||||
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);
|
||||
}
|
||||
|
||||
float4 FragHue(v2f_img i) : SV_Target
|
||||
{
|
||||
float3 hsv = HsvToRgb(float3(i.uv.x, 1.0, 0.2));
|
||||
float4 color = float4((0.0).xxx, 1.0);
|
||||
color.rgb = lerp(color.rgb, hsv, smoothstep(0.5, 1.1, 1.0 - i.uv.y)) + lerp(color.rgb, hsv, smoothstep(0.5, 1.1, i.uv.y));
|
||||
color.rgb += (0.15).xxx;
|
||||
return float4(color.rgb, color.a * _DisabledState);
|
||||
}
|
||||
|
||||
float4 FragSat(v2f_img i) : SV_Target
|
||||
{
|
||||
float4 color = float4((0.0).xxx, 1.0);
|
||||
float sat = i.uv.x / 2;
|
||||
color.rgb += lerp(color.rgb, (sat).xxx, smoothstep(0.5, 1.2, 1.0 - i.uv.y)) + lerp(color.rgb, (sat).xxx, smoothstep(0.5, 1.2, i.uv.y));
|
||||
color.rgb += (0.15).xxx;
|
||||
return float4(color.rgb, color.a * _DisabledState);
|
||||
}
|
||||
|
||||
ENDCG
|
||||
|
||||
SubShader
|
||||
{
|
||||
Cull Off ZWrite Off ZTest Always
|
||||
|
||||
// (0) Hue
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vert_img
|
||||
#pragma fragment FragHue
|
||||
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// (1) Sat/lum
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vert_img
|
||||
#pragma fragment FragSat
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b1b2bfb2897659e45983f0c3e7dda2c8
|
||||
timeCreated: 1460970196
|
||||
licenseType: Store
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
After Width: | Height: | Size: 7.9 KiB |
|
@ -0,0 +1,59 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c0fa58091049bd24394fa15b0b6d4c5a
|
||||
timeCreated: 1468326774
|
||||
licenseType: Store
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 1
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 7
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
allowsAlphaSplitting: 0
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,118 @@
|
|||
Shader "Hidden/Post FX/UI/Trackball"
|
||||
{
|
||||
CGINCLUDE
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
#define PI 3.14159265359
|
||||
#define PI2 6.28318530718
|
||||
|
||||
float _Offset;
|
||||
float _DisabledState;
|
||||
float2 _Resolution; // x: size, y: size / 2
|
||||
|
||||
float3 HsvToRgb(float3 c)
|
||||
{
|
||||
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||
float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
|
||||
return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);
|
||||
}
|
||||
|
||||
float4 CreateWheel(v2f_img i, float crossColor, float offsetColor)
|
||||
{
|
||||
const float kHueOuterRadius = 0.45;
|
||||
const float kHueInnerRadius = 0.38;
|
||||
const float kLumOuterRadius = 0.495;
|
||||
const float kLumInnerRadius = 0.48;
|
||||
|
||||
float4 color = (0.0).xxxx;
|
||||
float2 uvc = i.uv - (0.5).xx;
|
||||
float dist = sqrt(dot(uvc, uvc));
|
||||
float delta = fwidth(dist);
|
||||
float angle = atan2(uvc.x, uvc.y);
|
||||
|
||||
// Cross
|
||||
{
|
||||
float radius = (0.5 - kHueInnerRadius) * _Resolution.x + 1.0;
|
||||
float2 pixel = (_Resolution.xx - 1.0) * i.uv + 1.0;
|
||||
|
||||
float vline = step(floor(fmod(pixel.x, _Resolution.y)), 0.0);
|
||||
vline *= step(radius, pixel.y) * step(pixel.y, _Resolution.x - radius);
|
||||
|
||||
float hline = step(floor(fmod(pixel.y, _Resolution.y)), 0.0);
|
||||
hline *= step(radius, pixel.x) * step(pixel.x, _Resolution.x - radius);
|
||||
|
||||
color += hline.xxxx * (1.0).xxxx;
|
||||
color += vline.xxxx * (1.0).xxxx;
|
||||
color = saturate(color);
|
||||
color *= half4((crossColor).xxx, 0.05);
|
||||
}
|
||||
|
||||
// Hue
|
||||
{
|
||||
float alphaOut = smoothstep(kHueOuterRadius - delta, kHueOuterRadius + delta, dist);
|
||||
float alphaIn = smoothstep(kHueInnerRadius - delta, kHueInnerRadius + delta, dist);
|
||||
|
||||
float hue = angle;
|
||||
hue = 1.0 - ((hue > 0.0) ? hue : PI2 + hue) / PI2;
|
||||
float4 c = float4(HsvToRgb(float3(hue, 1.0, 1.0)), 1.0);
|
||||
color += lerp((0.0).xxxx, c, alphaIn - alphaOut);
|
||||
}
|
||||
|
||||
// Offset
|
||||
{
|
||||
float alphaOut = smoothstep(kLumOuterRadius - delta, kLumOuterRadius + delta, dist);
|
||||
float alphaIn = smoothstep(kLumInnerRadius - delta, kLumInnerRadius + delta / 2, dist);
|
||||
float4 c = float4((offsetColor).xxx, 1.0);
|
||||
|
||||
float a = PI * _Offset;
|
||||
if (_Offset >= 0 && angle < a && angle > 0.0)
|
||||
c = float4((1.0).xxx, 0.5);
|
||||
else if (angle > a && angle < 0.0)
|
||||
c = float4((1.0).xxx, 0.5);
|
||||
|
||||
color += lerp((0.0).xxxx, c, alphaIn - alphaOut);
|
||||
}
|
||||
|
||||
return color * _DisabledState;
|
||||
}
|
||||
|
||||
float4 FragTrackballDark(v2f_img i) : SV_Target
|
||||
{
|
||||
return CreateWheel(i, 1.0, 0.15);
|
||||
}
|
||||
|
||||
float4 FragTrackballLight(v2f_img i) : SV_Target
|
||||
{
|
||||
return CreateWheel(i, 0.0, 0.3);
|
||||
}
|
||||
|
||||
ENDCG
|
||||
|
||||
SubShader
|
||||
{
|
||||
Cull Off ZWrite Off ZTest Always
|
||||
|
||||
// (0) Dark skin
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vert_img
|
||||
#pragma fragment FragTrackballDark
|
||||
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// (1) Light skin
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vert_img
|
||||
#pragma fragment FragTrackballLight
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4bf49309c7ab9eb42a86774d2c09b4fa
|
||||
timeCreated: 1460627788
|
||||
licenseType: Store
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e0e418747b892364db5c5f4451e67ede
|
||||
folderAsset: yes
|
||||
timeCreated: 1466586258
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cc5c690f549b4704eb992a9be781554d
|
||||
folderAsset: yes
|
||||
timeCreated: 1466769698
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
public class PostProcessingModelEditorAttribute : Attribute
|
||||
{
|
||||
public readonly Type type;
|
||||
public readonly bool alwaysEnabled;
|
||||
|
||||
public PostProcessingModelEditorAttribute(Type type, bool alwaysEnabled = false)
|
||||
{
|
||||
this.type = type;
|
||||
this.alwaysEnabled = alwaysEnabled;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c21938aa988055347a2271f03a3e731e
|
||||
timeCreated: 1466769734
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d5341d31985da604db4b100f174142ad
|
||||
folderAsset: yes
|
||||
timeCreated: 1466769808
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,42 @@
|
|||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using Settings = AmbientOcclusionModel.Settings;
|
||||
|
||||
[PostProcessingModelEditor(typeof(AmbientOcclusionModel))]
|
||||
public class AmbientOcclusionModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
SerializedProperty m_Intensity;
|
||||
SerializedProperty m_Radius;
|
||||
SerializedProperty m_SampleCount;
|
||||
SerializedProperty m_Downsampling;
|
||||
SerializedProperty m_ForceForwardCompatibility;
|
||||
SerializedProperty m_AmbientOnly;
|
||||
SerializedProperty m_HighPrecision;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_Intensity = FindSetting((Settings x) => x.intensity);
|
||||
m_Radius = FindSetting((Settings x) => x.radius);
|
||||
m_SampleCount = FindSetting((Settings x) => x.sampleCount);
|
||||
m_Downsampling = FindSetting((Settings x) => x.downsampling);
|
||||
m_ForceForwardCompatibility = FindSetting((Settings x) => x.forceForwardCompatibility);
|
||||
m_AmbientOnly = FindSetting((Settings x) => x.ambientOnly);
|
||||
m_HighPrecision = FindSetting((Settings x) => x.highPrecision);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_Intensity);
|
||||
EditorGUILayout.PropertyField(m_Radius);
|
||||
EditorGUILayout.PropertyField(m_SampleCount);
|
||||
EditorGUILayout.PropertyField(m_Downsampling);
|
||||
EditorGUILayout.PropertyField(m_ForceForwardCompatibility);
|
||||
EditorGUILayout.PropertyField(m_HighPrecision, EditorGUIHelper.GetContent("High Precision (Forward)"));
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(m_ForceForwardCompatibility.boolValue))
|
||||
EditorGUILayout.PropertyField(m_AmbientOnly, EditorGUIHelper.GetContent("Ambient Only (Deferred + HDR)"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9fcb710e23a5a0546a3b8b0ca28c1720
|
||||
timeCreated: 1467190133
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,71 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using Method = AntialiasingModel.Method;
|
||||
using Settings = AntialiasingModel.Settings;
|
||||
|
||||
[PostProcessingModelEditor(typeof(AntialiasingModel))]
|
||||
public class AntialiasingModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
SerializedProperty m_Method;
|
||||
|
||||
SerializedProperty m_FxaaPreset;
|
||||
|
||||
SerializedProperty m_TaaJitterSpread;
|
||||
SerializedProperty m_TaaSharpen;
|
||||
SerializedProperty m_TaaStationaryBlending;
|
||||
SerializedProperty m_TaaMotionBlending;
|
||||
|
||||
static string[] s_MethodNames =
|
||||
{
|
||||
"Fast Approximate Anti-aliasing",
|
||||
"Temporal Anti-aliasing"
|
||||
};
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_Method = FindSetting((Settings x) => x.method);
|
||||
|
||||
m_FxaaPreset = FindSetting((Settings x) => x.fxaaSettings.preset);
|
||||
|
||||
m_TaaJitterSpread = FindSetting((Settings x) => x.taaSettings.jitterSpread);
|
||||
m_TaaSharpen = FindSetting((Settings x) => x.taaSettings.sharpen);
|
||||
m_TaaStationaryBlending = FindSetting((Settings x) => x.taaSettings.stationaryBlending);
|
||||
m_TaaMotionBlending = FindSetting((Settings x) => x.taaSettings.motionBlending);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
m_Method.intValue = EditorGUILayout.Popup("Method", m_Method.intValue, s_MethodNames);
|
||||
|
||||
if (m_Method.intValue == (int)Method.Fxaa)
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_FxaaPreset);
|
||||
}
|
||||
else if (m_Method.intValue == (int)Method.Taa)
|
||||
{
|
||||
if (QualitySettings.antiAliasing > 1)
|
||||
EditorGUILayout.HelpBox("Temporal Anti-Aliasing doesn't work correctly when MSAA is enabled.", MessageType.Warning);
|
||||
|
||||
EditorGUILayout.LabelField("Jitter", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_TaaJitterSpread, EditorGUIHelper.GetContent("Spread"));
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Blending", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_TaaStationaryBlending, EditorGUIHelper.GetContent("Stationary"));
|
||||
EditorGUILayout.PropertyField(m_TaaMotionBlending, EditorGUIHelper.GetContent("Motion"));
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(m_TaaSharpen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2451939fe695c1a408ba688219837667
|
||||
timeCreated: 1467190133
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,204 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using Settings = BloomModel.Settings;
|
||||
|
||||
[PostProcessingModelEditor(typeof(BloomModel))]
|
||||
public class BloomModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
struct BloomSettings
|
||||
{
|
||||
public SerializedProperty intensity;
|
||||
public SerializedProperty threshold;
|
||||
public SerializedProperty softKnee;
|
||||
public SerializedProperty radius;
|
||||
public SerializedProperty antiFlicker;
|
||||
}
|
||||
|
||||
struct LensDirtSettings
|
||||
{
|
||||
public SerializedProperty texture;
|
||||
public SerializedProperty intensity;
|
||||
}
|
||||
|
||||
BloomSettings m_Bloom;
|
||||
LensDirtSettings m_LensDirt;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_Bloom = new BloomSettings
|
||||
{
|
||||
intensity = FindSetting((Settings x) => x.bloom.intensity),
|
||||
threshold = FindSetting((Settings x) => x.bloom.threshold),
|
||||
softKnee = FindSetting((Settings x) => x.bloom.softKnee),
|
||||
radius = FindSetting((Settings x) => x.bloom.radius),
|
||||
antiFlicker = FindSetting((Settings x) => x.bloom.antiFlicker)
|
||||
};
|
||||
|
||||
m_LensDirt = new LensDirtSettings
|
||||
{
|
||||
texture = FindSetting((Settings x) => x.lensDirt.texture),
|
||||
intensity = FindSetting((Settings x) => x.lensDirt.intensity)
|
||||
};
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
PrepareGraph();
|
||||
DrawGraph();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Bloom.intensity);
|
||||
EditorGUILayout.PropertyField(m_Bloom.threshold, EditorGUIHelper.GetContent("Threshold (Gamma)"));
|
||||
EditorGUILayout.PropertyField(m_Bloom.softKnee);
|
||||
EditorGUILayout.PropertyField(m_Bloom.radius);
|
||||
EditorGUILayout.PropertyField(m_Bloom.antiFlicker);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Dirt", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_LensDirt.texture);
|
||||
EditorGUILayout.PropertyField(m_LensDirt.intensity);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
#region Graph
|
||||
|
||||
float m_GraphThreshold;
|
||||
float m_GraphKnee;
|
||||
float m_GraphIntensity;
|
||||
|
||||
// Number of vertices in curve
|
||||
const int k_CurveResolution = 48;
|
||||
|
||||
// Vertex buffers
|
||||
Vector3[] m_RectVertices = new Vector3[4];
|
||||
Vector3[] m_LineVertices = new Vector3[2];
|
||||
Vector3[] m_CurveVertices = new Vector3[k_CurveResolution];
|
||||
|
||||
Rect m_RectGraph;
|
||||
float m_RangeX;
|
||||
float m_RangeY;
|
||||
|
||||
float ResponseFunction(float x)
|
||||
{
|
||||
var rq = Mathf.Clamp(x - m_GraphThreshold + m_GraphKnee, 0, m_GraphKnee * 2);
|
||||
rq = rq * rq * 0.25f / m_GraphKnee;
|
||||
return Mathf.Max(rq, x - m_GraphThreshold) * m_GraphIntensity;
|
||||
}
|
||||
|
||||
// Transform a point into the graph rect
|
||||
Vector3 PointInRect(float x, float y)
|
||||
{
|
||||
x = Mathf.Lerp(m_RectGraph.x, m_RectGraph.xMax, x / m_RangeX);
|
||||
y = Mathf.Lerp(m_RectGraph.yMax, m_RectGraph.y, y / m_RangeY);
|
||||
return new Vector3(x, y, 0);
|
||||
}
|
||||
|
||||
// Draw a line in the graph rect
|
||||
void DrawLine(float x1, float y1, float x2, float y2, float grayscale)
|
||||
{
|
||||
m_LineVertices[0] = PointInRect(x1, y1);
|
||||
m_LineVertices[1] = PointInRect(x2, y2);
|
||||
Handles.color = Color.white * grayscale;
|
||||
Handles.DrawAAPolyLine(2.0f, m_LineVertices);
|
||||
}
|
||||
|
||||
// Draw a rect in the graph rect
|
||||
void DrawRect(float x1, float y1, float x2, float y2, float fill, float line)
|
||||
{
|
||||
m_RectVertices[0] = PointInRect(x1, y1);
|
||||
m_RectVertices[1] = PointInRect(x2, y1);
|
||||
m_RectVertices[2] = PointInRect(x2, y2);
|
||||
m_RectVertices[3] = PointInRect(x1, y2);
|
||||
|
||||
Handles.DrawSolidRectangleWithOutline(
|
||||
m_RectVertices,
|
||||
fill < 0 ? Color.clear : Color.white * fill,
|
||||
line < 0 ? Color.clear : Color.white * line
|
||||
);
|
||||
}
|
||||
|
||||
// Update internal state with a given bloom instance
|
||||
public void PrepareGraph()
|
||||
{
|
||||
var bloom = (BloomModel)target;
|
||||
m_RangeX = 5f;
|
||||
m_RangeY = 2f;
|
||||
|
||||
m_GraphThreshold = bloom.settings.bloom.thresholdLinear;
|
||||
m_GraphKnee = bloom.settings.bloom.softKnee * m_GraphThreshold + 1e-5f;
|
||||
|
||||
// Intensity is capped to prevent sampling errors
|
||||
m_GraphIntensity = Mathf.Min(bloom.settings.bloom.intensity, 10f);
|
||||
}
|
||||
|
||||
// Draw the graph at the current position
|
||||
public void DrawGraph()
|
||||
{
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.Space(EditorGUI.indentLevel * 15f);
|
||||
m_RectGraph = GUILayoutUtility.GetRect(128, 80);
|
||||
}
|
||||
|
||||
// Background
|
||||
DrawRect(0, 0, m_RangeX, m_RangeY, 0.1f, 0.4f);
|
||||
|
||||
// Soft-knee range
|
||||
DrawRect(m_GraphThreshold - m_GraphKnee, 0, m_GraphThreshold + m_GraphKnee, m_RangeY, 0.25f, -1);
|
||||
|
||||
// Horizontal lines
|
||||
for (var i = 1; i < m_RangeY; i++)
|
||||
DrawLine(0, i, m_RangeX, i, 0.4f);
|
||||
|
||||
// Vertical lines
|
||||
for (var i = 1; i < m_RangeX; i++)
|
||||
DrawLine(i, 0, i, m_RangeY, 0.4f);
|
||||
|
||||
// Label
|
||||
Handles.Label(
|
||||
PointInRect(0, m_RangeY) + Vector3.right,
|
||||
"Brightness Response (linear)", EditorStyles.miniLabel
|
||||
);
|
||||
|
||||
// Threshold line
|
||||
DrawLine(m_GraphThreshold, 0, m_GraphThreshold, m_RangeY, 0.6f);
|
||||
|
||||
// Response curve
|
||||
var vcount = 0;
|
||||
while (vcount < k_CurveResolution)
|
||||
{
|
||||
var x = m_RangeX * vcount / (k_CurveResolution - 1);
|
||||
var y = ResponseFunction(x);
|
||||
if (y < m_RangeY)
|
||||
{
|
||||
m_CurveVertices[vcount++] = PointInRect(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vcount > 1)
|
||||
{
|
||||
// Extend the last segment to the top edge of the rect.
|
||||
var v1 = m_CurveVertices[vcount - 2];
|
||||
var v2 = m_CurveVertices[vcount - 1];
|
||||
var clip = (m_RectGraph.y - v1.y) / (v2.y - v1.y);
|
||||
m_CurveVertices[vcount - 1] = v1 + (v2 - v1) * clip;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (vcount > 1)
|
||||
{
|
||||
Handles.color = Color.white * 0.9f;
|
||||
Handles.DrawAAPolyLine(2.0f, vcount, m_CurveVertices);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a95f3f10e7e437c49ade656f531b30d2
|
||||
timeCreated: 1467190133
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,106 @@
|
|||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using Mode = BuiltinDebugViewsModel.Mode;
|
||||
using Settings = BuiltinDebugViewsModel.Settings;
|
||||
|
||||
[PostProcessingModelEditor(typeof(BuiltinDebugViewsModel), alwaysEnabled: true)]
|
||||
public class BuiltinDebugViewsEditor : PostProcessingModelEditor
|
||||
{
|
||||
struct DepthSettings
|
||||
{
|
||||
public SerializedProperty scale;
|
||||
}
|
||||
|
||||
struct MotionVectorsSettings
|
||||
{
|
||||
public SerializedProperty sourceOpacity;
|
||||
public SerializedProperty motionImageOpacity;
|
||||
public SerializedProperty motionImageAmplitude;
|
||||
public SerializedProperty motionVectorsOpacity;
|
||||
public SerializedProperty motionVectorsResolution;
|
||||
public SerializedProperty motionVectorsAmplitude;
|
||||
}
|
||||
|
||||
SerializedProperty m_Mode;
|
||||
DepthSettings m_Depth;
|
||||
MotionVectorsSettings m_MotionVectors;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_Mode = FindSetting((Settings x) => x.mode);
|
||||
|
||||
m_Depth = new DepthSettings
|
||||
{
|
||||
scale = FindSetting((Settings x) => x.depth.scale)
|
||||
};
|
||||
|
||||
m_MotionVectors = new MotionVectorsSettings
|
||||
{
|
||||
sourceOpacity = FindSetting((Settings x) => x.motionVectors.sourceOpacity),
|
||||
motionImageOpacity = FindSetting((Settings x) => x.motionVectors.motionImageOpacity),
|
||||
motionImageAmplitude = FindSetting((Settings x) => x.motionVectors.motionImageAmplitude),
|
||||
motionVectorsOpacity = FindSetting((Settings x) => x.motionVectors.motionVectorsOpacity),
|
||||
motionVectorsResolution = FindSetting((Settings x) => x.motionVectors.motionVectorsResolution),
|
||||
motionVectorsAmplitude = FindSetting((Settings x) => x.motionVectors.motionVectorsAmplitude),
|
||||
};
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_Mode);
|
||||
|
||||
int mode = m_Mode.intValue;
|
||||
|
||||
if (mode == (int)Mode.Depth)
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_Depth.scale);
|
||||
}
|
||||
else if (mode == (int)Mode.MotionVectors)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Switch to play mode to see motion vectors.", MessageType.Info);
|
||||
|
||||
EditorGUILayout.LabelField("Source Image", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_MotionVectors.sourceOpacity, EditorGUIHelper.GetContent("Opacity"));
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Motion Vectors (overlay)", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
if (m_MotionVectors.motionImageOpacity.floatValue > 0f)
|
||||
EditorGUILayout.HelpBox("Please keep opacity to 0 if you're subject to motion sickness.", MessageType.Warning);
|
||||
|
||||
EditorGUILayout.PropertyField(m_MotionVectors.motionImageOpacity, EditorGUIHelper.GetContent("Opacity"));
|
||||
EditorGUILayout.PropertyField(m_MotionVectors.motionImageAmplitude, EditorGUIHelper.GetContent("Amplitude"));
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Motion Vectors (arrows)", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_MotionVectors.motionVectorsOpacity, EditorGUIHelper.GetContent("Opacity"));
|
||||
EditorGUILayout.PropertyField(m_MotionVectors.motionVectorsResolution, EditorGUIHelper.GetContent("Resolution"));
|
||||
EditorGUILayout.PropertyField(m_MotionVectors.motionVectorsAmplitude, EditorGUIHelper.GetContent("Amplitude"));
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckActiveEffect(mode == (int)Mode.AmbientOcclusion && !profile.ambientOcclusion.enabled, "Ambient Occlusion");
|
||||
CheckActiveEffect(mode == (int)Mode.FocusPlane && !profile.depthOfField.enabled, "Depth Of Field");
|
||||
CheckActiveEffect(mode == (int)Mode.EyeAdaptation && !profile.eyeAdaptation.enabled, "Eye Adaptation");
|
||||
CheckActiveEffect((mode == (int)Mode.LogLut || mode == (int)Mode.PreGradingLog) && !profile.colorGrading.enabled, "Color Grading");
|
||||
CheckActiveEffect(mode == (int)Mode.UserLut && !profile.userLut.enabled, "User Lut");
|
||||
}
|
||||
}
|
||||
|
||||
void CheckActiveEffect(bool expr, string name)
|
||||
{
|
||||
if (expr)
|
||||
EditorGUILayout.HelpBox(string.Format("{0} isn't enabled, the debug view won't work.", name), MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 760ffebbef2ed644c87940a699eb7fe6
|
||||
timeCreated: 1468237035
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
[PostProcessingModelEditor(typeof(ChromaticAberrationModel))]
|
||||
public class ChromaticaAberrationModelEditor : DefaultPostFxModelEditor
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8a713f71a0169794a915a081f6242f60
|
||||
timeCreated: 1467190133
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,672 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using Settings = ColorGradingModel.Settings;
|
||||
using Tonemapper = ColorGradingModel.Tonemapper;
|
||||
using ColorWheelMode = ColorGradingModel.ColorWheelMode;
|
||||
|
||||
[PostProcessingModelEditor(typeof(ColorGradingModel))]
|
||||
public class ColorGradingModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
static GUIContent[] s_Tonemappers =
|
||||
{
|
||||
new GUIContent("None"),
|
||||
new GUIContent("Filmic (ACES)"),
|
||||
new GUIContent("Neutral")
|
||||
};
|
||||
|
||||
struct TonemappingSettings
|
||||
{
|
||||
public SerializedProperty tonemapper;
|
||||
public SerializedProperty neutralBlackIn;
|
||||
public SerializedProperty neutralWhiteIn;
|
||||
public SerializedProperty neutralBlackOut;
|
||||
public SerializedProperty neutralWhiteOut;
|
||||
public SerializedProperty neutralWhiteLevel;
|
||||
public SerializedProperty neutralWhiteClip;
|
||||
}
|
||||
|
||||
struct BasicSettings
|
||||
{
|
||||
public SerializedProperty exposure;
|
||||
public SerializedProperty temperature;
|
||||
public SerializedProperty tint;
|
||||
public SerializedProperty hueShift;
|
||||
public SerializedProperty saturation;
|
||||
public SerializedProperty contrast;
|
||||
}
|
||||
|
||||
struct ChannelMixerSettings
|
||||
{
|
||||
public SerializedProperty[] channels;
|
||||
public SerializedProperty currentEditingChannel;
|
||||
}
|
||||
|
||||
struct ColorWheelsSettings
|
||||
{
|
||||
public SerializedProperty mode;
|
||||
public SerializedProperty log;
|
||||
public SerializedProperty linear;
|
||||
}
|
||||
|
||||
static GUIContent[] s_Curves =
|
||||
{
|
||||
new GUIContent("YRGB"),
|
||||
new GUIContent("Hue VS Hue"),
|
||||
new GUIContent("Hue VS Sat"),
|
||||
new GUIContent("Sat VS Sat"),
|
||||
new GUIContent("Lum VS Sat")
|
||||
};
|
||||
|
||||
struct CurvesSettings
|
||||
{
|
||||
public SerializedProperty master;
|
||||
public SerializedProperty red;
|
||||
public SerializedProperty green;
|
||||
public SerializedProperty blue;
|
||||
|
||||
public SerializedProperty hueVShue;
|
||||
public SerializedProperty hueVSsat;
|
||||
public SerializedProperty satVSsat;
|
||||
public SerializedProperty lumVSsat;
|
||||
|
||||
public SerializedProperty currentEditingCurve;
|
||||
public SerializedProperty curveY;
|
||||
public SerializedProperty curveR;
|
||||
public SerializedProperty curveG;
|
||||
public SerializedProperty curveB;
|
||||
}
|
||||
|
||||
TonemappingSettings m_Tonemapping;
|
||||
BasicSettings m_Basic;
|
||||
ChannelMixerSettings m_ChannelMixer;
|
||||
ColorWheelsSettings m_ColorWheels;
|
||||
CurvesSettings m_Curves;
|
||||
|
||||
CurveEditor m_CurveEditor;
|
||||
Dictionary<SerializedProperty, Color> m_CurveDict;
|
||||
|
||||
// Neutral tonemapping curve helper
|
||||
const int k_CurveResolution = 24;
|
||||
const float k_NeutralRangeX = 2f;
|
||||
const float k_NeutralRangeY = 1f;
|
||||
Vector3[] m_RectVertices = new Vector3[4];
|
||||
Vector3[] m_LineVertices = new Vector3[2];
|
||||
Vector3[] m_CurveVertices = new Vector3[k_CurveResolution];
|
||||
Rect m_NeutralCurveRect;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
// Tonemapping settings
|
||||
m_Tonemapping = new TonemappingSettings
|
||||
{
|
||||
tonemapper = FindSetting((Settings x) => x.tonemapping.tonemapper),
|
||||
neutralBlackIn = FindSetting((Settings x) => x.tonemapping.neutralBlackIn),
|
||||
neutralWhiteIn = FindSetting((Settings x) => x.tonemapping.neutralWhiteIn),
|
||||
neutralBlackOut = FindSetting((Settings x) => x.tonemapping.neutralBlackOut),
|
||||
neutralWhiteOut = FindSetting((Settings x) => x.tonemapping.neutralWhiteOut),
|
||||
neutralWhiteLevel = FindSetting((Settings x) => x.tonemapping.neutralWhiteLevel),
|
||||
neutralWhiteClip = FindSetting((Settings x) => x.tonemapping.neutralWhiteClip)
|
||||
};
|
||||
|
||||
// Basic settings
|
||||
m_Basic = new BasicSettings
|
||||
{
|
||||
exposure = FindSetting((Settings x) => x.basic.postExposure),
|
||||
temperature = FindSetting((Settings x) => x.basic.temperature),
|
||||
tint = FindSetting((Settings x) => x.basic.tint),
|
||||
hueShift = FindSetting((Settings x) => x.basic.hueShift),
|
||||
saturation = FindSetting((Settings x) => x.basic.saturation),
|
||||
contrast = FindSetting((Settings x) => x.basic.contrast)
|
||||
};
|
||||
|
||||
// Channel mixer
|
||||
m_ChannelMixer = new ChannelMixerSettings
|
||||
{
|
||||
channels = new[]
|
||||
{
|
||||
FindSetting((Settings x) => x.channelMixer.red),
|
||||
FindSetting((Settings x) => x.channelMixer.green),
|
||||
FindSetting((Settings x) => x.channelMixer.blue)
|
||||
},
|
||||
currentEditingChannel = FindSetting((Settings x) => x.channelMixer.currentEditingChannel)
|
||||
};
|
||||
|
||||
// Color wheels
|
||||
m_ColorWheels = new ColorWheelsSettings
|
||||
{
|
||||
mode = FindSetting((Settings x) => x.colorWheels.mode),
|
||||
log = FindSetting((Settings x) => x.colorWheels.log),
|
||||
linear = FindSetting((Settings x) => x.colorWheels.linear)
|
||||
};
|
||||
|
||||
// Curves
|
||||
m_Curves = new CurvesSettings
|
||||
{
|
||||
master = FindSetting((Settings x) => x.curves.master.curve),
|
||||
red = FindSetting((Settings x) => x.curves.red.curve),
|
||||
green = FindSetting((Settings x) => x.curves.green.curve),
|
||||
blue = FindSetting((Settings x) => x.curves.blue.curve),
|
||||
|
||||
hueVShue = FindSetting((Settings x) => x.curves.hueVShue.curve),
|
||||
hueVSsat = FindSetting((Settings x) => x.curves.hueVSsat.curve),
|
||||
satVSsat = FindSetting((Settings x) => x.curves.satVSsat.curve),
|
||||
lumVSsat = FindSetting((Settings x) => x.curves.lumVSsat.curve),
|
||||
|
||||
currentEditingCurve = FindSetting((Settings x) => x.curves.e_CurrentEditingCurve),
|
||||
curveY = FindSetting((Settings x) => x.curves.e_CurveY),
|
||||
curveR = FindSetting((Settings x) => x.curves.e_CurveR),
|
||||
curveG = FindSetting((Settings x) => x.curves.e_CurveG),
|
||||
curveB = FindSetting((Settings x) => x.curves.e_CurveB)
|
||||
};
|
||||
|
||||
// Prepare the curve editor and extract curve display settings
|
||||
m_CurveDict = new Dictionary<SerializedProperty, Color>();
|
||||
|
||||
var settings = CurveEditor.Settings.defaultSettings;
|
||||
|
||||
m_CurveEditor = new CurveEditor(settings);
|
||||
AddCurve(m_Curves.master, new Color(1f, 1f, 1f), 2, false);
|
||||
AddCurve(m_Curves.red, new Color(1f, 0f, 0f), 2, false);
|
||||
AddCurve(m_Curves.green, new Color(0f, 1f, 0f), 2, false);
|
||||
AddCurve(m_Curves.blue, new Color(0f, 0.5f, 1f), 2, false);
|
||||
AddCurve(m_Curves.hueVShue, new Color(1f, 1f, 1f), 0, true);
|
||||
AddCurve(m_Curves.hueVSsat, new Color(1f, 1f, 1f), 0, true);
|
||||
AddCurve(m_Curves.satVSsat, new Color(1f, 1f, 1f), 0, false);
|
||||
AddCurve(m_Curves.lumVSsat, new Color(1f, 1f, 1f), 0, false);
|
||||
}
|
||||
|
||||
void AddCurve(SerializedProperty prop, Color color, uint minPointCount, bool loop)
|
||||
{
|
||||
var state = CurveEditor.CurveState.defaultState;
|
||||
state.color = color;
|
||||
state.visible = false;
|
||||
state.minPointCount = minPointCount;
|
||||
state.onlyShowHandlesOnSelection = true;
|
||||
state.zeroKeyConstantValue = 0.5f;
|
||||
state.loopInBounds = loop;
|
||||
m_CurveEditor.Add(prop, state);
|
||||
m_CurveDict.Add(prop, color);
|
||||
}
|
||||
|
||||
public override void OnDisable()
|
||||
{
|
||||
m_CurveEditor.RemoveAll();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DoGUIFor("Tonemapping", DoTonemappingGUI);
|
||||
EditorGUILayout.Space();
|
||||
DoGUIFor("Basic", DoBasicGUI);
|
||||
EditorGUILayout.Space();
|
||||
DoGUIFor("Channel Mixer", DoChannelMixerGUI);
|
||||
EditorGUILayout.Space();
|
||||
DoGUIFor("Trackballs", DoColorWheelsGUI);
|
||||
EditorGUILayout.Space();
|
||||
DoGUIFor("Grading Curves", DoCurvesGUI);
|
||||
}
|
||||
|
||||
void DoGUIFor(string title, Action func)
|
||||
{
|
||||
EditorGUILayout.LabelField(title, EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
func();
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
void DoTonemappingGUI()
|
||||
{
|
||||
int tid = EditorGUILayout.Popup(EditorGUIHelper.GetContent("Tonemapper"), m_Tonemapping.tonemapper.intValue, s_Tonemappers);
|
||||
|
||||
if (tid == (int)Tonemapper.Neutral)
|
||||
{
|
||||
DrawNeutralTonemappingCurve();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Tonemapping.neutralBlackIn, EditorGUIHelper.GetContent("Black In"));
|
||||
EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteIn, EditorGUIHelper.GetContent("White In"));
|
||||
EditorGUILayout.PropertyField(m_Tonemapping.neutralBlackOut, EditorGUIHelper.GetContent("Black Out"));
|
||||
EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteOut, EditorGUIHelper.GetContent("White Out"));
|
||||
EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteLevel, EditorGUIHelper.GetContent("White Level"));
|
||||
EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteClip, EditorGUIHelper.GetContent("White Clip"));
|
||||
}
|
||||
|
||||
m_Tonemapping.tonemapper.intValue = tid;
|
||||
}
|
||||
|
||||
void DrawNeutralTonemappingCurve()
|
||||
{
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.Space(EditorGUI.indentLevel * 15f);
|
||||
m_NeutralCurveRect = GUILayoutUtility.GetRect(128, 80);
|
||||
}
|
||||
|
||||
// Background
|
||||
m_RectVertices[0] = PointInRect( 0f, 0f);
|
||||
m_RectVertices[1] = PointInRect(k_NeutralRangeX, 0f);
|
||||
m_RectVertices[2] = PointInRect(k_NeutralRangeX, k_NeutralRangeY);
|
||||
m_RectVertices[3] = PointInRect( 0f, k_NeutralRangeY);
|
||||
|
||||
Handles.DrawSolidRectangleWithOutline(
|
||||
m_RectVertices,
|
||||
Color.white * 0.1f,
|
||||
Color.white * 0.4f
|
||||
);
|
||||
|
||||
// Horizontal lines
|
||||
for (var i = 1; i < k_NeutralRangeY; i++)
|
||||
DrawLine(0, i, k_NeutralRangeX, i, 0.4f);
|
||||
|
||||
// Vertical lines
|
||||
for (var i = 1; i < k_NeutralRangeX; i++)
|
||||
DrawLine(i, 0, i, k_NeutralRangeY, 0.4f);
|
||||
|
||||
// Label
|
||||
Handles.Label(
|
||||
PointInRect(0, k_NeutralRangeY) + Vector3.right,
|
||||
"Neutral Tonemapper", EditorStyles.miniLabel
|
||||
);
|
||||
|
||||
// Precompute some values
|
||||
var tonemap = ((ColorGradingModel)target).settings.tonemapping;
|
||||
|
||||
const float scaleFactor = 20f;
|
||||
const float scaleFactorHalf = scaleFactor * 0.5f;
|
||||
|
||||
float inBlack = tonemap.neutralBlackIn * scaleFactor + 1f;
|
||||
float outBlack = tonemap.neutralBlackOut * scaleFactorHalf + 1f;
|
||||
float inWhite = tonemap.neutralWhiteIn / scaleFactor;
|
||||
float outWhite = 1f - tonemap.neutralWhiteOut / scaleFactor;
|
||||
float blackRatio = inBlack / outBlack;
|
||||
float whiteRatio = inWhite / outWhite;
|
||||
|
||||
const float a = 0.2f;
|
||||
float b = Mathf.Max(0f, Mathf.LerpUnclamped(0.57f, 0.37f, blackRatio));
|
||||
float c = Mathf.LerpUnclamped(0.01f, 0.24f, whiteRatio);
|
||||
float d = Mathf.Max(0f, Mathf.LerpUnclamped(0.02f, 0.20f, blackRatio));
|
||||
const float e = 0.02f;
|
||||
const float f = 0.30f;
|
||||
float whiteLevel = tonemap.neutralWhiteLevel;
|
||||
float whiteClip = tonemap.neutralWhiteClip / scaleFactorHalf;
|
||||
|
||||
// Tonemapping curve
|
||||
var vcount = 0;
|
||||
while (vcount < k_CurveResolution)
|
||||
{
|
||||
float x = k_NeutralRangeX * vcount / (k_CurveResolution - 1);
|
||||
float y = NeutralTonemap(x, a, b, c, d, e, f, whiteLevel, whiteClip);
|
||||
|
||||
if (y < k_NeutralRangeY)
|
||||
{
|
||||
m_CurveVertices[vcount++] = PointInRect(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vcount > 1)
|
||||
{
|
||||
// Extend the last segment to the top edge of the rect.
|
||||
var v1 = m_CurveVertices[vcount - 2];
|
||||
var v2 = m_CurveVertices[vcount - 1];
|
||||
var clip = (m_NeutralCurveRect.y - v1.y) / (v2.y - v1.y);
|
||||
m_CurveVertices[vcount - 1] = v1 + (v2 - v1) * clip;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (vcount > 1)
|
||||
{
|
||||
Handles.color = Color.white * 0.9f;
|
||||
Handles.DrawAAPolyLine(2.0f, vcount, m_CurveVertices);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawLine(float x1, float y1, float x2, float y2, float grayscale)
|
||||
{
|
||||
m_LineVertices[0] = PointInRect(x1, y1);
|
||||
m_LineVertices[1] = PointInRect(x2, y2);
|
||||
Handles.color = Color.white * grayscale;
|
||||
Handles.DrawAAPolyLine(2f, m_LineVertices);
|
||||
}
|
||||
|
||||
Vector3 PointInRect(float x, float y)
|
||||
{
|
||||
x = Mathf.Lerp(m_NeutralCurveRect.x, m_NeutralCurveRect.xMax, x / k_NeutralRangeX);
|
||||
y = Mathf.Lerp(m_NeutralCurveRect.yMax, m_NeutralCurveRect.y, y / k_NeutralRangeY);
|
||||
return new Vector3(x, y, 0);
|
||||
}
|
||||
|
||||
float NeutralCurve(float x, float a, float b, float c, float d, float e, float f)
|
||||
{
|
||||
return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f;
|
||||
}
|
||||
|
||||
float NeutralTonemap(float x, float a, float b, float c, float d, float e, float f, float whiteLevel, float whiteClip)
|
||||
{
|
||||
x = Mathf.Max(0f, x);
|
||||
|
||||
// Tonemap
|
||||
float whiteScale = 1f / NeutralCurve(whiteLevel, a, b, c, d, e, f);
|
||||
x = NeutralCurve(x * whiteScale, a, b, c, d, e, f);
|
||||
x *= whiteScale;
|
||||
|
||||
// Post-curve white point adjustment
|
||||
x /= whiteClip;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void DoBasicGUI()
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_Basic.exposure, EditorGUIHelper.GetContent("Post Exposure (EV)"));
|
||||
EditorGUILayout.PropertyField(m_Basic.temperature);
|
||||
EditorGUILayout.PropertyField(m_Basic.tint);
|
||||
EditorGUILayout.PropertyField(m_Basic.hueShift);
|
||||
EditorGUILayout.PropertyField(m_Basic.saturation);
|
||||
EditorGUILayout.PropertyField(m_Basic.contrast);
|
||||
}
|
||||
|
||||
void DoChannelMixerGUI()
|
||||
{
|
||||
int currentChannel = m_ChannelMixer.currentEditingChannel.intValue;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
EditorGUILayout.PrefixLabel("Channel");
|
||||
if (GUILayout.Toggle(currentChannel == 0, EditorGUIHelper.GetContent("Red|Red output channel."), EditorStyles.miniButtonLeft)) currentChannel = 0;
|
||||
if (GUILayout.Toggle(currentChannel == 1, EditorGUIHelper.GetContent("Green|Green output channel."), EditorStyles.miniButtonMid)) currentChannel = 1;
|
||||
if (GUILayout.Toggle(currentChannel == 2, EditorGUIHelper.GetContent("Blue|Blue output channel."), EditorStyles.miniButtonRight)) currentChannel = 2;
|
||||
}
|
||||
}
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
GUI.FocusControl(null);
|
||||
}
|
||||
|
||||
var serializedChannel = m_ChannelMixer.channels[currentChannel];
|
||||
m_ChannelMixer.currentEditingChannel.intValue = currentChannel;
|
||||
|
||||
var v = serializedChannel.vector3Value;
|
||||
v.x = EditorGUILayout.Slider(EditorGUIHelper.GetContent("Red|Modify influence of the red channel within the overall mix."), v.x, -2f, 2f);
|
||||
v.y = EditorGUILayout.Slider(EditorGUIHelper.GetContent("Green|Modify influence of the green channel within the overall mix."), v.y, -2f, 2f);
|
||||
v.z = EditorGUILayout.Slider(EditorGUIHelper.GetContent("Blue|Modify influence of the blue channel within the overall mix."), v.z, -2f, 2f);
|
||||
serializedChannel.vector3Value = v;
|
||||
}
|
||||
|
||||
void DoColorWheelsGUI()
|
||||
{
|
||||
int wheelMode = m_ColorWheels.mode.intValue;
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.Space(15);
|
||||
if (GUILayout.Toggle(wheelMode == (int)ColorWheelMode.Linear, "Linear", EditorStyles.miniButtonLeft)) wheelMode = (int)ColorWheelMode.Linear;
|
||||
if (GUILayout.Toggle(wheelMode == (int)ColorWheelMode.Log, "Log", EditorStyles.miniButtonRight)) wheelMode = (int)ColorWheelMode.Log;
|
||||
}
|
||||
|
||||
m_ColorWheels.mode.intValue = wheelMode;
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (wheelMode == (int)ColorWheelMode.Linear)
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_ColorWheels.linear);
|
||||
WheelSetTitle(GUILayoutUtility.GetLastRect(), "Linear Controls");
|
||||
}
|
||||
else if (wheelMode == (int)ColorWheelMode.Log)
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_ColorWheels.log);
|
||||
WheelSetTitle(GUILayoutUtility.GetLastRect(), "Log Controls");
|
||||
}
|
||||
}
|
||||
|
||||
static void WheelSetTitle(Rect position, string label)
|
||||
{
|
||||
var matrix = GUI.matrix;
|
||||
var rect = new Rect(position.x - 10f, position.y, TrackballGroupDrawer.m_Size, TrackballGroupDrawer.m_Size);
|
||||
GUIUtility.RotateAroundPivot(-90f, rect.center);
|
||||
GUI.Label(rect, label, FxStyles.centeredMiniLabel);
|
||||
GUI.matrix = matrix;
|
||||
}
|
||||
|
||||
void ResetVisibleCurves()
|
||||
{
|
||||
foreach (var curve in m_CurveDict)
|
||||
{
|
||||
var state = m_CurveEditor.GetCurveState(curve.Key);
|
||||
state.visible = false;
|
||||
m_CurveEditor.SetCurveState(curve.Key, state);
|
||||
}
|
||||
}
|
||||
|
||||
void SetCurveVisible(SerializedProperty prop)
|
||||
{
|
||||
var state = m_CurveEditor.GetCurveState(prop);
|
||||
state.visible = true;
|
||||
m_CurveEditor.SetCurveState(prop, state);
|
||||
}
|
||||
|
||||
bool SpecialToggle(bool value, string name, out bool rightClicked)
|
||||
{
|
||||
var rect = GUILayoutUtility.GetRect(EditorGUIHelper.GetContent(name), EditorStyles.toolbarButton);
|
||||
|
||||
var e = Event.current;
|
||||
rightClicked = (e.type == EventType.MouseUp && rect.Contains(e.mousePosition) && e.button == 1);
|
||||
|
||||
return GUI.Toggle(rect, value, name, EditorStyles.toolbarButton);
|
||||
}
|
||||
|
||||
static Material s_MaterialSpline;
|
||||
|
||||
void DoCurvesGUI()
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorGUI.indentLevel -= 2;
|
||||
ResetVisibleCurves();
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(serializedProperty.serializedObject.isEditingMultipleObjects))
|
||||
{
|
||||
int curveEditingId = 0;
|
||||
|
||||
// Top toolbar
|
||||
using (new GUILayout.HorizontalScope(EditorStyles.toolbar))
|
||||
{
|
||||
curveEditingId = EditorGUILayout.Popup(m_Curves.currentEditingCurve.intValue, s_Curves, EditorStyles.toolbarPopup, GUILayout.MaxWidth(150f));
|
||||
bool y = false, r = false, g = false, b = false;
|
||||
|
||||
if (curveEditingId == 0)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
bool rightClickedY, rightClickedR, rightClickedG, rightClickedB;
|
||||
|
||||
y = SpecialToggle(m_Curves.curveY.boolValue, "Y", out rightClickedY);
|
||||
r = SpecialToggle(m_Curves.curveR.boolValue, "R", out rightClickedR);
|
||||
g = SpecialToggle(m_Curves.curveG.boolValue, "G", out rightClickedG);
|
||||
b = SpecialToggle(m_Curves.curveB.boolValue, "B", out rightClickedB);
|
||||
|
||||
if (!y && !r && !g && !b)
|
||||
{
|
||||
r = g = b = false;
|
||||
y = true;
|
||||
}
|
||||
|
||||
if (rightClickedY || rightClickedR || rightClickedG || rightClickedB)
|
||||
{
|
||||
y = rightClickedY;
|
||||
r = rightClickedR;
|
||||
g = rightClickedG;
|
||||
b = rightClickedB;
|
||||
}
|
||||
|
||||
if (y) SetCurveVisible(m_Curves.master);
|
||||
if (r) SetCurveVisible(m_Curves.red);
|
||||
if (g) SetCurveVisible(m_Curves.green);
|
||||
if (b) SetCurveVisible(m_Curves.blue);
|
||||
|
||||
m_Curves.curveY.boolValue = y;
|
||||
m_Curves.curveR.boolValue = r;
|
||||
m_Curves.curveG.boolValue = g;
|
||||
m_Curves.curveB.boolValue = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (curveEditingId)
|
||||
{
|
||||
case 1: SetCurveVisible(m_Curves.hueVShue);
|
||||
break;
|
||||
case 2: SetCurveVisible(m_Curves.hueVSsat);
|
||||
break;
|
||||
case 3: SetCurveVisible(m_Curves.satVSsat);
|
||||
break;
|
||||
case 4: SetCurveVisible(m_Curves.lumVSsat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
if (GUILayout.Button("Reset", EditorStyles.toolbarButton))
|
||||
{
|
||||
switch (curveEditingId)
|
||||
{
|
||||
case 0:
|
||||
if (y) m_Curves.master.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
|
||||
if (r) m_Curves.red.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
|
||||
if (g) m_Curves.green.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
|
||||
if (b) m_Curves.blue.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
|
||||
break;
|
||||
case 1: m_Curves.hueVShue.animationCurveValue = new AnimationCurve();
|
||||
break;
|
||||
case 2: m_Curves.hueVSsat.animationCurveValue = new AnimationCurve();
|
||||
break;
|
||||
case 3: m_Curves.satVSsat.animationCurveValue = new AnimationCurve();
|
||||
break;
|
||||
case 4: m_Curves.lumVSsat.animationCurveValue = new AnimationCurve();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_Curves.currentEditingCurve.intValue = curveEditingId;
|
||||
}
|
||||
|
||||
// Curve area
|
||||
var settings = m_CurveEditor.settings;
|
||||
var rect = GUILayoutUtility.GetAspectRect(2f);
|
||||
var innerRect = settings.padding.Remove(rect);
|
||||
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
// Background
|
||||
EditorGUI.DrawRect(rect, new Color(0.15f, 0.15f, 0.15f, 1f));
|
||||
|
||||
if (s_MaterialSpline == null)
|
||||
s_MaterialSpline = new Material(Shader.Find("Hidden/Post FX/UI/Curve Background")) { hideFlags = HideFlags.HideAndDontSave };
|
||||
|
||||
if (curveEditingId == 1 || curveEditingId == 2)
|
||||
DrawBackgroundTexture(innerRect, 0);
|
||||
else if (curveEditingId == 3 || curveEditingId == 4)
|
||||
DrawBackgroundTexture(innerRect, 1);
|
||||
|
||||
// Bounds
|
||||
Handles.color = Color.white;
|
||||
Handles.DrawSolidRectangleWithOutline(innerRect, Color.clear, new Color(0.8f, 0.8f, 0.8f, 0.5f));
|
||||
|
||||
// Grid setup
|
||||
Handles.color = new Color(1f, 1f, 1f, 0.05f);
|
||||
int hLines = (int)Mathf.Sqrt(innerRect.width);
|
||||
int vLines = (int)(hLines / (innerRect.width / innerRect.height));
|
||||
|
||||
// Vertical grid
|
||||
int gridOffset = Mathf.FloorToInt(innerRect.width / hLines);
|
||||
int gridPadding = ((int)(innerRect.width) % hLines) / 2;
|
||||
|
||||
for (int i = 1; i < hLines; i++)
|
||||
{
|
||||
var offset = i * Vector2.right * gridOffset;
|
||||
offset.x += gridPadding;
|
||||
Handles.DrawLine(innerRect.position + offset, new Vector2(innerRect.x, innerRect.yMax - 1) + offset);
|
||||
}
|
||||
|
||||
// Horizontal grid
|
||||
gridOffset = Mathf.FloorToInt(innerRect.height / vLines);
|
||||
gridPadding = ((int)(innerRect.height) % vLines) / 2;
|
||||
|
||||
for (int i = 1; i < vLines; i++)
|
||||
{
|
||||
var offset = i * Vector2.up * gridOffset;
|
||||
offset.y += gridPadding;
|
||||
Handles.DrawLine(innerRect.position + offset, new Vector2(innerRect.xMax - 1, innerRect.y) + offset);
|
||||
}
|
||||
}
|
||||
|
||||
// Curve editor
|
||||
if (m_CurveEditor.OnGUI(rect))
|
||||
{
|
||||
Repaint();
|
||||
GUI.changed = true;
|
||||
}
|
||||
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
// Borders
|
||||
Handles.color = Color.black;
|
||||
Handles.DrawLine(new Vector2(rect.x, rect.y - 18f), new Vector2(rect.xMax, rect.y - 18f));
|
||||
Handles.DrawLine(new Vector2(rect.x, rect.y - 19f), new Vector2(rect.x, rect.yMax));
|
||||
Handles.DrawLine(new Vector2(rect.x, rect.yMax), new Vector2(rect.xMax, rect.yMax));
|
||||
Handles.DrawLine(new Vector2(rect.xMax, rect.yMax), new Vector2(rect.xMax, rect.y - 18f));
|
||||
|
||||
// Selection info
|
||||
var selection = m_CurveEditor.GetSelection();
|
||||
|
||||
if (selection.curve != null && selection.keyframeIndex > -1)
|
||||
{
|
||||
var key = selection.keyframe.Value;
|
||||
var infoRect = innerRect;
|
||||
infoRect.x += 5f;
|
||||
infoRect.width = 100f;
|
||||
infoRect.height = 30f;
|
||||
GUI.Label(infoRect, string.Format("{0}\n{1}", key.time.ToString("F3"), key.value.ToString("F3")), FxStyles.preLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
EditorGUILayout.HelpBox(
|
||||
@"Curve editor cheat sheet:
|
||||
- [Del] or [Backspace] to remove a key
|
||||
- [Ctrl] to break a tangent handle
|
||||
- [Shift] to align tangent handles
|
||||
- [Double click] to create a key on the curve(s) at mouse position
|
||||
- [Alt] + [Double click] to create a key on the curve(s) at a given time",
|
||||
MessageType.Info);
|
||||
*/
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUI.indentLevel += 2;
|
||||
}
|
||||
|
||||
void DrawBackgroundTexture(Rect rect, int pass)
|
||||
{
|
||||
float scale = EditorGUIUtility.pixelsPerPoint;
|
||||
|
||||
var oldRt = RenderTexture.active;
|
||||
var rt = RenderTexture.GetTemporary(Mathf.CeilToInt(rect.width * scale), Mathf.CeilToInt(rect.height * scale), 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
|
||||
s_MaterialSpline.SetFloat("_DisabledState", GUI.enabled ? 1f : 0.5f);
|
||||
s_MaterialSpline.SetFloat("_PixelScaling", EditorGUIUtility.pixelsPerPoint);
|
||||
|
||||
Graphics.Blit(null, rt, s_MaterialSpline, pass);
|
||||
RenderTexture.active = oldRt;
|
||||
|
||||
GUI.DrawTexture(rect, rt);
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c3e3bce1d5c900d4fa7aa0f2b21814cf
|
||||
timeCreated: 1467190133
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,22 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
public class DefaultPostFxModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
List<SerializedProperty> m_Properties = new List<SerializedProperty>();
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
var iter = m_SettingsProperty.Copy().GetEnumerator();
|
||||
while (iter.MoveNext())
|
||||
m_Properties.Add(((SerializedProperty)iter.Current).Copy());
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
foreach (var property in m_Properties)
|
||||
EditorGUILayout.PropertyField(property);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c15016a7fef58974f91a6a4d6b132d94
|
||||
timeCreated: 1467190133
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,37 @@
|
|||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using Settings = DepthOfFieldModel.Settings;
|
||||
|
||||
[PostProcessingModelEditor(typeof(DepthOfFieldModel))]
|
||||
public class DepthOfFieldModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
SerializedProperty m_FocusDistance;
|
||||
SerializedProperty m_Aperture;
|
||||
SerializedProperty m_FocalLength;
|
||||
SerializedProperty m_UseCameraFov;
|
||||
SerializedProperty m_KernelSize;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_FocusDistance = FindSetting((Settings x) => x.focusDistance);
|
||||
m_Aperture = FindSetting((Settings x) => x.aperture);
|
||||
m_FocalLength = FindSetting((Settings x) => x.focalLength);
|
||||
m_UseCameraFov = FindSetting((Settings x) => x.useCameraFov);
|
||||
m_KernelSize = FindSetting((Settings x) => x.kernelSize);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_FocusDistance);
|
||||
EditorGUILayout.PropertyField(m_Aperture, EditorGUIHelper.GetContent("Aperture (f-stop)"));
|
||||
|
||||
EditorGUILayout.PropertyField(m_UseCameraFov, EditorGUIHelper.GetContent("Use Camera FOV"));
|
||||
if (!m_UseCameraFov.boolValue)
|
||||
EditorGUILayout.PropertyField(m_FocalLength, EditorGUIHelper.GetContent("Focal Length (mm)"));
|
||||
|
||||
EditorGUILayout.PropertyField(m_KernelSize);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dc2f388440e9f8b4f8fc7bb43c01cc7d
|
||||
timeCreated: 1467190133
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,16 @@
|
|||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
[PostProcessingModelEditor(typeof(DitheringModel))]
|
||||
public class DitheringModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (profile.grain.enabled && target.enabled)
|
||||
EditorGUILayout.HelpBox("Grain is enabled, you probably don't need dithering !", MessageType.Warning);
|
||||
else
|
||||
EditorGUILayout.HelpBox("Nothing to configure !", MessageType.Info);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 87377c86d84f49a4e912d37d28353e7f
|
||||
timeCreated: 1485179854
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,86 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using Settings = EyeAdaptationModel.Settings;
|
||||
|
||||
[PostProcessingModelEditor(typeof(EyeAdaptationModel))]
|
||||
public class EyeAdaptationModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
SerializedProperty m_LowPercent;
|
||||
SerializedProperty m_HighPercent;
|
||||
SerializedProperty m_MinLuminance;
|
||||
SerializedProperty m_MaxLuminance;
|
||||
SerializedProperty m_KeyValue;
|
||||
SerializedProperty m_DynamicKeyValue;
|
||||
SerializedProperty m_AdaptationType;
|
||||
SerializedProperty m_SpeedUp;
|
||||
SerializedProperty m_SpeedDown;
|
||||
SerializedProperty m_LogMin;
|
||||
SerializedProperty m_LogMax;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_LowPercent = FindSetting((Settings x) => x.lowPercent);
|
||||
m_HighPercent = FindSetting((Settings x) => x.highPercent);
|
||||
m_MinLuminance = FindSetting((Settings x) => x.minLuminance);
|
||||
m_MaxLuminance = FindSetting((Settings x) => x.maxLuminance);
|
||||
m_KeyValue = FindSetting((Settings x) => x.keyValue);
|
||||
m_DynamicKeyValue = FindSetting((Settings x) => x.dynamicKeyValue);
|
||||
m_AdaptationType = FindSetting((Settings x) => x.adaptationType);
|
||||
m_SpeedUp = FindSetting((Settings x) => x.speedUp);
|
||||
m_SpeedDown = FindSetting((Settings x) => x.speedDown);
|
||||
m_LogMin = FindSetting((Settings x) => x.logMin);
|
||||
m_LogMax = FindSetting((Settings x) => x.logMax);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (!GraphicsUtils.supportsDX11)
|
||||
EditorGUILayout.HelpBox("This effect requires support for compute shaders. Enabling it won't do anything on unsupported platforms.", MessageType.Warning);
|
||||
|
||||
EditorGUILayout.LabelField("Luminosity range", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_LogMin, EditorGUIHelper.GetContent("Minimum (EV)"));
|
||||
EditorGUILayout.PropertyField(m_LogMax, EditorGUIHelper.GetContent("Maximum (EV)"));
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Auto exposure", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
float low = m_LowPercent.floatValue;
|
||||
float high = m_HighPercent.floatValue;
|
||||
|
||||
EditorGUILayout.MinMaxSlider(EditorGUIHelper.GetContent("Histogram filtering|These values are the lower and upper percentages of the histogram that will be used to find a stable average luminance. Values outside of this range will be discarded and won't contribute to the average luminance."), ref low, ref high, 1f, 99f);
|
||||
|
||||
m_LowPercent.floatValue = low;
|
||||
m_HighPercent.floatValue = high;
|
||||
|
||||
EditorGUILayout.PropertyField(m_MinLuminance, EditorGUIHelper.GetContent("Minimum (EV)"));
|
||||
EditorGUILayout.PropertyField(m_MaxLuminance, EditorGUIHelper.GetContent("Maximum (EV)"));
|
||||
EditorGUILayout.PropertyField(m_DynamicKeyValue);
|
||||
|
||||
if (!m_DynamicKeyValue.boolValue)
|
||||
EditorGUILayout.PropertyField(m_KeyValue);
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Adaptation", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
EditorGUILayout.PropertyField(m_AdaptationType, EditorGUIHelper.GetContent("Type"));
|
||||
|
||||
if (m_AdaptationType.intValue == (int)EyeAdaptationModel.EyeAdaptationType.Progressive)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_SpeedUp);
|
||||
EditorGUILayout.PropertyField(m_SpeedDown);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 489b5c785ba0f614d90c322fa0827216
|
||||
timeCreated: 1467190133
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,24 @@
|
|||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using Settings = FogModel.Settings;
|
||||
|
||||
[PostProcessingModelEditor(typeof(FogModel))]
|
||||
public class FogModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
SerializedProperty m_ExcludeSkybox;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_ExcludeSkybox = FindSetting((Settings x) => x.excludeSkybox);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.HelpBox("This effect adds fog compatibility to the deferred rendering path; enabling it with the forward rendering path won't have any effect. Actual fog settings should be set in the Lighting panel.", MessageType.Info);
|
||||
EditorGUILayout.PropertyField(m_ExcludeSkybox);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 44a64b44ec891d24b96ed84d958c3d4f
|
||||
timeCreated: 1487335049
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,31 @@
|
|||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using Settings = GrainModel.Settings;
|
||||
|
||||
[PostProcessingModelEditor(typeof(GrainModel))]
|
||||
public class GrainModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
SerializedProperty m_Colored;
|
||||
SerializedProperty m_Intensity;
|
||||
SerializedProperty m_Size;
|
||||
SerializedProperty m_LuminanceContribution;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_Colored = FindSetting((Settings x) => x.colored);
|
||||
m_Intensity = FindSetting((Settings x) => x.intensity);
|
||||
m_Size = FindSetting((Settings x) => x.size);
|
||||
m_LuminanceContribution = FindSetting((Settings x) => x.luminanceContribution);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_Intensity);
|
||||
EditorGUILayout.PropertyField(m_LuminanceContribution);
|
||||
EditorGUILayout.PropertyField(m_Size);
|
||||
EditorGUILayout.PropertyField(m_Colored);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8330694e2c90c284f81153ac83b3cb4a
|
||||
timeCreated: 1467190133
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,197 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using Settings = MotionBlurModel.Settings;
|
||||
|
||||
[PostProcessingModelEditor(typeof(MotionBlurModel))]
|
||||
public class MotionBlurModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
SerializedProperty m_ShutterAngle;
|
||||
SerializedProperty m_SampleCount;
|
||||
SerializedProperty m_FrameBlending;
|
||||
|
||||
GraphDrawer m_GraphDrawer;
|
||||
|
||||
class GraphDrawer
|
||||
{
|
||||
const float k_Height = 32f;
|
||||
|
||||
Texture m_BlendingIcon;
|
||||
|
||||
GUIStyle m_LowerCenterStyle;
|
||||
GUIStyle m_MiddleCenterStyle;
|
||||
|
||||
Color m_ColorDark;
|
||||
Color m_ColorGray;
|
||||
|
||||
Vector3[] m_RectVertices = new Vector3[4];
|
||||
|
||||
public GraphDrawer()
|
||||
{
|
||||
m_BlendingIcon = EditorResources.Load<Texture>("UI/MotionBlendingIcon.png");
|
||||
|
||||
m_LowerCenterStyle = new GUIStyle(EditorStyles.miniLabel) { alignment = TextAnchor.LowerCenter };
|
||||
m_MiddleCenterStyle = new GUIStyle(EditorStyles.miniLabel) { alignment = TextAnchor.MiddleCenter };
|
||||
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
{
|
||||
m_ColorDark = new Color(0.18f, 0.18f, 0.18f);
|
||||
m_ColorGray = new Color(0.43f, 0.43f, 0.43f);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ColorDark = new Color(0.64f, 0.64f, 0.64f);
|
||||
m_ColorGray = new Color(0.92f, 0.92f, 0.92f);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawShutterGraph(float angle)
|
||||
{
|
||||
var center = GUILayoutUtility.GetRect(128, k_Height).center;
|
||||
|
||||
// Parameters used to make transitions smooth.
|
||||
var zeroWhenOff = Mathf.Min(1f, angle * 0.1f);
|
||||
var zeroWhenFull = Mathf.Min(1f, (360f - angle) * 0.02f);
|
||||
|
||||
// Shutter angle graph
|
||||
var discCenter = center - new Vector2(k_Height * 2.4f, 0f);
|
||||
// - exposure duration indicator
|
||||
DrawDisc(discCenter, k_Height * Mathf.Lerp(0.5f, 0.38f, zeroWhenFull), m_ColorGray);
|
||||
// - shutter disc
|
||||
DrawDisc(discCenter, k_Height * 0.16f * zeroWhenFull, m_ColorDark);
|
||||
// - shutter blade
|
||||
DrawArc(discCenter, k_Height * 0.5f, 360f - angle, m_ColorDark);
|
||||
// - shutter axis
|
||||
DrawDisc(discCenter, zeroWhenOff, m_ColorGray);
|
||||
|
||||
// Shutter label (off/full)
|
||||
var labelSize = new Vector2(k_Height, k_Height);
|
||||
var labelOrigin = discCenter - labelSize * 0.5f;
|
||||
var labelRect = new Rect(labelOrigin, labelSize);
|
||||
|
||||
if (Mathf.Approximately(angle, 0f))
|
||||
GUI.Label(labelRect, "Off", m_MiddleCenterStyle);
|
||||
else if (Mathf.Approximately(angle, 360f))
|
||||
GUI.Label(labelRect, "Full", m_MiddleCenterStyle);
|
||||
|
||||
// Exposure time bar graph
|
||||
var outerBarSize = new Vector2(4.75f, 0.5f) * k_Height;
|
||||
var innerBarSize = outerBarSize;
|
||||
innerBarSize.x *= angle / 360f;
|
||||
|
||||
var barCenter = center + new Vector2(k_Height * 0.9f, 0f);
|
||||
var barOrigin = barCenter - outerBarSize * 0.5f;
|
||||
|
||||
DrawRect(barOrigin, outerBarSize, m_ColorDark);
|
||||
DrawRect(barOrigin, innerBarSize, m_ColorGray);
|
||||
|
||||
var barText = "Exposure time = " + (angle / 3.6f).ToString("0") + "% of ΔT";
|
||||
GUI.Label(new Rect(barOrigin, outerBarSize), barText, m_MiddleCenterStyle);
|
||||
}
|
||||
|
||||
public void DrawBlendingGraph(float strength)
|
||||
{
|
||||
var center = GUILayoutUtility.GetRect(128, k_Height).center;
|
||||
|
||||
var iconSize = new Vector2(k_Height, k_Height);
|
||||
var iconStride = new Vector2(k_Height * 0.9f, 0f);
|
||||
var iconOrigin = center - iconSize * 0.5f - iconStride * 2f;
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
var weight = BlendingWeight(strength, i / 60f);
|
||||
var rect = new Rect(iconOrigin + iconStride * i, iconSize);
|
||||
|
||||
var color = m_ColorGray;
|
||||
color.a = weight;
|
||||
|
||||
GUI.color = color;
|
||||
GUI.Label(rect, m_BlendingIcon);
|
||||
|
||||
GUI.color = Color.white;
|
||||
GUI.Label(rect, (weight * 100).ToString("0") + "%", m_LowerCenterStyle);
|
||||
}
|
||||
// EditorGUIUtility.isProSkin
|
||||
}
|
||||
|
||||
// Weight function for multi frame blending
|
||||
float BlendingWeight(float strength, float time)
|
||||
{
|
||||
if (strength > 0f || Mathf.Approximately(time, 0f))
|
||||
return Mathf.Exp(-time * Mathf.Lerp(80f, 10f, strength));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Draw a solid disc in the graph rect.
|
||||
void DrawDisc(Vector2 center, float radius, Color fill)
|
||||
{
|
||||
Handles.color = fill;
|
||||
Handles.DrawSolidDisc(center, Vector3.forward, radius);
|
||||
}
|
||||
|
||||
// Draw an arc in the graph rect.
|
||||
void DrawArc(Vector2 center, float radius, float angle, Color fill)
|
||||
{
|
||||
var start = new Vector2(
|
||||
-Mathf.Cos(Mathf.Deg2Rad * angle / 2f),
|
||||
Mathf.Sin(Mathf.Deg2Rad * angle / 2f)
|
||||
);
|
||||
|
||||
Handles.color = fill;
|
||||
Handles.DrawSolidArc(center, Vector3.forward, start, angle, radius);
|
||||
}
|
||||
|
||||
// Draw a rectangle in the graph rect.
|
||||
void DrawRect(Vector2 origin, Vector2 size, Color color)
|
||||
{
|
||||
var p0 = origin;
|
||||
var p1 = origin + size;
|
||||
|
||||
m_RectVertices[0] = p0;
|
||||
m_RectVertices[1] = new Vector2(p1.x, p0.y);
|
||||
m_RectVertices[2] = p1;
|
||||
m_RectVertices[3] = new Vector2(p0.x, p1.y);
|
||||
|
||||
Handles.color = Color.white;
|
||||
Handles.DrawSolidRectangleWithOutline(m_RectVertices, color, Color.clear);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_ShutterAngle = FindSetting((Settings x) => x.shutterAngle);
|
||||
m_SampleCount = FindSetting((Settings x) => x.sampleCount);
|
||||
m_FrameBlending = FindSetting((Settings x) => x.frameBlending);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (m_GraphDrawer == null)
|
||||
m_GraphDrawer = new GraphDrawer();
|
||||
|
||||
EditorGUILayout.LabelField("Shutter Speed Simulation", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
m_GraphDrawer.DrawShutterGraph(m_ShutterAngle.floatValue);
|
||||
EditorGUILayout.PropertyField(m_ShutterAngle);
|
||||
EditorGUILayout.PropertyField(m_SampleCount);
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Multiple Frame Blending", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
float fbValue = m_FrameBlending.floatValue;
|
||||
m_GraphDrawer.DrawBlendingGraph(fbValue);
|
||||
EditorGUILayout.PropertyField(m_FrameBlending);
|
||||
|
||||
if (fbValue > 0f)
|
||||
EditorGUILayout.HelpBox("Multi-Frame Blending lowers precision of the final picture for optimization purposes.", MessageType.Info);
|
||||
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 870806eda355b5144879155e2ba37eb6
|
||||
timeCreated: 1468325681
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,100 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using Settings = ScreenSpaceReflectionModel.Settings;
|
||||
|
||||
[PostProcessingModelEditor(typeof(ScreenSpaceReflectionModel))]
|
||||
public class ScreenSpaceReflectionModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
struct IntensitySettings
|
||||
{
|
||||
public SerializedProperty reflectionMultiplier;
|
||||
public SerializedProperty fadeDistance;
|
||||
public SerializedProperty fresnelFade;
|
||||
public SerializedProperty fresnelFadePower;
|
||||
}
|
||||
|
||||
struct ReflectionSettings
|
||||
{
|
||||
public SerializedProperty blendType;
|
||||
public SerializedProperty reflectionQuality;
|
||||
public SerializedProperty maxDistance;
|
||||
public SerializedProperty iterationCount;
|
||||
public SerializedProperty stepSize;
|
||||
public SerializedProperty widthModifier;
|
||||
public SerializedProperty reflectionBlur;
|
||||
public SerializedProperty reflectBackfaces;
|
||||
}
|
||||
|
||||
struct ScreenEdgeMask
|
||||
{
|
||||
public SerializedProperty intensity;
|
||||
}
|
||||
|
||||
IntensitySettings m_Intensity;
|
||||
ReflectionSettings m_Reflection;
|
||||
ScreenEdgeMask m_ScreenEdgeMask;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_Intensity = new IntensitySettings
|
||||
{
|
||||
reflectionMultiplier = FindSetting((Settings x) => x.intensity.reflectionMultiplier),
|
||||
fadeDistance = FindSetting((Settings x) => x.intensity.fadeDistance),
|
||||
fresnelFade = FindSetting((Settings x) => x.intensity.fresnelFade),
|
||||
fresnelFadePower = FindSetting((Settings x) => x.intensity.fresnelFadePower)
|
||||
};
|
||||
|
||||
m_Reflection = new ReflectionSettings
|
||||
{
|
||||
blendType = FindSetting((Settings x) => x.reflection.blendType),
|
||||
reflectionQuality = FindSetting((Settings x) => x.reflection.reflectionQuality),
|
||||
maxDistance = FindSetting((Settings x) => x.reflection.maxDistance),
|
||||
iterationCount = FindSetting((Settings x) => x.reflection.iterationCount),
|
||||
stepSize = FindSetting((Settings x) => x.reflection.stepSize),
|
||||
widthModifier = FindSetting((Settings x) => x.reflection.widthModifier),
|
||||
reflectionBlur = FindSetting((Settings x) => x.reflection.reflectionBlur),
|
||||
reflectBackfaces = FindSetting((Settings x) => x.reflection.reflectBackfaces)
|
||||
};
|
||||
|
||||
m_ScreenEdgeMask = new ScreenEdgeMask
|
||||
{
|
||||
intensity = FindSetting((Settings x) => x.screenEdgeMask.intensity)
|
||||
};
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.HelpBox("This effect only works with the deferred rendering path.", MessageType.Info);
|
||||
|
||||
EditorGUILayout.LabelField("Reflection", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_Reflection.blendType);
|
||||
EditorGUILayout.PropertyField(m_Reflection.reflectionQuality);
|
||||
EditorGUILayout.PropertyField(m_Reflection.maxDistance);
|
||||
EditorGUILayout.PropertyField(m_Reflection.iterationCount);
|
||||
EditorGUILayout.PropertyField(m_Reflection.stepSize);
|
||||
EditorGUILayout.PropertyField(m_Reflection.widthModifier);
|
||||
EditorGUILayout.PropertyField(m_Reflection.reflectionBlur);
|
||||
EditorGUILayout.PropertyField(m_Reflection.reflectBackfaces);
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Intensity", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_Intensity.reflectionMultiplier);
|
||||
EditorGUILayout.PropertyField(m_Intensity.fadeDistance);
|
||||
EditorGUILayout.PropertyField(m_Intensity.fresnelFade);
|
||||
EditorGUILayout.PropertyField(m_Intensity.fresnelFadePower);
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Screen Edge Mask", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(m_ScreenEdgeMask.intensity);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 57bbe1f20eec7bb4d9bc90fc65ef381b
|
||||
timeCreated: 1467190133
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,87 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using Settings = UserLutModel.Settings;
|
||||
|
||||
[PostProcessingModelEditor(typeof(UserLutModel))]
|
||||
public class UserLutModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
SerializedProperty m_Texture;
|
||||
SerializedProperty m_Contribution;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_Texture = FindSetting((Settings x) => x.lut);
|
||||
m_Contribution = FindSetting((Settings x) => x.contribution);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var lut = (target as UserLutModel).settings.lut;
|
||||
|
||||
// Checks import settings on the lut, offers to fix them if invalid
|
||||
if (lut != null)
|
||||
{
|
||||
var importer = (TextureImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(lut));
|
||||
|
||||
if (importer != null) // Fails when using an internal texture
|
||||
{
|
||||
#if UNITY_5_5_OR_NEWER
|
||||
bool valid = importer.anisoLevel == 0
|
||||
&& importer.mipmapEnabled == false
|
||||
&& importer.sRGBTexture == false
|
||||
&& (importer.textureCompression == TextureImporterCompression.Uncompressed);
|
||||
#else
|
||||
bool valid = importer.anisoLevel == 0
|
||||
&& importer.mipmapEnabled == false
|
||||
&& importer.linearTexture == true
|
||||
&& (importer.textureFormat == TextureImporterFormat.RGB24 || importer.textureFormat == TextureImporterFormat.AutomaticTruecolor);
|
||||
#endif
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Invalid LUT import settings.", MessageType.Warning);
|
||||
|
||||
GUILayout.Space(-32);
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button("Fix", GUILayout.Width(60)))
|
||||
{
|
||||
SetLUTImportSettings(importer);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
GUILayout.Space(8);
|
||||
}
|
||||
GUILayout.Space(11);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Texture.objectReferenceValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(m_Texture);
|
||||
EditorGUILayout.PropertyField(m_Contribution);
|
||||
}
|
||||
|
||||
void SetLUTImportSettings(TextureImporter importer)
|
||||
{
|
||||
#if UNITY_5_5_OR_NEWER
|
||||
importer.textureType = TextureImporterType.Default;
|
||||
importer.sRGBTexture = false;
|
||||
importer.textureCompression = TextureImporterCompression.Uncompressed;
|
||||
#else
|
||||
importer.textureType = TextureImporterType.Advanced;
|
||||
importer.linearTexture = true;
|
||||
importer.textureFormat = TextureImporterFormat.RGB24;
|
||||
#endif
|
||||
importer.anisoLevel = 0;
|
||||
importer.mipmapEnabled = false;
|
||||
importer.SaveAndReimport();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b235eb1c486b38c4fa06470234bbfd32
|
||||
timeCreated: 1466769818
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,118 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using VignetteMode = VignetteModel.Mode;
|
||||
using Settings = VignetteModel.Settings;
|
||||
|
||||
[PostProcessingModelEditor(typeof(VignetteModel))]
|
||||
public class VignetteModelEditor : PostProcessingModelEditor
|
||||
{
|
||||
SerializedProperty m_Mode;
|
||||
SerializedProperty m_Color;
|
||||
SerializedProperty m_Center;
|
||||
SerializedProperty m_Intensity;
|
||||
SerializedProperty m_Smoothness;
|
||||
SerializedProperty m_Roundness;
|
||||
SerializedProperty m_Mask;
|
||||
SerializedProperty m_Opacity;
|
||||
SerializedProperty m_Rounded;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
m_Mode = FindSetting((Settings x) => x.mode);
|
||||
m_Color = FindSetting((Settings x) => x.color);
|
||||
m_Center = FindSetting((Settings x) => x.center);
|
||||
m_Intensity = FindSetting((Settings x) => x.intensity);
|
||||
m_Smoothness = FindSetting((Settings x) => x.smoothness);
|
||||
m_Roundness = FindSetting((Settings x) => x.roundness);
|
||||
m_Mask = FindSetting((Settings x) => x.mask);
|
||||
m_Opacity = FindSetting((Settings x) => x.opacity);
|
||||
m_Rounded = FindSetting((Settings x) => x.rounded);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_Mode);
|
||||
EditorGUILayout.PropertyField(m_Color);
|
||||
|
||||
if (m_Mode.intValue < (int)VignetteMode.Masked)
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_Center);
|
||||
EditorGUILayout.PropertyField(m_Intensity);
|
||||
EditorGUILayout.PropertyField(m_Smoothness);
|
||||
EditorGUILayout.PropertyField(m_Roundness);
|
||||
EditorGUILayout.PropertyField(m_Rounded);
|
||||
}
|
||||
else
|
||||
{
|
||||
var mask = (target as VignetteModel).settings.mask;
|
||||
|
||||
// Checks import settings on the mask, offers to fix them if invalid
|
||||
if (mask != null)
|
||||
{
|
||||
var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(mask)) as TextureImporter;
|
||||
|
||||
if (importer != null) // Fails when using an internal texture
|
||||
{
|
||||
#if UNITY_5_5_OR_NEWER
|
||||
bool valid = importer.anisoLevel == 0
|
||||
&& importer.mipmapEnabled == false
|
||||
//&& importer.alphaUsage == TextureImporterAlphaUsage.FromGrayScale
|
||||
&& importer.alphaSource == TextureImporterAlphaSource.FromGrayScale
|
||||
&& importer.textureCompression == TextureImporterCompression.Uncompressed
|
||||
&& importer.wrapMode == TextureWrapMode.Clamp;
|
||||
#else
|
||||
bool valid = importer.anisoLevel == 0
|
||||
&& importer.mipmapEnabled == false
|
||||
&& importer.grayscaleToAlpha == true
|
||||
&& importer.textureFormat == TextureImporterFormat.Alpha8
|
||||
&& importer.wrapMode == TextureWrapMode.Clamp;
|
||||
#endif
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Invalid mask import settings.", MessageType.Warning);
|
||||
|
||||
GUILayout.Space(-32);
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button("Fix", GUILayout.Width(60)))
|
||||
{
|
||||
SetMaskImportSettings(importer);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
GUILayout.Space(8);
|
||||
}
|
||||
GUILayout.Space(11);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(m_Mask);
|
||||
EditorGUILayout.PropertyField(m_Opacity);
|
||||
}
|
||||
}
|
||||
|
||||
void SetMaskImportSettings(TextureImporter importer)
|
||||
{
|
||||
#if UNITY_5_5_OR_NEWER
|
||||
importer.textureType = TextureImporterType.SingleChannel;
|
||||
//importer.alphaUsage = TextureImporterAlphaUsage.FromGrayScale;
|
||||
importer.alphaSource = TextureImporterAlphaSource.FromGrayScale;
|
||||
importer.textureCompression = TextureImporterCompression.Uncompressed;
|
||||
#else
|
||||
importer.textureType = TextureImporterType.Advanced;
|
||||
importer.grayscaleToAlpha = true;
|
||||
importer.textureFormat = TextureImporterFormat.Alpha8;
|
||||
#endif
|
||||
|
||||
importer.anisoLevel = 0;
|
||||
importer.mipmapEnabled = false;
|
||||
importer.wrapMode = TextureWrapMode.Clamp;
|
||||
importer.SaveAndReimport();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 745ad42620dabf04b94761acc86189ba
|
||||
timeCreated: 1467190133
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e31078d57ac582944ad5e1e76a84f36a
|
||||
folderAsset: yes
|
||||
timeCreated: 1467188891
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,338 @@
|
|||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using HistogramMode = PostProcessingProfile.MonitorSettings.HistogramMode;
|
||||
|
||||
public class HistogramMonitor : PostProcessingMonitor
|
||||
{
|
||||
static GUIContent s_MonitorTitle = new GUIContent("Histogram");
|
||||
|
||||
ComputeShader m_ComputeShader;
|
||||
ComputeBuffer m_Buffer;
|
||||
Material m_Material;
|
||||
RenderTexture m_HistogramTexture;
|
||||
Rect m_MonitorAreaRect;
|
||||
|
||||
public HistogramMonitor()
|
||||
{
|
||||
m_ComputeShader = EditorResources.Load<ComputeShader>("Monitors/HistogramCompute.compute");
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
GraphicsUtils.Destroy(m_Material);
|
||||
GraphicsUtils.Destroy(m_HistogramTexture);
|
||||
|
||||
if (m_Buffer != null)
|
||||
m_Buffer.Release();
|
||||
|
||||
m_Material = null;
|
||||
m_HistogramTexture = null;
|
||||
m_Buffer = null;
|
||||
}
|
||||
|
||||
public override bool IsSupported()
|
||||
{
|
||||
return m_ComputeShader != null && GraphicsUtils.supportsDX11;
|
||||
}
|
||||
|
||||
public override GUIContent GetMonitorTitle()
|
||||
{
|
||||
return s_MonitorTitle;
|
||||
}
|
||||
|
||||
public override void OnMonitorSettings()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
bool refreshOnPlay = m_MonitorSettings.refreshOnPlay;
|
||||
var mode = m_MonitorSettings.histogramMode;
|
||||
|
||||
refreshOnPlay = GUILayout.Toggle(refreshOnPlay, new GUIContent(FxStyles.playIcon, "Keep refreshing the histogram in play mode; this may impact performances."), FxStyles.preButton);
|
||||
mode = (HistogramMode)EditorGUILayout.EnumPopup(mode, FxStyles.preDropdown, GUILayout.MaxWidth(100f));
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(m_BaseEditor.serializedObject.targetObject, "Histogram Settings Changed");
|
||||
m_MonitorSettings.refreshOnPlay = refreshOnPlay;
|
||||
m_MonitorSettings.histogramMode = mode;
|
||||
InternalEditorUtility.RepaintAllViews();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMonitorGUI(Rect r)
|
||||
{
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
// If m_MonitorAreaRect isn't set the preview was just opened so refresh the render to get the histogram data
|
||||
if (Mathf.Approximately(m_MonitorAreaRect.width, 0) && Mathf.Approximately(m_MonitorAreaRect.height, 0))
|
||||
InternalEditorUtility.RepaintAllViews();
|
||||
|
||||
// Sizing
|
||||
float width = m_HistogramTexture != null
|
||||
? Mathf.Min(m_HistogramTexture.width, r.width - 65f)
|
||||
: r.width;
|
||||
float height = m_HistogramTexture != null
|
||||
? Mathf.Min(m_HistogramTexture.height, r.height - 45f)
|
||||
: r.height;
|
||||
|
||||
m_MonitorAreaRect = new Rect(
|
||||
Mathf.Floor(r.x + r.width / 2f - width / 2f),
|
||||
Mathf.Floor(r.y + r.height / 2f - height / 2f - 5f),
|
||||
width, height
|
||||
);
|
||||
|
||||
if (m_HistogramTexture != null)
|
||||
{
|
||||
Graphics.DrawTexture(m_MonitorAreaRect, m_HistogramTexture);
|
||||
|
||||
var color = Color.white;
|
||||
const float kTickSize = 5f;
|
||||
|
||||
// Rect, lines & ticks points
|
||||
if (m_MonitorSettings.histogramMode == HistogramMode.RGBSplit)
|
||||
{
|
||||
// A B C D E
|
||||
// N F
|
||||
// M G
|
||||
// L K J I H
|
||||
|
||||
var A = new Vector3(m_MonitorAreaRect.x - 1f, m_MonitorAreaRect.y - 1f);
|
||||
var E = new Vector3(A.x + m_MonitorAreaRect.width + 2f, m_MonitorAreaRect.y - 1f);
|
||||
var H = new Vector3(E.x, E.y + m_MonitorAreaRect.height + 2f);
|
||||
var L = new Vector3(A.x, H.y);
|
||||
|
||||
var N = new Vector3(A.x, A.y + (L.y - A.y) / 3f);
|
||||
var M = new Vector3(A.x, A.y + (L.y - A.y) * 2f / 3f);
|
||||
var F = new Vector3(E.x, E.y + (H.y - E.y) / 3f);
|
||||
var G = new Vector3(E.x, E.y + (H.y - E.y) * 2f / 3f);
|
||||
|
||||
var C = new Vector3(A.x + (E.x - A.x) / 2f, A.y);
|
||||
var J = new Vector3(L.x + (H.x - L.x) / 2f, L.y);
|
||||
|
||||
var B = new Vector3(A.x + (C.x - A.x) / 2f, A.y);
|
||||
var D = new Vector3(C.x + (E.x - C.x) / 2f, C.y);
|
||||
var I = new Vector3(J.x + (H.x - J.x) / 2f, J.y);
|
||||
var K = new Vector3(L.x + (J.x - L.x) / 2f, L.y);
|
||||
|
||||
// Borders
|
||||
Handles.color = color;
|
||||
Handles.DrawLine(A, E);
|
||||
Handles.DrawLine(E, H);
|
||||
Handles.DrawLine(H, L);
|
||||
Handles.DrawLine(L, new Vector3(A.x, A.y - 1f));
|
||||
|
||||
// Vertical ticks
|
||||
Handles.DrawLine(A, new Vector3(A.x - kTickSize, A.y));
|
||||
Handles.DrawLine(N, new Vector3(N.x - kTickSize, N.y));
|
||||
Handles.DrawLine(M, new Vector3(M.x - kTickSize, M.y));
|
||||
Handles.DrawLine(L, new Vector3(L.x - kTickSize, L.y));
|
||||
|
||||
Handles.DrawLine(E, new Vector3(E.x + kTickSize, E.y));
|
||||
Handles.DrawLine(F, new Vector3(F.x + kTickSize, F.y));
|
||||
Handles.DrawLine(G, new Vector3(G.x + kTickSize, G.y));
|
||||
Handles.DrawLine(H, new Vector3(H.x + kTickSize, H.y));
|
||||
|
||||
// Horizontal ticks
|
||||
Handles.DrawLine(A, new Vector3(A.x, A.y - kTickSize));
|
||||
Handles.DrawLine(B, new Vector3(B.x, B.y - kTickSize));
|
||||
Handles.DrawLine(C, new Vector3(C.x, C.y - kTickSize));
|
||||
Handles.DrawLine(D, new Vector3(D.x, D.y - kTickSize));
|
||||
Handles.DrawLine(E, new Vector3(E.x, E.y - kTickSize));
|
||||
|
||||
Handles.DrawLine(L, new Vector3(L.x, L.y + kTickSize));
|
||||
Handles.DrawLine(K, new Vector3(K.x, K.y + kTickSize));
|
||||
Handles.DrawLine(J, new Vector3(J.x, J.y + kTickSize));
|
||||
Handles.DrawLine(I, new Vector3(I.x, I.y + kTickSize));
|
||||
Handles.DrawLine(H, new Vector3(H.x, H.y + kTickSize));
|
||||
|
||||
// Separators
|
||||
Handles.DrawLine(N, F);
|
||||
Handles.DrawLine(M, G);
|
||||
|
||||
// Labels
|
||||
GUI.color = color;
|
||||
GUI.Label(new Rect(L.x - 15f, L.y + kTickSize - 4f, 30f, 30f), "0.0", FxStyles.tickStyleCenter);
|
||||
GUI.Label(new Rect(J.x - 15f, J.y + kTickSize - 4f, 30f, 30f), "0.5", FxStyles.tickStyleCenter);
|
||||
GUI.Label(new Rect(H.x - 15f, H.y + kTickSize - 4f, 30f, 30f), "1.0", FxStyles.tickStyleCenter);
|
||||
}
|
||||
else
|
||||
{
|
||||
// A B C D E
|
||||
// P F
|
||||
// O G
|
||||
// N H
|
||||
// M L K J I
|
||||
|
||||
var A = new Vector3(m_MonitorAreaRect.x, m_MonitorAreaRect.y);
|
||||
var E = new Vector3(A.x + m_MonitorAreaRect.width + 1f, m_MonitorAreaRect.y);
|
||||
var I = new Vector3(E.x, E.y + m_MonitorAreaRect.height + 1f);
|
||||
var M = new Vector3(A.x, I.y);
|
||||
|
||||
var C = new Vector3(A.x + (E.x - A.x) / 2f, A.y);
|
||||
var G = new Vector3(E.x, E.y + (I.y - E.y) / 2f);
|
||||
var K = new Vector3(M.x + (I.x - M.x) / 2f, M.y);
|
||||
var O = new Vector3(A.x, A.y + (M.y - A.y) / 2f);
|
||||
|
||||
var P = new Vector3(A.x, A.y + (O.y - A.y) / 2f);
|
||||
var F = new Vector3(E.x, E.y + (G.y - E.y) / 2f);
|
||||
var N = new Vector3(A.x, O.y + (M.y - O.y) / 2f);
|
||||
var H = new Vector3(E.x, G.y + (I.y - G.y) / 2f);
|
||||
|
||||
var B = new Vector3(A.x + (C.x - A.x) / 2f, A.y);
|
||||
var L = new Vector3(M.x + (K.x - M.x) / 2f, M.y);
|
||||
var D = new Vector3(C.x + (E.x - C.x) / 2f, A.y);
|
||||
var J = new Vector3(K.x + (I.x - K.x) / 2f, M.y);
|
||||
|
||||
// Borders
|
||||
Handles.color = color;
|
||||
Handles.DrawLine(A, E);
|
||||
Handles.DrawLine(E, I);
|
||||
Handles.DrawLine(I, M);
|
||||
Handles.DrawLine(M, new Vector3(A.x, A.y - 1f));
|
||||
|
||||
// Vertical ticks
|
||||
Handles.DrawLine(A, new Vector3(A.x - kTickSize, A.y));
|
||||
Handles.DrawLine(P, new Vector3(P.x - kTickSize, P.y));
|
||||
Handles.DrawLine(O, new Vector3(O.x - kTickSize, O.y));
|
||||
Handles.DrawLine(N, new Vector3(N.x - kTickSize, N.y));
|
||||
Handles.DrawLine(M, new Vector3(M.x - kTickSize, M.y));
|
||||
|
||||
Handles.DrawLine(E, new Vector3(E.x + kTickSize, E.y));
|
||||
Handles.DrawLine(F, new Vector3(F.x + kTickSize, F.y));
|
||||
Handles.DrawLine(G, new Vector3(G.x + kTickSize, G.y));
|
||||
Handles.DrawLine(H, new Vector3(H.x + kTickSize, H.y));
|
||||
Handles.DrawLine(I, new Vector3(I.x + kTickSize, I.y));
|
||||
|
||||
// Horizontal ticks
|
||||
Handles.DrawLine(A, new Vector3(A.x, A.y - kTickSize));
|
||||
Handles.DrawLine(B, new Vector3(B.x, B.y - kTickSize));
|
||||
Handles.DrawLine(C, new Vector3(C.x, C.y - kTickSize));
|
||||
Handles.DrawLine(D, new Vector3(D.x, D.y - kTickSize));
|
||||
Handles.DrawLine(E, new Vector3(E.x, E.y - kTickSize));
|
||||
|
||||
Handles.DrawLine(M, new Vector3(M.x, M.y + kTickSize));
|
||||
Handles.DrawLine(L, new Vector3(L.x, L.y + kTickSize));
|
||||
Handles.DrawLine(K, new Vector3(K.x, K.y + kTickSize));
|
||||
Handles.DrawLine(J, new Vector3(J.x, J.y + kTickSize));
|
||||
Handles.DrawLine(I, new Vector3(I.x, I.y + kTickSize));
|
||||
|
||||
// Labels
|
||||
GUI.color = color;
|
||||
GUI.Label(new Rect(A.x - kTickSize - 34f, A.y - 15f, 30f, 30f), "1.0", FxStyles.tickStyleRight);
|
||||
GUI.Label(new Rect(O.x - kTickSize - 34f, O.y - 15f, 30f, 30f), "0.5", FxStyles.tickStyleRight);
|
||||
GUI.Label(new Rect(M.x - kTickSize - 34f, M.y - 15f, 30f, 30f), "0.0", FxStyles.tickStyleRight);
|
||||
|
||||
GUI.Label(new Rect(E.x + kTickSize + 4f, E.y - 15f, 30f, 30f), "1.0", FxStyles.tickStyleLeft);
|
||||
GUI.Label(new Rect(G.x + kTickSize + 4f, G.y - 15f, 30f, 30f), "0.5", FxStyles.tickStyleLeft);
|
||||
GUI.Label(new Rect(I.x + kTickSize + 4f, I.y - 15f, 30f, 30f), "0.0", FxStyles.tickStyleLeft);
|
||||
|
||||
GUI.Label(new Rect(M.x - 15f, M.y + kTickSize - 4f, 30f, 30f), "0.0", FxStyles.tickStyleCenter);
|
||||
GUI.Label(new Rect(K.x - 15f, K.y + kTickSize - 4f, 30f, 30f), "0.5", FxStyles.tickStyleCenter);
|
||||
GUI.Label(new Rect(I.x - 15f, I.y + kTickSize - 4f, 30f, 30f), "1.0", FxStyles.tickStyleCenter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnFrameData(RenderTexture source)
|
||||
{
|
||||
if (Application.isPlaying && !m_MonitorSettings.refreshOnPlay)
|
||||
return;
|
||||
|
||||
if (Mathf.Approximately(m_MonitorAreaRect.width, 0) || Mathf.Approximately(m_MonitorAreaRect.height, 0))
|
||||
return;
|
||||
|
||||
float ratio = (float)source.width / (float)source.height;
|
||||
int h = 512;
|
||||
int w = Mathf.FloorToInt(h * ratio);
|
||||
|
||||
var rt = RenderTexture.GetTemporary(w, h, 0, source.format);
|
||||
Graphics.Blit(source, rt);
|
||||
ComputeHistogram(rt);
|
||||
m_BaseEditor.Repaint();
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
}
|
||||
|
||||
void CreateBuffer(int width, int height)
|
||||
{
|
||||
m_Buffer = new ComputeBuffer(width * height, sizeof(uint) << 2);
|
||||
}
|
||||
|
||||
void ComputeHistogram(RenderTexture source)
|
||||
{
|
||||
if (m_Buffer == null)
|
||||
{
|
||||
CreateBuffer(256, 1);
|
||||
}
|
||||
else if (m_Buffer.count != 256)
|
||||
{
|
||||
m_Buffer.Release();
|
||||
CreateBuffer(256, 1);
|
||||
}
|
||||
|
||||
if (m_Material == null)
|
||||
{
|
||||
m_Material = new Material(Shader.Find("Hidden/Post FX/Monitors/Histogram Render")) { hideFlags = HideFlags.DontSave };
|
||||
}
|
||||
|
||||
var channels = Vector4.zero;
|
||||
switch (m_MonitorSettings.histogramMode)
|
||||
{
|
||||
case HistogramMode.Red: channels.x = 1f; break;
|
||||
case HistogramMode.Green: channels.y = 1f; break;
|
||||
case HistogramMode.Blue: channels.z = 1f; break;
|
||||
case HistogramMode.Luminance: channels.w = 1f; break;
|
||||
default: channels = new Vector4(1f, 1f, 1f, 0f); break;
|
||||
}
|
||||
|
||||
var cs = m_ComputeShader;
|
||||
|
||||
int kernel = cs.FindKernel("KHistogramClear");
|
||||
cs.SetBuffer(kernel, "_Histogram", m_Buffer);
|
||||
cs.Dispatch(kernel, 1, 1, 1);
|
||||
|
||||
kernel = cs.FindKernel("KHistogramGather");
|
||||
cs.SetBuffer(kernel, "_Histogram", m_Buffer);
|
||||
cs.SetTexture(kernel, "_Source", source);
|
||||
cs.SetInt("_IsLinear", GraphicsUtils.isLinearColorSpace ? 1 : 0);
|
||||
cs.SetVector("_Res", new Vector4(source.width, source.height, 0f, 0f));
|
||||
cs.SetVector("_Channels", channels);
|
||||
cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 16f), Mathf.CeilToInt(source.height / 16f), 1);
|
||||
|
||||
kernel = cs.FindKernel("KHistogramScale");
|
||||
cs.SetBuffer(kernel, "_Histogram", m_Buffer);
|
||||
cs.Dispatch(kernel, 1, 1, 1);
|
||||
|
||||
if (m_HistogramTexture == null || m_HistogramTexture.width != source.width || m_HistogramTexture.height != source.height)
|
||||
{
|
||||
GraphicsUtils.Destroy(m_HistogramTexture);
|
||||
m_HistogramTexture = new RenderTexture(source.width, source.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear)
|
||||
{
|
||||
hideFlags = HideFlags.DontSave,
|
||||
wrapMode = TextureWrapMode.Clamp,
|
||||
filterMode = FilterMode.Bilinear
|
||||
};
|
||||
}
|
||||
|
||||
m_Material.SetBuffer("_Histogram", m_Buffer);
|
||||
m_Material.SetVector("_Size", new Vector2(m_HistogramTexture.width, m_HistogramTexture.height));
|
||||
m_Material.SetColor("_ColorR", new Color(1f, 0f, 0f, 1f));
|
||||
m_Material.SetColor("_ColorG", new Color(0f, 1f, 0f, 1f));
|
||||
m_Material.SetColor("_ColorB", new Color(0f, 0f, 1f, 1f));
|
||||
m_Material.SetColor("_ColorL", new Color(1f, 1f, 1f, 1f));
|
||||
m_Material.SetInt("_Channel", (int)m_MonitorSettings.histogramMode);
|
||||
|
||||
int pass = 0;
|
||||
if (m_MonitorSettings.histogramMode == HistogramMode.RGBMerged)
|
||||
pass = 1;
|
||||
else if (m_MonitorSettings.histogramMode == HistogramMode.RGBSplit)
|
||||
pass = 2;
|
||||
|
||||
Graphics.Blit(null, m_HistogramTexture, m_Material, pass);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4581c45ac4aa2264187087659a4cc252
|
||||
timeCreated: 1460031632
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,257 @@
|
|||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
public class ParadeMonitor : PostProcessingMonitor
|
||||
{
|
||||
static GUIContent s_MonitorTitle = new GUIContent("Parade");
|
||||
|
||||
ComputeShader m_ComputeShader;
|
||||
ComputeBuffer m_Buffer;
|
||||
Material m_Material;
|
||||
RenderTexture m_WaveformTexture;
|
||||
Rect m_MonitorAreaRect;
|
||||
|
||||
public ParadeMonitor()
|
||||
{
|
||||
m_ComputeShader = EditorResources.Load<ComputeShader>("Monitors/WaveformCompute.compute");
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
GraphicsUtils.Destroy(m_Material);
|
||||
GraphicsUtils.Destroy(m_WaveformTexture);
|
||||
|
||||
if (m_Buffer != null)
|
||||
m_Buffer.Release();
|
||||
|
||||
m_Material = null;
|
||||
m_WaveformTexture = null;
|
||||
m_Buffer = null;
|
||||
}
|
||||
|
||||
public override bool IsSupported()
|
||||
{
|
||||
return m_ComputeShader != null && GraphicsUtils.supportsDX11;
|
||||
}
|
||||
|
||||
public override GUIContent GetMonitorTitle()
|
||||
{
|
||||
return s_MonitorTitle;
|
||||
}
|
||||
|
||||
public override void OnMonitorSettings()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
bool refreshOnPlay = m_MonitorSettings.refreshOnPlay;
|
||||
float exposure = m_MonitorSettings.paradeExposure;
|
||||
|
||||
refreshOnPlay = GUILayout.Toggle(refreshOnPlay, new GUIContent(FxStyles.playIcon, "Keep refreshing the parade in play mode; this may impact performances."), FxStyles.preButton);
|
||||
exposure = GUILayout.HorizontalSlider(exposure, 0.05f, 0.3f, FxStyles.preSlider, FxStyles.preSliderThumb, GUILayout.Width(40f));
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(m_BaseEditor.serializedObject.targetObject, "Parade Settings Changed");
|
||||
m_MonitorSettings.refreshOnPlay = refreshOnPlay;
|
||||
m_MonitorSettings.paradeExposure = exposure;
|
||||
InternalEditorUtility.RepaintAllViews();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMonitorGUI(Rect r)
|
||||
{
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
// If m_MonitorAreaRect isn't set the preview was just opened so refresh the render to get the waveform data
|
||||
if (Mathf.Approximately(m_MonitorAreaRect.width, 0) && Mathf.Approximately(m_MonitorAreaRect.height, 0))
|
||||
InternalEditorUtility.RepaintAllViews();
|
||||
|
||||
// Sizing
|
||||
float width = m_WaveformTexture != null
|
||||
? Mathf.Min(m_WaveformTexture.width, r.width - 65f)
|
||||
: r.width;
|
||||
float height = m_WaveformTexture != null
|
||||
? Mathf.Min(m_WaveformTexture.height, r.height - 45f)
|
||||
: r.height;
|
||||
|
||||
m_MonitorAreaRect = new Rect(
|
||||
Mathf.Floor(r.x + r.width / 2f - width / 2f),
|
||||
Mathf.Floor(r.y + r.height / 2f - height / 2f - 5f),
|
||||
width, height
|
||||
);
|
||||
|
||||
if (m_WaveformTexture != null)
|
||||
{
|
||||
m_Material.SetFloat("_Exposure", m_MonitorSettings.paradeExposure);
|
||||
|
||||
var oldActive = RenderTexture.active;
|
||||
Graphics.Blit(null, m_WaveformTexture, m_Material, 0);
|
||||
RenderTexture.active = oldActive;
|
||||
|
||||
Graphics.DrawTexture(m_MonitorAreaRect, m_WaveformTexture);
|
||||
|
||||
var color = Color.white;
|
||||
const float kTickSize = 5f;
|
||||
|
||||
// Rect, lines & ticks points
|
||||
// A O B P C Q D
|
||||
// N E
|
||||
// M F
|
||||
// L G
|
||||
// K T J S I R H
|
||||
|
||||
var A = new Vector3(m_MonitorAreaRect.x, m_MonitorAreaRect.y);
|
||||
var D = new Vector3(A.x + m_MonitorAreaRect.width + 1f, m_MonitorAreaRect.y);
|
||||
var H = new Vector3(D.x, D.y + m_MonitorAreaRect.height + 1f);
|
||||
var K = new Vector3(A.x, H.y);
|
||||
|
||||
var F = new Vector3(D.x, D.y + (H.y - D.y) / 2f);
|
||||
var M = new Vector3(A.x, A.y + (K.y - A.y) / 2f);
|
||||
|
||||
var B = new Vector3(A.x + (D.x - A.x) / 3f, A.y);
|
||||
var C = new Vector3(A.x + (D.x - A.x) * 2f / 3f, A.y);
|
||||
var I = new Vector3(K.x + (H.x - K.x) * 2f / 3f, K.y);
|
||||
var J = new Vector3(K.x + (H.x - K.x) / 3f, K.y);
|
||||
|
||||
var N = new Vector3(A.x, A.y + (M.y - A.y) / 2f);
|
||||
var L = new Vector3(A.x, M.y + (K.y - M.y) / 2f);
|
||||
var E = new Vector3(D.x, D.y + (F.y - D.y) / 2f);
|
||||
var G = new Vector3(D.x, F.y + (H.y - F.y) / 2f);
|
||||
|
||||
var O = new Vector3(A.x + (B.x - A.x) / 2f, A.y);
|
||||
var P = new Vector3(B.x + (C.x - B.x) / 2f, B.y);
|
||||
var Q = new Vector3(C.x + (D.x - C.x) / 2f, C.y);
|
||||
|
||||
var R = new Vector3(I.x + (H.x - I.x) / 2f, I.y);
|
||||
var S = new Vector3(J.x + (I.x - J.x) / 2f, J.y);
|
||||
var T = new Vector3(K.x + (J.x - K.x) / 2f, K.y);
|
||||
|
||||
// Borders
|
||||
Handles.color = color;
|
||||
Handles.DrawLine(A, D);
|
||||
Handles.DrawLine(D, H);
|
||||
Handles.DrawLine(H, K);
|
||||
Handles.DrawLine(K, new Vector3(A.x, A.y - 1f));
|
||||
|
||||
Handles.DrawLine(B, J);
|
||||
Handles.DrawLine(C, I);
|
||||
|
||||
// Vertical ticks
|
||||
Handles.DrawLine(A, new Vector3(A.x - kTickSize, A.y));
|
||||
Handles.DrawLine(N, new Vector3(N.x - kTickSize, N.y));
|
||||
Handles.DrawLine(M, new Vector3(M.x - kTickSize, M.y));
|
||||
Handles.DrawLine(L, new Vector3(L.x - kTickSize, L.y));
|
||||
Handles.DrawLine(K, new Vector3(K.x - kTickSize, K.y));
|
||||
|
||||
Handles.DrawLine(D, new Vector3(D.x + kTickSize, D.y));
|
||||
Handles.DrawLine(E, new Vector3(E.x + kTickSize, E.y));
|
||||
Handles.DrawLine(F, new Vector3(F.x + kTickSize, F.y));
|
||||
Handles.DrawLine(G, new Vector3(G.x + kTickSize, G.y));
|
||||
Handles.DrawLine(H, new Vector3(H.x + kTickSize, H.y));
|
||||
|
||||
// Horizontal ticks
|
||||
Handles.DrawLine(A, new Vector3(A.x, A.y - kTickSize));
|
||||
Handles.DrawLine(B, new Vector3(B.x, B.y - kTickSize));
|
||||
Handles.DrawLine(C, new Vector3(C.x, C.y - kTickSize));
|
||||
Handles.DrawLine(D, new Vector3(D.x, D.y - kTickSize));
|
||||
Handles.DrawLine(O, new Vector3(O.x, O.y - kTickSize));
|
||||
Handles.DrawLine(P, new Vector3(P.x, P.y - kTickSize));
|
||||
Handles.DrawLine(Q, new Vector3(Q.x, Q.y - kTickSize));
|
||||
|
||||
Handles.DrawLine(H, new Vector3(H.x, H.y + kTickSize));
|
||||
Handles.DrawLine(I, new Vector3(I.x, I.y + kTickSize));
|
||||
Handles.DrawLine(J, new Vector3(J.x, J.y + kTickSize));
|
||||
Handles.DrawLine(K, new Vector3(K.x, K.y + kTickSize));
|
||||
Handles.DrawLine(R, new Vector3(R.x, R.y + kTickSize));
|
||||
Handles.DrawLine(S, new Vector3(S.x, S.y + kTickSize));
|
||||
Handles.DrawLine(T, new Vector3(T.x, T.y + kTickSize));
|
||||
|
||||
// Labels
|
||||
GUI.color = color;
|
||||
GUI.Label(new Rect(A.x - kTickSize - 34f, A.y - 15f, 30f, 30f), "1.0", FxStyles.tickStyleRight);
|
||||
GUI.Label(new Rect(M.x - kTickSize - 34f, M.y - 15f, 30f, 30f), "0.5", FxStyles.tickStyleRight);
|
||||
GUI.Label(new Rect(K.x - kTickSize - 34f, K.y - 15f, 30f, 30f), "0.0", FxStyles.tickStyleRight);
|
||||
|
||||
GUI.Label(new Rect(D.x + kTickSize + 4f, D.y - 15f, 30f, 30f), "1.0", FxStyles.tickStyleLeft);
|
||||
GUI.Label(new Rect(F.x + kTickSize + 4f, F.y - 15f, 30f, 30f), "0.5", FxStyles.tickStyleLeft);
|
||||
GUI.Label(new Rect(H.x + kTickSize + 4f, H.y - 15f, 30f, 30f), "0.0", FxStyles.tickStyleLeft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnFrameData(RenderTexture source)
|
||||
{
|
||||
if (Application.isPlaying && !m_MonitorSettings.refreshOnPlay)
|
||||
return;
|
||||
|
||||
if (Mathf.Approximately(m_MonitorAreaRect.width, 0) || Mathf.Approximately(m_MonitorAreaRect.height, 0))
|
||||
return;
|
||||
|
||||
float ratio = ((float)source.width / (float)source.height) / 3f;
|
||||
int h = 384;
|
||||
int w = Mathf.FloorToInt(h * ratio);
|
||||
|
||||
var rt = RenderTexture.GetTemporary(w, h, 0, source.format);
|
||||
Graphics.Blit(source, rt);
|
||||
ComputeWaveform(rt);
|
||||
m_BaseEditor.Repaint();
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
}
|
||||
|
||||
void CreateBuffer(int width, int height)
|
||||
{
|
||||
m_Buffer = new ComputeBuffer(width * height, sizeof(uint) << 2);
|
||||
}
|
||||
|
||||
void ComputeWaveform(RenderTexture source)
|
||||
{
|
||||
if (m_Buffer == null)
|
||||
{
|
||||
CreateBuffer(source.width, source.height);
|
||||
}
|
||||
else if (m_Buffer.count != (source.width * source.height))
|
||||
{
|
||||
m_Buffer.Release();
|
||||
CreateBuffer(source.width, source.height);
|
||||
}
|
||||
|
||||
var channels = m_MonitorSettings.waveformY
|
||||
? new Vector4(0f, 0f, 0f, 1f)
|
||||
: new Vector4(m_MonitorSettings.waveformR ? 1f : 0f, m_MonitorSettings.waveformG ? 1f : 0f, m_MonitorSettings.waveformB ? 1f : 0f, 0f);
|
||||
|
||||
var cs = m_ComputeShader;
|
||||
|
||||
int kernel = cs.FindKernel("KWaveformClear");
|
||||
cs.SetBuffer(kernel, "_Waveform", m_Buffer);
|
||||
cs.Dispatch(kernel, source.width, 1, 1);
|
||||
|
||||
kernel = cs.FindKernel("KWaveform");
|
||||
cs.SetBuffer(kernel, "_Waveform", m_Buffer);
|
||||
cs.SetTexture(kernel, "_Source", source);
|
||||
cs.SetInt("_IsLinear", GraphicsUtils.isLinearColorSpace ? 1 : 0);
|
||||
cs.SetVector("_Channels", channels);
|
||||
cs.Dispatch(kernel, source.width, 1, 1);
|
||||
|
||||
if (m_WaveformTexture == null || m_WaveformTexture.width != (source.width * 3) || m_WaveformTexture.height != source.height)
|
||||
{
|
||||
GraphicsUtils.Destroy(m_WaveformTexture);
|
||||
m_WaveformTexture = new RenderTexture(source.width * 3, source.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear)
|
||||
{
|
||||
hideFlags = HideFlags.DontSave,
|
||||
wrapMode = TextureWrapMode.Clamp,
|
||||
filterMode = FilterMode.Bilinear
|
||||
};
|
||||
}
|
||||
|
||||
if (m_Material == null)
|
||||
m_Material = new Material(Shader.Find("Hidden/Post FX/Monitors/Parade Render")) { hideFlags = HideFlags.DontSave };
|
||||
|
||||
m_Material.SetBuffer("_Waveform", m_Buffer);
|
||||
m_Material.SetVector("_Size", new Vector2(m_WaveformTexture.width, m_WaveformTexture.height));
|
||||
m_Material.SetVector("_Channels", channels);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b1f878f3742072e40a280683573bd0ee
|
||||
timeCreated: 1460031643
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,241 @@
|
|||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
public class VectorscopeMonitor : PostProcessingMonitor
|
||||
{
|
||||
static GUIContent s_MonitorTitle = new GUIContent("Vectorscope");
|
||||
|
||||
ComputeShader m_ComputeShader;
|
||||
ComputeBuffer m_Buffer;
|
||||
Material m_Material;
|
||||
RenderTexture m_VectorscopeTexture;
|
||||
Rect m_MonitorAreaRect;
|
||||
|
||||
public VectorscopeMonitor()
|
||||
{
|
||||
m_ComputeShader = EditorResources.Load<ComputeShader>("Monitors/VectorscopeCompute.compute");
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
GraphicsUtils.Destroy(m_Material);
|
||||
GraphicsUtils.Destroy(m_VectorscopeTexture);
|
||||
|
||||
if (m_Buffer != null)
|
||||
m_Buffer.Release();
|
||||
|
||||
m_Material = null;
|
||||
m_VectorscopeTexture = null;
|
||||
m_Buffer = null;
|
||||
}
|
||||
|
||||
public override bool IsSupported()
|
||||
{
|
||||
return m_ComputeShader != null && GraphicsUtils.supportsDX11;
|
||||
}
|
||||
|
||||
public override GUIContent GetMonitorTitle()
|
||||
{
|
||||
return s_MonitorTitle;
|
||||
}
|
||||
|
||||
public override void OnMonitorSettings()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
bool refreshOnPlay = m_MonitorSettings.refreshOnPlay;
|
||||
float exposure = m_MonitorSettings.vectorscopeExposure;
|
||||
bool showBackground = m_MonitorSettings.vectorscopeShowBackground;
|
||||
|
||||
refreshOnPlay = GUILayout.Toggle(refreshOnPlay, new GUIContent(FxStyles.playIcon, "Keep refreshing the vectorscope in play mode; this may impact performances."), FxStyles.preButton);
|
||||
exposure = GUILayout.HorizontalSlider(exposure, 0.05f, 0.3f, FxStyles.preSlider, FxStyles.preSliderThumb, GUILayout.Width(40f));
|
||||
showBackground = GUILayout.Toggle(showBackground, new GUIContent(FxStyles.checkerIcon, "Show an YUV background in the vectorscope."), FxStyles.preButton);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(m_BaseEditor.serializedObject.targetObject, "Vectorscope Settings Changed");
|
||||
m_MonitorSettings.refreshOnPlay = refreshOnPlay;
|
||||
m_MonitorSettings.vectorscopeExposure = exposure;
|
||||
m_MonitorSettings.vectorscopeShowBackground = showBackground;
|
||||
InternalEditorUtility.RepaintAllViews();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMonitorGUI(Rect r)
|
||||
{
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
// If m_MonitorAreaRect isn't set the preview was just opened so refresh the render to get the vectoscope data
|
||||
if (Mathf.Approximately(m_MonitorAreaRect.width, 0) && Mathf.Approximately(m_MonitorAreaRect.height, 0))
|
||||
InternalEditorUtility.RepaintAllViews();
|
||||
|
||||
// Sizing
|
||||
float size = 0f;
|
||||
|
||||
if (r.width < r.height)
|
||||
{
|
||||
size = m_VectorscopeTexture != null
|
||||
? Mathf.Min(m_VectorscopeTexture.width, r.width - 35f)
|
||||
: r.width;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = m_VectorscopeTexture != null
|
||||
? Mathf.Min(m_VectorscopeTexture.height, r.height - 25f)
|
||||
: r.height;
|
||||
}
|
||||
|
||||
m_MonitorAreaRect = new Rect(
|
||||
Mathf.Floor(r.x + r.width / 2f - size / 2f),
|
||||
Mathf.Floor(r.y + r.height / 2f - size / 2f - 5f),
|
||||
size, size
|
||||
);
|
||||
|
||||
if (m_VectorscopeTexture != null)
|
||||
{
|
||||
m_Material.SetFloat("_Exposure", m_MonitorSettings.vectorscopeExposure);
|
||||
|
||||
var oldActive = RenderTexture.active;
|
||||
Graphics.Blit(null, m_VectorscopeTexture, m_Material, m_MonitorSettings.vectorscopeShowBackground ? 0 : 1);
|
||||
RenderTexture.active = oldActive;
|
||||
|
||||
Graphics.DrawTexture(m_MonitorAreaRect, m_VectorscopeTexture);
|
||||
|
||||
var color = Color.white;
|
||||
const float kTickSize = 10f;
|
||||
const int kTickCount = 24;
|
||||
|
||||
float radius = m_MonitorAreaRect.width / 2f;
|
||||
float midX = m_MonitorAreaRect.x + radius;
|
||||
float midY = m_MonitorAreaRect.y + radius;
|
||||
var center = new Vector2(midX, midY);
|
||||
|
||||
// Cross
|
||||
color.a *= 0.5f;
|
||||
Handles.color = color;
|
||||
Handles.DrawLine(new Vector2(midX, m_MonitorAreaRect.y), new Vector2(midX, m_MonitorAreaRect.y + m_MonitorAreaRect.height));
|
||||
Handles.DrawLine(new Vector2(m_MonitorAreaRect.x, midY), new Vector2(m_MonitorAreaRect.x + m_MonitorAreaRect.width, midY));
|
||||
|
||||
if (m_MonitorAreaRect.width > 100f)
|
||||
{
|
||||
color.a = 1f;
|
||||
|
||||
// Ticks
|
||||
Handles.color = color;
|
||||
for (int i = 0; i < kTickCount; i++)
|
||||
{
|
||||
float a = (float)i / (float)kTickCount;
|
||||
float theta = a * (Mathf.PI * 2f);
|
||||
float tx = Mathf.Cos(theta + (Mathf.PI / 2f));
|
||||
float ty = Mathf.Sin(theta - (Mathf.PI / 2f));
|
||||
var innerVec = center + new Vector2(tx, ty) * (radius - kTickSize);
|
||||
var outerVec = center + new Vector2(tx, ty) * radius;
|
||||
Handles.DrawAAPolyLine(3f, innerVec, outerVec);
|
||||
}
|
||||
|
||||
// Labels (where saturation reaches 75%)
|
||||
color.a = 1f;
|
||||
var oldColor = GUI.color;
|
||||
GUI.color = color * 2f;
|
||||
|
||||
var point = new Vector2(-0.254f, -0.750f) * radius + center;
|
||||
var rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
|
||||
GUI.Label(rect, "[R]", FxStyles.tickStyleCenter);
|
||||
|
||||
point = new Vector2(-0.497f, 0.629f) * radius + center;
|
||||
rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
|
||||
GUI.Label(rect, "[G]", FxStyles.tickStyleCenter);
|
||||
|
||||
point = new Vector2(0.750f, 0.122f) * radius + center;
|
||||
rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
|
||||
GUI.Label(rect, "[B]", FxStyles.tickStyleCenter);
|
||||
|
||||
point = new Vector2(-0.750f, -0.122f) * radius + center;
|
||||
rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
|
||||
GUI.Label(rect, "[Y]", FxStyles.tickStyleCenter);
|
||||
|
||||
point = new Vector2(0.254f, 0.750f) * radius + center;
|
||||
rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
|
||||
GUI.Label(rect, "[C]", FxStyles.tickStyleCenter);
|
||||
|
||||
point = new Vector2(0.497f, -0.629f) * radius + center;
|
||||
rect = new Rect(point.x - 10f, point.y - 10f, 20f, 20f);
|
||||
GUI.Label(rect, "[M]", FxStyles.tickStyleCenter);
|
||||
GUI.color = oldColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnFrameData(RenderTexture source)
|
||||
{
|
||||
if (Application.isPlaying && !m_MonitorSettings.refreshOnPlay)
|
||||
return;
|
||||
|
||||
if (Mathf.Approximately(m_MonitorAreaRect.width, 0) || Mathf.Approximately(m_MonitorAreaRect.height, 0))
|
||||
return;
|
||||
|
||||
float ratio = (float)source.width / (float)source.height;
|
||||
int h = 384;
|
||||
int w = Mathf.FloorToInt(h * ratio);
|
||||
|
||||
var rt = RenderTexture.GetTemporary(w, h, 0, source.format);
|
||||
Graphics.Blit(source, rt);
|
||||
ComputeVectorscope(rt);
|
||||
m_BaseEditor.Repaint();
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
}
|
||||
|
||||
void CreateBuffer(int width, int height)
|
||||
{
|
||||
m_Buffer = new ComputeBuffer(width * height, sizeof(uint));
|
||||
}
|
||||
|
||||
void ComputeVectorscope(RenderTexture source)
|
||||
{
|
||||
if (m_Buffer == null)
|
||||
{
|
||||
CreateBuffer(source.width, source.height);
|
||||
}
|
||||
else if (m_Buffer.count != (source.width * source.height))
|
||||
{
|
||||
m_Buffer.Release();
|
||||
CreateBuffer(source.width, source.height);
|
||||
}
|
||||
|
||||
var cs = m_ComputeShader;
|
||||
|
||||
int kernel = cs.FindKernel("KVectorscopeClear");
|
||||
cs.SetBuffer(kernel, "_Vectorscope", m_Buffer);
|
||||
cs.SetVector("_Res", new Vector4(source.width, source.height, 0f, 0f));
|
||||
cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 32f), Mathf.CeilToInt(source.height / 32f), 1);
|
||||
|
||||
kernel = cs.FindKernel("KVectorscope");
|
||||
cs.SetBuffer(kernel, "_Vectorscope", m_Buffer);
|
||||
cs.SetTexture(kernel, "_Source", source);
|
||||
cs.SetInt("_IsLinear", GraphicsUtils.isLinearColorSpace ? 1 : 0);
|
||||
cs.SetVector("_Res", new Vector4(source.width, source.height, 0f, 0f));
|
||||
cs.Dispatch(kernel, Mathf.CeilToInt(source.width / 32f), Mathf.CeilToInt(source.height / 32f), 1);
|
||||
|
||||
if (m_VectorscopeTexture == null || m_VectorscopeTexture.width != source.width || m_VectorscopeTexture.height != source.height)
|
||||
{
|
||||
GraphicsUtils.Destroy(m_VectorscopeTexture);
|
||||
m_VectorscopeTexture = new RenderTexture(source.width, source.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear)
|
||||
{
|
||||
hideFlags = HideFlags.DontSave,
|
||||
wrapMode = TextureWrapMode.Clamp,
|
||||
filterMode = FilterMode.Bilinear
|
||||
};
|
||||
}
|
||||
|
||||
if (m_Material == null)
|
||||
m_Material = new Material(Shader.Find("Hidden/Post FX/Monitors/Vectorscope Render")) { hideFlags = HideFlags.DontSave };
|
||||
|
||||
m_Material.SetBuffer("_Vectorscope", m_Buffer);
|
||||
m_Material.SetVector("_Size", new Vector2(m_VectorscopeTexture.width, m_VectorscopeTexture.height));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 805119df0d94800418006c621cc99cc2
|
||||
timeCreated: 1461748750
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,280 @@
|
|||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
public class WaveformMonitor : PostProcessingMonitor
|
||||
{
|
||||
static GUIContent s_MonitorTitle = new GUIContent("Waveform");
|
||||
|
||||
ComputeShader m_ComputeShader;
|
||||
ComputeBuffer m_Buffer;
|
||||
Material m_Material;
|
||||
RenderTexture m_WaveformTexture;
|
||||
Rect m_MonitorAreaRect;
|
||||
|
||||
public WaveformMonitor()
|
||||
{
|
||||
m_ComputeShader = EditorResources.Load<ComputeShader>("Monitors/WaveformCompute.compute");
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
GraphicsUtils.Destroy(m_Material);
|
||||
GraphicsUtils.Destroy(m_WaveformTexture);
|
||||
|
||||
if (m_Buffer != null)
|
||||
m_Buffer.Release();
|
||||
|
||||
m_Material = null;
|
||||
m_WaveformTexture = null;
|
||||
m_Buffer = null;
|
||||
}
|
||||
|
||||
public override bool IsSupported()
|
||||
{
|
||||
return m_ComputeShader != null && GraphicsUtils.supportsDX11;
|
||||
}
|
||||
|
||||
public override GUIContent GetMonitorTitle()
|
||||
{
|
||||
return s_MonitorTitle;
|
||||
}
|
||||
|
||||
public override void OnMonitorSettings()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
bool refreshOnPlay = m_MonitorSettings.refreshOnPlay;
|
||||
float exposure = m_MonitorSettings.waveformExposure;
|
||||
bool Y = m_MonitorSettings.waveformY;
|
||||
bool R = m_MonitorSettings.waveformR;
|
||||
bool G = m_MonitorSettings.waveformG;
|
||||
bool B = m_MonitorSettings.waveformB;
|
||||
|
||||
refreshOnPlay = GUILayout.Toggle(refreshOnPlay, new GUIContent(FxStyles.playIcon, "Keep refreshing the waveform in play mode; this may impact performances."), FxStyles.preButton);
|
||||
|
||||
exposure = GUILayout.HorizontalSlider(exposure, 0.05f, 0.3f, FxStyles.preSlider, FxStyles.preSliderThumb, GUILayout.Width(40f));
|
||||
|
||||
Y = GUILayout.Toggle(Y, new GUIContent("Y", "Show the luminance waveform only."), FxStyles.preButton);
|
||||
|
||||
if (Y)
|
||||
{
|
||||
R = false;
|
||||
G = false;
|
||||
B = false;
|
||||
}
|
||||
|
||||
R = GUILayout.Toggle(R, new GUIContent("R", "Show the red waveform."), FxStyles.preButton);
|
||||
G = GUILayout.Toggle(G, new GUIContent("G", "Show the green waveform."), FxStyles.preButton);
|
||||
B = GUILayout.Toggle(B, new GUIContent("B", "Show the blue waveform."), FxStyles.preButton);
|
||||
|
||||
if (R || G || B)
|
||||
Y = false;
|
||||
|
||||
if (!Y && !R && !G && !B)
|
||||
{
|
||||
R = true;
|
||||
G = true;
|
||||
B = true;
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(m_BaseEditor.serializedObject.targetObject, "Waveforme Settings Changed");
|
||||
m_MonitorSettings.refreshOnPlay = refreshOnPlay;
|
||||
m_MonitorSettings.waveformExposure = exposure;
|
||||
m_MonitorSettings.waveformY = Y;
|
||||
m_MonitorSettings.waveformR = R;
|
||||
m_MonitorSettings.waveformG = G;
|
||||
m_MonitorSettings.waveformB = B;
|
||||
InternalEditorUtility.RepaintAllViews();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMonitorGUI(Rect r)
|
||||
{
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
// If m_MonitorAreaRect isn't set the preview was just opened so refresh the render to get the waveform data
|
||||
if (Mathf.Approximately(m_MonitorAreaRect.width, 0) && Mathf.Approximately(m_MonitorAreaRect.height, 0))
|
||||
InternalEditorUtility.RepaintAllViews();
|
||||
|
||||
// Sizing
|
||||
float width = m_WaveformTexture != null
|
||||
? Mathf.Min(m_WaveformTexture.width, r.width - 65f)
|
||||
: r.width;
|
||||
float height = m_WaveformTexture != null
|
||||
? Mathf.Min(m_WaveformTexture.height, r.height - 45f)
|
||||
: r.height;
|
||||
|
||||
m_MonitorAreaRect = new Rect(
|
||||
Mathf.Floor(r.x + r.width / 2f - width / 2f),
|
||||
Mathf.Floor(r.y + r.height / 2f - height / 2f - 5f),
|
||||
width, height
|
||||
);
|
||||
|
||||
if (m_WaveformTexture != null)
|
||||
{
|
||||
m_Material.SetFloat("_Exposure", m_MonitorSettings.waveformExposure);
|
||||
|
||||
var oldActive = RenderTexture.active;
|
||||
Graphics.Blit(null, m_WaveformTexture, m_Material, 0);
|
||||
RenderTexture.active = oldActive;
|
||||
|
||||
Graphics.DrawTexture(m_MonitorAreaRect, m_WaveformTexture);
|
||||
|
||||
var color = Color.white;
|
||||
const float kTickSize = 5f;
|
||||
|
||||
// Rect, lines & ticks points
|
||||
// A B C D E
|
||||
// P F
|
||||
// O G
|
||||
// N H
|
||||
// M L K J I
|
||||
|
||||
var A = new Vector3(m_MonitorAreaRect.x, m_MonitorAreaRect.y);
|
||||
var E = new Vector3(A.x + m_MonitorAreaRect.width + 1f, m_MonitorAreaRect.y);
|
||||
var I = new Vector3(E.x, E.y + m_MonitorAreaRect.height + 1f);
|
||||
var M = new Vector3(A.x, I.y);
|
||||
|
||||
var C = new Vector3(A.x + (E.x - A.x) / 2f, A.y);
|
||||
var G = new Vector3(E.x, E.y + (I.y - E.y) / 2f);
|
||||
var K = new Vector3(M.x + (I.x - M.x) / 2f, M.y);
|
||||
var O = new Vector3(A.x, A.y + (M.y - A.y) / 2f);
|
||||
|
||||
var P = new Vector3(A.x, A.y + (O.y - A.y) / 2f);
|
||||
var F = new Vector3(E.x, E.y + (G.y - E.y) / 2f);
|
||||
var N = new Vector3(A.x, O.y + (M.y - O.y) / 2f);
|
||||
var H = new Vector3(E.x, G.y + (I.y - G.y) / 2f);
|
||||
|
||||
var B = new Vector3(A.x + (C.x - A.x) / 2f, A.y);
|
||||
var L = new Vector3(M.x + (K.x - M.x) / 2f, M.y);
|
||||
var D = new Vector3(C.x + (E.x - C.x) / 2f, A.y);
|
||||
var J = new Vector3(K.x + (I.x - K.x) / 2f, M.y);
|
||||
|
||||
// Borders
|
||||
Handles.color = color;
|
||||
Handles.DrawLine(A, E);
|
||||
Handles.DrawLine(E, I);
|
||||
Handles.DrawLine(I, M);
|
||||
Handles.DrawLine(M, new Vector3(A.x, A.y - 1f));
|
||||
|
||||
// Vertical ticks
|
||||
Handles.DrawLine(A, new Vector3(A.x - kTickSize, A.y));
|
||||
Handles.DrawLine(P, new Vector3(P.x - kTickSize, P.y));
|
||||
Handles.DrawLine(O, new Vector3(O.x - kTickSize, O.y));
|
||||
Handles.DrawLine(N, new Vector3(N.x - kTickSize, N.y));
|
||||
Handles.DrawLine(M, new Vector3(M.x - kTickSize, M.y));
|
||||
|
||||
Handles.DrawLine(E, new Vector3(E.x + kTickSize, E.y));
|
||||
Handles.DrawLine(F, new Vector3(F.x + kTickSize, F.y));
|
||||
Handles.DrawLine(G, new Vector3(G.x + kTickSize, G.y));
|
||||
Handles.DrawLine(H, new Vector3(H.x + kTickSize, H.y));
|
||||
Handles.DrawLine(I, new Vector3(I.x + kTickSize, I.y));
|
||||
|
||||
// Horizontal ticks
|
||||
Handles.DrawLine(A, new Vector3(A.x, A.y - kTickSize));
|
||||
Handles.DrawLine(B, new Vector3(B.x, B.y - kTickSize));
|
||||
Handles.DrawLine(C, new Vector3(C.x, C.y - kTickSize));
|
||||
Handles.DrawLine(D, new Vector3(D.x, D.y - kTickSize));
|
||||
Handles.DrawLine(E, new Vector3(E.x, E.y - kTickSize));
|
||||
|
||||
Handles.DrawLine(M, new Vector3(M.x, M.y + kTickSize));
|
||||
Handles.DrawLine(L, new Vector3(L.x, L.y + kTickSize));
|
||||
Handles.DrawLine(K, new Vector3(K.x, K.y + kTickSize));
|
||||
Handles.DrawLine(J, new Vector3(J.x, J.y + kTickSize));
|
||||
Handles.DrawLine(I, new Vector3(I.x, I.y + kTickSize));
|
||||
|
||||
// Labels
|
||||
GUI.color = color;
|
||||
GUI.Label(new Rect(A.x - kTickSize - 34f, A.y - 15f, 30f, 30f), "1.0", FxStyles.tickStyleRight);
|
||||
GUI.Label(new Rect(O.x - kTickSize - 34f, O.y - 15f, 30f, 30f), "0.5", FxStyles.tickStyleRight);
|
||||
GUI.Label(new Rect(M.x - kTickSize - 34f, M.y - 15f, 30f, 30f), "0.0", FxStyles.tickStyleRight);
|
||||
|
||||
GUI.Label(new Rect(E.x + kTickSize + 4f, E.y - 15f, 30f, 30f), "1.0", FxStyles.tickStyleLeft);
|
||||
GUI.Label(new Rect(G.x + kTickSize + 4f, G.y - 15f, 30f, 30f), "0.5", FxStyles.tickStyleLeft);
|
||||
GUI.Label(new Rect(I.x + kTickSize + 4f, I.y - 15f, 30f, 30f), "0.0", FxStyles.tickStyleLeft);
|
||||
|
||||
GUI.Label(new Rect(M.x - 15f, M.y + kTickSize - 4f, 30f, 30f), "0.0", FxStyles.tickStyleCenter);
|
||||
GUI.Label(new Rect(K.x - 15f, K.y + kTickSize - 4f, 30f, 30f), "0.5", FxStyles.tickStyleCenter);
|
||||
GUI.Label(new Rect(I.x - 15f, I.y + kTickSize - 4f, 30f, 30f), "1.0", FxStyles.tickStyleCenter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnFrameData(RenderTexture source)
|
||||
{
|
||||
if (Application.isPlaying && !m_MonitorSettings.refreshOnPlay)
|
||||
return;
|
||||
|
||||
if (Mathf.Approximately(m_MonitorAreaRect.width, 0) || Mathf.Approximately(m_MonitorAreaRect.height, 0))
|
||||
return;
|
||||
|
||||
float ratio = (float)source.width / (float)source.height;
|
||||
int h = 384;
|
||||
int w = Mathf.FloorToInt(h * ratio);
|
||||
|
||||
var rt = RenderTexture.GetTemporary(w, h, 0, source.format);
|
||||
Graphics.Blit(source, rt);
|
||||
ComputeWaveform(rt);
|
||||
m_BaseEditor.Repaint();
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
}
|
||||
|
||||
void CreateBuffer(int width, int height)
|
||||
{
|
||||
m_Buffer = new ComputeBuffer(width * height, sizeof(uint) << 2);
|
||||
}
|
||||
|
||||
void ComputeWaveform(RenderTexture source)
|
||||
{
|
||||
if (m_Buffer == null)
|
||||
{
|
||||
CreateBuffer(source.width, source.height);
|
||||
}
|
||||
else if (m_Buffer.count != (source.width * source.height))
|
||||
{
|
||||
m_Buffer.Release();
|
||||
CreateBuffer(source.width, source.height);
|
||||
}
|
||||
|
||||
var channels = m_MonitorSettings.waveformY
|
||||
? new Vector4(0f, 0f, 0f, 1f)
|
||||
: new Vector4(m_MonitorSettings.waveformR ? 1f : 0f, m_MonitorSettings.waveformG ? 1f : 0f, m_MonitorSettings.waveformB ? 1f : 0f, 0f);
|
||||
|
||||
var cs = m_ComputeShader;
|
||||
|
||||
int kernel = cs.FindKernel("KWaveformClear");
|
||||
cs.SetBuffer(kernel, "_Waveform", m_Buffer);
|
||||
cs.Dispatch(kernel, source.width, 1, 1);
|
||||
|
||||
kernel = cs.FindKernel("KWaveform");
|
||||
cs.SetBuffer(kernel, "_Waveform", m_Buffer);
|
||||
cs.SetTexture(kernel, "_Source", source);
|
||||
cs.SetInt("_IsLinear", GraphicsUtils.isLinearColorSpace ? 1 : 0);
|
||||
cs.SetVector("_Channels", channels);
|
||||
cs.Dispatch(kernel, source.width, 1, 1);
|
||||
|
||||
if (m_WaveformTexture == null || m_WaveformTexture.width != source.width || m_WaveformTexture.height != source.height)
|
||||
{
|
||||
GraphicsUtils.Destroy(m_WaveformTexture);
|
||||
m_WaveformTexture = new RenderTexture(source.width, source.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear)
|
||||
{
|
||||
hideFlags = HideFlags.DontSave,
|
||||
wrapMode = TextureWrapMode.Clamp,
|
||||
filterMode = FilterMode.Bilinear
|
||||
};
|
||||
}
|
||||
|
||||
if (m_Material == null)
|
||||
m_Material = new Material(Shader.Find("Hidden/Post FX/Monitors/Waveform Render")) { hideFlags = HideFlags.DontSave };
|
||||
|
||||
m_Material.SetBuffer("_Waveform", m_Buffer);
|
||||
m_Material.SetVector("_Size", new Vector2(m_WaveformTexture.width, m_WaveformTexture.height));
|
||||
m_Material.SetVector("_Channels", channels);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2d45bc7edb5916446b4fa1ae1b6f9065
|
||||
timeCreated: 1459957472
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
[CustomEditor(typeof(PostProcessingBehaviour))]
|
||||
public class PostProcessingBehaviourEditor : Editor
|
||||
{
|
||||
SerializedProperty m_Profile;
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
m_Profile = FindSetting((PostProcessingBehaviour x) => x.profile);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Profile);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
SerializedProperty FindSetting<T, TValue>(Expression<Func<T, TValue>> expr)
|
||||
{
|
||||
return serializedObject.FindProperty(ReflectionUtils.GetFieldPath(expr));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0c12e797b02402246a52aa270c45059b
|
||||
timeCreated: 1476193645
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,35 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
using UnityEditor.ProjectWindowCallback;
|
||||
using System.IO;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
public class PostProcessingFactory
|
||||
{
|
||||
[MenuItem("Assets/Create/Post-Processing Profile", priority = 201)]
|
||||
static void MenuCreatePostProcessingProfile()
|
||||
{
|
||||
var icon = EditorGUIUtility.FindTexture("ScriptableObject Icon");
|
||||
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, ScriptableObject.CreateInstance<DoCreatePostProcessingProfile>(), "New Post-Processing Profile.asset", icon, null);
|
||||
}
|
||||
|
||||
internal static PostProcessingProfile CreatePostProcessingProfileAtPath(string path)
|
||||
{
|
||||
var profile = ScriptableObject.CreateInstance<PostProcessingProfile>();
|
||||
profile.name = Path.GetFileName(path);
|
||||
profile.fog.enabled = true;
|
||||
AssetDatabase.CreateAsset(profile, path);
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
|
||||
class DoCreatePostProcessingProfile : EndNameEditAction
|
||||
{
|
||||
public override void Action(int instanceId, string pathName, string resourceFile)
|
||||
{
|
||||
PostProcessingProfile profile = PostProcessingFactory.CreatePostProcessingProfileAtPath(pathName);
|
||||
ProjectWindowUtil.ShowCreatedAsset(profile);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0dfcadb180d67014cb0a6e18d6b11f90
|
||||
timeCreated: 1466586271
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,208 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
//[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(PostProcessingProfile))]
|
||||
public class PostProcessingInspector : Editor
|
||||
{
|
||||
static GUIContent s_PreviewTitle = new GUIContent("Monitors");
|
||||
|
||||
PostProcessingProfile m_ConcreteTarget
|
||||
{
|
||||
get { return target as PostProcessingProfile; }
|
||||
}
|
||||
|
||||
int m_CurrentMonitorID
|
||||
{
|
||||
get { return m_ConcreteTarget.monitors.currentMonitorID; }
|
||||
set { m_ConcreteTarget.monitors.currentMonitorID = value; }
|
||||
}
|
||||
|
||||
List<PostProcessingMonitor> m_Monitors;
|
||||
GUIContent[] m_MonitorNames;
|
||||
Dictionary<PostProcessingModelEditor, PostProcessingModel> m_CustomEditors = new Dictionary<PostProcessingModelEditor, PostProcessingModel>();
|
||||
|
||||
public bool IsInteractivePreviewOpened { get; private set; }
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
// Aggregate custom post-fx editors
|
||||
var assembly = Assembly.GetAssembly(typeof(PostProcessingInspector));
|
||||
|
||||
var editorTypes = assembly.GetTypes()
|
||||
.Where(x => x.IsDefined(typeof(PostProcessingModelEditorAttribute), false));
|
||||
|
||||
var customEditors = new Dictionary<Type, PostProcessingModelEditor>();
|
||||
foreach (var editor in editorTypes)
|
||||
{
|
||||
var attr = (PostProcessingModelEditorAttribute)editor.GetCustomAttributes(typeof(PostProcessingModelEditorAttribute), false)[0];
|
||||
var effectType = attr.type;
|
||||
var alwaysEnabled = attr.alwaysEnabled;
|
||||
|
||||
var editorInst = (PostProcessingModelEditor)Activator.CreateInstance(editor);
|
||||
editorInst.alwaysEnabled = alwaysEnabled;
|
||||
editorInst.profile = target as PostProcessingProfile;
|
||||
editorInst.inspector = this;
|
||||
customEditors.Add(effectType, editorInst);
|
||||
}
|
||||
|
||||
// ... and corresponding models
|
||||
var baseType = target.GetType();
|
||||
var property = serializedObject.GetIterator();
|
||||
|
||||
while (property.Next(true))
|
||||
{
|
||||
if (!property.hasChildren)
|
||||
continue;
|
||||
|
||||
var type = baseType;
|
||||
var srcObject = ReflectionUtils.GetFieldValueFromPath(serializedObject.targetObject, ref type, property.propertyPath);
|
||||
|
||||
if (srcObject == null)
|
||||
continue;
|
||||
|
||||
PostProcessingModelEditor editor;
|
||||
if (customEditors.TryGetValue(type, out editor))
|
||||
{
|
||||
var effect = (PostProcessingModel)srcObject;
|
||||
|
||||
if (editor.alwaysEnabled)
|
||||
effect.enabled = editor.alwaysEnabled;
|
||||
|
||||
m_CustomEditors.Add(editor, effect);
|
||||
editor.target = effect;
|
||||
editor.serializedProperty = property.Copy();
|
||||
editor.OnPreEnable();
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare monitors
|
||||
m_Monitors = new List<PostProcessingMonitor>();
|
||||
|
||||
var monitors = new List<PostProcessingMonitor>
|
||||
{
|
||||
new HistogramMonitor(),
|
||||
new WaveformMonitor(),
|
||||
new ParadeMonitor(),
|
||||
new VectorscopeMonitor()
|
||||
};
|
||||
|
||||
var monitorNames = new List<GUIContent>();
|
||||
|
||||
foreach (var monitor in monitors)
|
||||
{
|
||||
if (monitor.IsSupported())
|
||||
{
|
||||
monitor.Init(m_ConcreteTarget.monitors, this);
|
||||
m_Monitors.Add(monitor);
|
||||
monitorNames.Add(monitor.GetMonitorTitle());
|
||||
}
|
||||
}
|
||||
|
||||
m_MonitorNames = monitorNames.ToArray();
|
||||
|
||||
if (m_Monitors.Count > 0)
|
||||
m_ConcreteTarget.monitors.onFrameEndEditorOnly = OnFrameEnd;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (m_CustomEditors != null)
|
||||
{
|
||||
foreach (var editor in m_CustomEditors.Keys)
|
||||
editor.OnDisable();
|
||||
|
||||
m_CustomEditors.Clear();
|
||||
}
|
||||
|
||||
if (m_Monitors != null)
|
||||
{
|
||||
foreach (var monitor in m_Monitors)
|
||||
monitor.Dispose();
|
||||
|
||||
m_Monitors.Clear();
|
||||
}
|
||||
|
||||
if (m_ConcreteTarget != null)
|
||||
m_ConcreteTarget.monitors.onFrameEndEditorOnly = null;
|
||||
}
|
||||
|
||||
void OnFrameEnd(RenderTexture source)
|
||||
{
|
||||
if (!IsInteractivePreviewOpened)
|
||||
return;
|
||||
|
||||
if (m_CurrentMonitorID < m_Monitors.Count)
|
||||
m_Monitors[m_CurrentMonitorID].OnFrameData(source);
|
||||
|
||||
IsInteractivePreviewOpened = false;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
// Handles undo/redo events first (before they get used by the editors' widgets)
|
||||
var e = Event.current;
|
||||
if (e.type == EventType.ValidateCommand && e.commandName == "UndoRedoPerformed")
|
||||
{
|
||||
foreach (var editor in m_CustomEditors)
|
||||
editor.Value.OnValidate();
|
||||
}
|
||||
|
||||
if (!m_ConcreteTarget.debugViews.IsModeActive(BuiltinDebugViewsModel.Mode.None))
|
||||
EditorGUILayout.HelpBox("A debug view is currently enabled. Changes done to an effect might not be visible.", MessageType.Info);
|
||||
|
||||
foreach (var editor in m_CustomEditors)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
editor.Key.OnGUI();
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
editor.Value.OnValidate();
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
public override GUIContent GetPreviewTitle()
|
||||
{
|
||||
return s_PreviewTitle;
|
||||
}
|
||||
|
||||
public override bool HasPreviewGUI()
|
||||
{
|
||||
return GraphicsUtils.supportsDX11 && m_Monitors.Count > 0;
|
||||
}
|
||||
|
||||
public override void OnPreviewSettings()
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (m_CurrentMonitorID < m_Monitors.Count)
|
||||
m_Monitors[m_CurrentMonitorID].OnMonitorSettings();
|
||||
|
||||
GUILayout.Space(5);
|
||||
m_CurrentMonitorID = EditorGUILayout.Popup(m_CurrentMonitorID, m_MonitorNames, FxStyles.preDropdown, GUILayout.MaxWidth(100f));
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInteractivePreviewGUI(Rect r, GUIStyle background)
|
||||
{
|
||||
IsInteractivePreviewOpened = true;
|
||||
|
||||
if (m_CurrentMonitorID < m_Monitors.Count)
|
||||
m_Monitors[m_CurrentMonitorID].OnMonitorGUI(r);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 27fa95984763d9d47bbad59e7fdb66fe
|
||||
timeCreated: 1467188923
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,79 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
public class PostProcessingModelEditor
|
||||
{
|
||||
public PostProcessingModel target { get; internal set; }
|
||||
public SerializedProperty serializedProperty { get; internal set; }
|
||||
|
||||
protected SerializedProperty m_SettingsProperty;
|
||||
protected SerializedProperty m_EnabledProperty;
|
||||
|
||||
internal bool alwaysEnabled = false;
|
||||
internal PostProcessingProfile profile;
|
||||
internal PostProcessingInspector inspector;
|
||||
|
||||
internal void OnPreEnable()
|
||||
{
|
||||
m_SettingsProperty = serializedProperty.FindPropertyRelative("m_Settings");
|
||||
m_EnabledProperty = serializedProperty.FindPropertyRelative("m_Enabled");
|
||||
|
||||
OnEnable();
|
||||
}
|
||||
|
||||
public virtual void OnEnable()
|
||||
{}
|
||||
|
||||
public virtual void OnDisable()
|
||||
{}
|
||||
|
||||
internal void OnGUI()
|
||||
{
|
||||
GUILayout.Space(5);
|
||||
|
||||
var display = alwaysEnabled
|
||||
? EditorGUIHelper.Header(serializedProperty.displayName, m_SettingsProperty, Reset)
|
||||
: EditorGUIHelper.Header(serializedProperty.displayName, m_SettingsProperty, m_EnabledProperty, Reset);
|
||||
|
||||
if (display)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
using (new EditorGUI.DisabledGroupScope(!m_EnabledProperty.boolValue))
|
||||
{
|
||||
OnInspectorGUI();
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
var obj = serializedProperty.serializedObject;
|
||||
Undo.RecordObject(obj.targetObject, "Reset");
|
||||
target.Reset();
|
||||
EditorUtility.SetDirty(obj.targetObject);
|
||||
}
|
||||
|
||||
public virtual void OnInspectorGUI()
|
||||
{}
|
||||
|
||||
public void Repaint()
|
||||
{
|
||||
inspector.Repaint();
|
||||
}
|
||||
|
||||
protected SerializedProperty FindSetting<T, TValue>(Expression<Func<T, TValue>> expr)
|
||||
{
|
||||
return m_SettingsProperty.FindPropertyRelative(ReflectionUtils.GetFieldPath(expr));
|
||||
}
|
||||
|
||||
protected SerializedProperty FindSetting<T, TValue>(SerializedProperty prop, Expression<Func<T, TValue>> expr)
|
||||
{
|
||||
return prop.FindPropertyRelative(ReflectionUtils.GetFieldPath(expr));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: afe296d4ede60a0479734dc8c7df82c2
|
||||
timeCreated: 1467188923
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using MonitorSettings = UnityEngine.PostProcessing.PostProcessingProfile.MonitorSettings;
|
||||
|
||||
public abstract class PostProcessingMonitor : IDisposable
|
||||
{
|
||||
protected MonitorSettings m_MonitorSettings;
|
||||
protected PostProcessingInspector m_BaseEditor;
|
||||
|
||||
public void Init(MonitorSettings monitorSettings, PostProcessingInspector baseEditor)
|
||||
{
|
||||
m_MonitorSettings = monitorSettings;
|
||||
m_BaseEditor = baseEditor;
|
||||
}
|
||||
|
||||
public abstract bool IsSupported();
|
||||
|
||||
public abstract GUIContent GetMonitorTitle();
|
||||
|
||||
public virtual void OnMonitorSettings()
|
||||
{}
|
||||
|
||||
public abstract void OnMonitorGUI(Rect r);
|
||||
|
||||
public virtual void OnFrameData(RenderTexture source)
|
||||
{}
|
||||
|
||||
public virtual void Dispose()
|
||||
{}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 801186e9e649457469bcddd8ee391c71
|
||||
timeCreated: 1467188912
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ced92f1cc2085ae48acacc79a2b8e196
|
||||
folderAsset: yes
|
||||
timeCreated: 1467189428
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,36 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(GetSetAttribute))]
|
||||
sealed class GetSetDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
var attribute = (GetSetAttribute)base.attribute;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUI.PropertyField(position, property, label);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
attribute.dirty = true;
|
||||
}
|
||||
else if (attribute.dirty)
|
||||
{
|
||||
var parent = ReflectionUtils.GetParentObject(property.propertyPath, property.serializedObject.targetObject);
|
||||
|
||||
var type = parent.GetType();
|
||||
var info = type.GetProperty(attribute.name);
|
||||
|
||||
if (info == null)
|
||||
Debug.LogError("Invalid property name \"" + attribute.name + "\"");
|
||||
else
|
||||
info.SetValue(parent, fieldInfo.GetValue(parent), null);
|
||||
|
||||
attribute.dirty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e1a43b92f2bbd914ca2e6b4c6a5dba48
|
||||
timeCreated: 1460383963
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,30 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(UnityEngine.PostProcessing.MinAttribute))]
|
||||
sealed class MinDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
UnityEngine.PostProcessing.MinAttribute attribute = (UnityEngine.PostProcessing.MinAttribute)base.attribute;
|
||||
|
||||
if (property.propertyType == SerializedPropertyType.Integer)
|
||||
{
|
||||
int v = EditorGUI.IntField(position, label, property.intValue);
|
||||
property.intValue = (int)Mathf.Max(v, attribute.min);
|
||||
}
|
||||
else if (property.propertyType == SerializedPropertyType.Float)
|
||||
{
|
||||
float v = EditorGUI.FloatField(position, label, property.floatValue);
|
||||
property.floatValue = Mathf.Max(v, attribute.min);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUI.LabelField(position, label.text, "Use Min with float or int.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8995f52f410f0fb4cb1bdaa71a16e04e
|
||||
timeCreated: 1467364278
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,244 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(TrackballGroupAttribute))]
|
||||
sealed class TrackballGroupDrawer : PropertyDrawer
|
||||
{
|
||||
static Material s_Material;
|
||||
|
||||
const int k_MinWheelSize = 80;
|
||||
const int k_MaxWheelSize = 256;
|
||||
|
||||
bool m_ResetState;
|
||||
|
||||
// Cached trackball computation methods (for speed reasons)
|
||||
static Dictionary<string, MethodInfo> m_TrackballMethods = new Dictionary<string, MethodInfo>();
|
||||
|
||||
internal static int m_Size
|
||||
{
|
||||
get
|
||||
{
|
||||
int size = Mathf.FloorToInt(EditorGUIUtility.currentViewWidth / 3f) - 18;
|
||||
size = Mathf.Clamp(size, k_MinWheelSize, k_MaxWheelSize);
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (s_Material == null)
|
||||
s_Material = new Material(Shader.Find("Hidden/Post FX/UI/Trackball")) { hideFlags = HideFlags.HideAndDontSave };
|
||||
|
||||
position = new Rect(position.x, position.y, position.width / 3f, position.height);
|
||||
int size = m_Size;
|
||||
position.x += 5f;
|
||||
|
||||
var enumerator = property.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
var prop = enumerator.Current as SerializedProperty;
|
||||
if (prop == null || prop.propertyType != SerializedPropertyType.Color)
|
||||
continue;
|
||||
|
||||
OnWheelGUI(position, size, prop.Copy());
|
||||
position.x += position.width;
|
||||
}
|
||||
}
|
||||
|
||||
void OnWheelGUI(Rect position, int size, SerializedProperty property)
|
||||
{
|
||||
if (Event.current.type == EventType.Layout)
|
||||
return;
|
||||
|
||||
var value = property.colorValue;
|
||||
float offset = value.a;
|
||||
|
||||
var wheelDrawArea = position;
|
||||
wheelDrawArea.height = size;
|
||||
|
||||
if (wheelDrawArea.width > wheelDrawArea.height)
|
||||
{
|
||||
wheelDrawArea.x += (wheelDrawArea.width - wheelDrawArea.height) / 2.0f;
|
||||
wheelDrawArea.width = position.height;
|
||||
}
|
||||
|
||||
wheelDrawArea.width = wheelDrawArea.height;
|
||||
|
||||
float hsize = size / 2f;
|
||||
float radius = 0.38f * size;
|
||||
Vector3 hsv;
|
||||
Color.RGBToHSV(value, out hsv.x, out hsv.y, out hsv.z);
|
||||
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
float scale = EditorGUIUtility.pixelsPerPoint;
|
||||
|
||||
// Wheel texture
|
||||
var oldRT = RenderTexture.active;
|
||||
var rt = RenderTexture.GetTemporary((int)(size * scale), (int)(size * scale), 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
|
||||
s_Material.SetFloat("_Offset", offset);
|
||||
s_Material.SetFloat("_DisabledState", GUI.enabled ? 1f : 0.5f);
|
||||
s_Material.SetVector("_Resolution", new Vector2(size * scale, size * scale / 2f));
|
||||
Graphics.Blit(null, rt, s_Material, EditorGUIUtility.isProSkin ? 0 : 1);
|
||||
RenderTexture.active = oldRT;
|
||||
|
||||
GUI.DrawTexture(wheelDrawArea, rt);
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
|
||||
// Thumb
|
||||
var thumbPos = Vector2.zero;
|
||||
float theta = hsv.x * (Mathf.PI * 2f);
|
||||
float len = hsv.y * radius;
|
||||
thumbPos.x = Mathf.Cos(theta + (Mathf.PI / 2f));
|
||||
thumbPos.y = Mathf.Sin(theta - (Mathf.PI / 2f));
|
||||
thumbPos *= len;
|
||||
var thumbSize = FxStyles.wheelThumbSize;
|
||||
var thumbSizeH = thumbSize / 2f;
|
||||
FxStyles.wheelThumb.Draw(new Rect(wheelDrawArea.x + hsize + thumbPos.x - thumbSizeH.x, wheelDrawArea.y + hsize + thumbPos.y - thumbSizeH.y, thumbSize.x, thumbSize.y), false, false, false, false);
|
||||
}
|
||||
|
||||
var bounds = wheelDrawArea;
|
||||
bounds.x += hsize - radius;
|
||||
bounds.y += hsize - radius;
|
||||
bounds.width = bounds.height = radius * 2f;
|
||||
hsv = GetInput(bounds, hsv, radius);
|
||||
value = Color.HSVToRGB(hsv.x, hsv.y, 1f);
|
||||
value.a = offset;
|
||||
|
||||
// Luminosity booster
|
||||
position = wheelDrawArea;
|
||||
float oldX = position.x;
|
||||
float oldW = position.width;
|
||||
position.y += position.height + 4f;
|
||||
position.x += (position.width - (position.width * 0.75f)) / 2f;
|
||||
position.width = position.width * 0.75f;
|
||||
position.height = EditorGUIUtility.singleLineHeight;
|
||||
value.a = GUI.HorizontalSlider(position, value.a, -1f, 1f);
|
||||
|
||||
// Advanced controls
|
||||
var data = Vector3.zero;
|
||||
|
||||
if (TryGetDisplayValue(value, property, out data))
|
||||
{
|
||||
position.x = oldX;
|
||||
position.y += position.height;
|
||||
position.width = oldW / 3f;
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(true))
|
||||
{
|
||||
GUI.Label(position, data.x.ToString("F2"), EditorStyles.centeredGreyMiniLabel);
|
||||
position.x += position.width;
|
||||
GUI.Label(position, data.y.ToString("F2"), EditorStyles.centeredGreyMiniLabel);
|
||||
position.x += position.width;
|
||||
GUI.Label(position, data.z.ToString("F2"), EditorStyles.centeredGreyMiniLabel);
|
||||
position.x += position.width;
|
||||
}
|
||||
}
|
||||
|
||||
// Title
|
||||
position.x = oldX;
|
||||
position.y += position.height;
|
||||
position.width = oldW;
|
||||
GUI.Label(position, property.displayName, EditorStyles.centeredGreyMiniLabel);
|
||||
|
||||
if (m_ResetState)
|
||||
{
|
||||
value = Color.clear;
|
||||
m_ResetState = false;
|
||||
}
|
||||
|
||||
property.colorValue = value;
|
||||
}
|
||||
|
||||
bool TryGetDisplayValue(Color color, SerializedProperty property, out Vector3 output)
|
||||
{
|
||||
output = Vector3.zero;
|
||||
MethodInfo method;
|
||||
|
||||
if (!m_TrackballMethods.TryGetValue(property.name, out method))
|
||||
{
|
||||
var field = ReflectionUtils.GetFieldInfoFromPath(property.serializedObject.targetObject, property.propertyPath);
|
||||
|
||||
if (!field.IsDefined(typeof(TrackballAttribute), false))
|
||||
return false;
|
||||
|
||||
var attr = (TrackballAttribute)field.GetCustomAttributes(typeof(TrackballAttribute), false)[0];
|
||||
const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
|
||||
method = typeof(ColorGradingComponent).GetMethod(attr.method, flags);
|
||||
m_TrackballMethods.Add(property.name, method);
|
||||
}
|
||||
|
||||
if (method == null)
|
||||
return false;
|
||||
|
||||
output = (Vector3)method.Invoke(property.serializedObject.targetObject, new object[] { color });
|
||||
return true;
|
||||
}
|
||||
|
||||
static readonly int k_ThumbHash = "colorWheelThumb".GetHashCode();
|
||||
|
||||
Vector3 GetInput(Rect bounds, Vector3 hsv, float radius)
|
||||
{
|
||||
var e = Event.current;
|
||||
var id = GUIUtility.GetControlID(k_ThumbHash, FocusType.Passive, bounds);
|
||||
|
||||
var mousePos = e.mousePosition;
|
||||
var relativePos = mousePos - new Vector2(bounds.x, bounds.y);
|
||||
|
||||
if (e.type == EventType.MouseDown && GUIUtility.hotControl == 0 && bounds.Contains(mousePos))
|
||||
{
|
||||
if (e.button == 0)
|
||||
{
|
||||
var center = new Vector2(bounds.x + radius, bounds.y + radius);
|
||||
float dist = Vector2.Distance(center, mousePos);
|
||||
|
||||
if (dist <= radius)
|
||||
{
|
||||
e.Use();
|
||||
GetWheelHueSaturation(relativePos.x, relativePos.y, radius, out hsv.x, out hsv.y);
|
||||
GUIUtility.hotControl = id;
|
||||
GUI.changed = true;
|
||||
}
|
||||
}
|
||||
else if (e.button == 1)
|
||||
{
|
||||
e.Use();
|
||||
GUI.changed = true;
|
||||
m_ResetState = true;
|
||||
}
|
||||
}
|
||||
else if (e.type == EventType.MouseDrag && e.button == 0 && GUIUtility.hotControl == id)
|
||||
{
|
||||
e.Use();
|
||||
GUI.changed = true;
|
||||
GetWheelHueSaturation(relativePos.x, relativePos.y, radius, out hsv.x, out hsv.y);
|
||||
}
|
||||
else if (e.rawType == EventType.MouseUp && e.button == 0 && GUIUtility.hotControl == id)
|
||||
{
|
||||
e.Use();
|
||||
GUIUtility.hotControl = 0;
|
||||
}
|
||||
|
||||
return hsv;
|
||||
}
|
||||
|
||||
void GetWheelHueSaturation(float x, float y, float radius, out float hue, out float saturation)
|
||||
{
|
||||
float dx = (x - radius) / radius;
|
||||
float dy = (y - radius) / radius;
|
||||
float d = Mathf.Sqrt(dx * dx + dy * dy);
|
||||
hue = Mathf.Atan2(dx, -dy);
|
||||
hue = 1f - ((hue > 0) ? hue : (Mathf.PI * 2f) + hue) / (Mathf.PI * 2f);
|
||||
saturation = Mathf.Clamp01(d);
|
||||
}
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
return m_Size + 4f * 2f + EditorGUIUtility.singleLineHeight * 3f;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a668d493c5ed56d448b53c19b2c3dfd2
|
||||
timeCreated: 1460563239
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b52c69ccefdae7545bfb4d0bf9b7df71
|
||||
folderAsset: yes
|
||||
timeCreated: 1467189428
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,847 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
public sealed class CurveEditor
|
||||
{
|
||||
#region Enums
|
||||
|
||||
enum EditMode
|
||||
{
|
||||
None,
|
||||
Moving,
|
||||
TangentEdit
|
||||
}
|
||||
|
||||
enum Tangent
|
||||
{
|
||||
In,
|
||||
Out
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Structs
|
||||
public struct Settings
|
||||
{
|
||||
public Rect bounds;
|
||||
public RectOffset padding;
|
||||
public Color selectionColor;
|
||||
public float curvePickingDistance;
|
||||
public float keyTimeClampingDistance;
|
||||
|
||||
public static Settings defaultSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Settings
|
||||
{
|
||||
bounds = new Rect(0f, 0f, 1f, 1f),
|
||||
padding = new RectOffset(10, 10, 10, 10),
|
||||
selectionColor = Color.yellow,
|
||||
curvePickingDistance = 6f,
|
||||
keyTimeClampingDistance = 1e-4f
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct CurveState
|
||||
{
|
||||
public bool visible;
|
||||
public bool editable;
|
||||
public uint minPointCount;
|
||||
public float zeroKeyConstantValue;
|
||||
public Color color;
|
||||
public float width;
|
||||
public float handleWidth;
|
||||
public bool showNonEditableHandles;
|
||||
public bool onlyShowHandlesOnSelection;
|
||||
public bool loopInBounds;
|
||||
|
||||
public static CurveState defaultState
|
||||
{
|
||||
get
|
||||
{
|
||||
return new CurveState
|
||||
{
|
||||
visible = true,
|
||||
editable = true,
|
||||
minPointCount = 2,
|
||||
zeroKeyConstantValue = 0f,
|
||||
color = Color.white,
|
||||
width = 2f,
|
||||
handleWidth = 2f,
|
||||
showNonEditableHandles = true,
|
||||
onlyShowHandlesOnSelection = false,
|
||||
loopInBounds = false
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct Selection
|
||||
{
|
||||
public SerializedProperty curve;
|
||||
public int keyframeIndex;
|
||||
public Keyframe? keyframe;
|
||||
|
||||
public Selection(SerializedProperty curve, int keyframeIndex, Keyframe? keyframe)
|
||||
{
|
||||
this.curve = curve;
|
||||
this.keyframeIndex = keyframeIndex;
|
||||
this.keyframe = keyframe;
|
||||
}
|
||||
}
|
||||
|
||||
internal struct MenuAction
|
||||
{
|
||||
internal SerializedProperty curve;
|
||||
internal int index;
|
||||
internal Vector3 position;
|
||||
|
||||
internal MenuAction(SerializedProperty curve)
|
||||
{
|
||||
this.curve = curve;
|
||||
this.index = -1;
|
||||
this.position = Vector3.zero;
|
||||
}
|
||||
|
||||
internal MenuAction(SerializedProperty curve, int index)
|
||||
{
|
||||
this.curve = curve;
|
||||
this.index = index;
|
||||
this.position = Vector3.zero;
|
||||
}
|
||||
|
||||
internal MenuAction(SerializedProperty curve, Vector3 position)
|
||||
{
|
||||
this.curve = curve;
|
||||
this.index = -1;
|
||||
this.position = position;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Fields & properties
|
||||
public Settings settings { get; private set; }
|
||||
|
||||
Dictionary<SerializedProperty, CurveState> m_Curves;
|
||||
Rect m_CurveArea;
|
||||
|
||||
SerializedProperty m_SelectedCurve;
|
||||
int m_SelectedKeyframeIndex = -1;
|
||||
|
||||
EditMode m_EditMode = EditMode.None;
|
||||
Tangent m_TangentEditMode;
|
||||
|
||||
bool m_Dirty;
|
||||
#endregion
|
||||
|
||||
#region Constructors & destructors
|
||||
public CurveEditor()
|
||||
: this(Settings.defaultSettings)
|
||||
{}
|
||||
|
||||
public CurveEditor(Settings settings)
|
||||
{
|
||||
this.settings = settings;
|
||||
m_Curves = new Dictionary<SerializedProperty, CurveState>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public API
|
||||
public void Add(params SerializedProperty[] curves)
|
||||
{
|
||||
foreach (var curve in curves)
|
||||
Add(curve, CurveState.defaultState);
|
||||
}
|
||||
|
||||
public void Add(SerializedProperty curve)
|
||||
{
|
||||
Add(curve, CurveState.defaultState);
|
||||
}
|
||||
|
||||
public void Add(SerializedProperty curve, CurveState state)
|
||||
{
|
||||
// Make sure the property is in fact an AnimationCurve
|
||||
var animCurve = curve.animationCurveValue;
|
||||
if (animCurve == null)
|
||||
throw new ArgumentException("curve");
|
||||
|
||||
if (m_Curves.ContainsKey(curve))
|
||||
Debug.LogWarning("Curve has already been added to the editor");
|
||||
|
||||
m_Curves.Add(curve, state);
|
||||
}
|
||||
|
||||
public void Remove(SerializedProperty curve)
|
||||
{
|
||||
m_Curves.Remove(curve);
|
||||
}
|
||||
|
||||
public void RemoveAll()
|
||||
{
|
||||
m_Curves.Clear();
|
||||
}
|
||||
|
||||
public CurveState GetCurveState(SerializedProperty curve)
|
||||
{
|
||||
CurveState state;
|
||||
if (!m_Curves.TryGetValue(curve, out state))
|
||||
throw new KeyNotFoundException("curve");
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
public void SetCurveState(SerializedProperty curve, CurveState state)
|
||||
{
|
||||
if (!m_Curves.ContainsKey(curve))
|
||||
throw new KeyNotFoundException("curve");
|
||||
|
||||
m_Curves[curve] = state;
|
||||
}
|
||||
|
||||
public Selection GetSelection()
|
||||
{
|
||||
Keyframe? key = null;
|
||||
if (m_SelectedKeyframeIndex > -1)
|
||||
{
|
||||
var curve = m_SelectedCurve.animationCurveValue;
|
||||
|
||||
if (m_SelectedKeyframeIndex >= curve.length)
|
||||
m_SelectedKeyframeIndex = -1;
|
||||
else
|
||||
key = curve[m_SelectedKeyframeIndex];
|
||||
}
|
||||
|
||||
return new Selection(m_SelectedCurve, m_SelectedKeyframeIndex, key);
|
||||
}
|
||||
|
||||
public void SetKeyframe(SerializedProperty curve, int keyframeIndex, Keyframe keyframe)
|
||||
{
|
||||
var animCurve = curve.animationCurveValue;
|
||||
SetKeyframe(animCurve, keyframeIndex, keyframe);
|
||||
SaveCurve(curve, animCurve);
|
||||
}
|
||||
|
||||
public bool OnGUI(Rect rect)
|
||||
{
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
m_Dirty = false;
|
||||
|
||||
GUI.BeginClip(rect);
|
||||
{
|
||||
var area = new Rect(Vector2.zero, rect.size);
|
||||
m_CurveArea = settings.padding.Remove(area);
|
||||
|
||||
foreach (var curve in m_Curves)
|
||||
OnCurveGUI(area, curve.Key, curve.Value);
|
||||
|
||||
OnGeneralUI(area);
|
||||
}
|
||||
GUI.EndClip();
|
||||
|
||||
return m_Dirty;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UI & events
|
||||
|
||||
void OnCurveGUI(Rect rect, SerializedProperty curve, CurveState state)
|
||||
{
|
||||
// Discard invisible curves
|
||||
if (!state.visible)
|
||||
return;
|
||||
|
||||
var animCurve = curve.animationCurveValue;
|
||||
var keys = animCurve.keys;
|
||||
var length = keys.Length;
|
||||
|
||||
// Curve drawing
|
||||
// Slightly dim non-editable curves
|
||||
var color = state.color;
|
||||
if (!state.editable)
|
||||
color.a *= 0.5f;
|
||||
|
||||
Handles.color = color;
|
||||
var bounds = settings.bounds;
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
var p1 = CurveToCanvas(new Vector3(bounds.xMin, state.zeroKeyConstantValue));
|
||||
var p2 = CurveToCanvas(new Vector3(bounds.xMax, state.zeroKeyConstantValue));
|
||||
Handles.DrawAAPolyLine(state.width, p1, p2);
|
||||
}
|
||||
else if (length == 1)
|
||||
{
|
||||
var p1 = CurveToCanvas(new Vector3(bounds.xMin, keys[0].value));
|
||||
var p2 = CurveToCanvas(new Vector3(bounds.xMax, keys[0].value));
|
||||
Handles.DrawAAPolyLine(state.width, p1, p2);
|
||||
}
|
||||
else
|
||||
{
|
||||
var prevKey = keys[0];
|
||||
for (int k = 1; k < length; k++)
|
||||
{
|
||||
var key = keys[k];
|
||||
var pts = BezierSegment(prevKey, key);
|
||||
|
||||
if (float.IsInfinity(prevKey.outTangent) || float.IsInfinity(key.inTangent))
|
||||
{
|
||||
var s = HardSegment(prevKey, key);
|
||||
Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]);
|
||||
}
|
||||
else Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width);
|
||||
|
||||
prevKey = key;
|
||||
}
|
||||
|
||||
// Curve extents & loops
|
||||
if (keys[0].time > bounds.xMin)
|
||||
{
|
||||
if (state.loopInBounds)
|
||||
{
|
||||
var p1 = keys[length - 1];
|
||||
p1.time -= settings.bounds.width;
|
||||
var p2 = keys[0];
|
||||
var pts = BezierSegment(p1, p2);
|
||||
|
||||
if (float.IsInfinity(p1.outTangent) || float.IsInfinity(p2.inTangent))
|
||||
{
|
||||
var s = HardSegment(p1, p2);
|
||||
Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]);
|
||||
}
|
||||
else Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width);
|
||||
}
|
||||
else
|
||||
{
|
||||
var p1 = CurveToCanvas(new Vector3(bounds.xMin, keys[0].value));
|
||||
var p2 = CurveToCanvas(keys[0]);
|
||||
Handles.DrawAAPolyLine(state.width, p1, p2);
|
||||
}
|
||||
}
|
||||
|
||||
if (keys[length - 1].time < bounds.xMax)
|
||||
{
|
||||
if (state.loopInBounds)
|
||||
{
|
||||
var p1 = keys[length - 1];
|
||||
var p2 = keys[0];
|
||||
p2.time += settings.bounds.width;
|
||||
var pts = BezierSegment(p1, p2);
|
||||
|
||||
if (float.IsInfinity(p1.outTangent) || float.IsInfinity(p2.inTangent))
|
||||
{
|
||||
var s = HardSegment(p1, p2);
|
||||
Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]);
|
||||
}
|
||||
else Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width);
|
||||
}
|
||||
else
|
||||
{
|
||||
var p1 = CurveToCanvas(keys[length - 1]);
|
||||
var p2 = CurveToCanvas(new Vector3(bounds.xMax, keys[length - 1].value));
|
||||
Handles.DrawAAPolyLine(state.width, p1, p2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure selection is correct (undo can break it)
|
||||
bool isCurrentlySelectedCurve = curve == m_SelectedCurve;
|
||||
|
||||
if (isCurrentlySelectedCurve && m_SelectedKeyframeIndex >= length)
|
||||
m_SelectedKeyframeIndex = -1;
|
||||
|
||||
// Handles & keys
|
||||
for (int k = 0; k < length; k++)
|
||||
{
|
||||
bool isCurrentlySelectedKeyframe = k == m_SelectedKeyframeIndex;
|
||||
var e = Event.current;
|
||||
|
||||
var pos = CurveToCanvas(keys[k]);
|
||||
var hitRect = new Rect(pos.x - 8f, pos.y - 8f, 16f, 16f);
|
||||
var offset = isCurrentlySelectedCurve
|
||||
? new RectOffset(5, 5, 5, 5)
|
||||
: new RectOffset(6, 6, 6, 6);
|
||||
|
||||
var outTangent = pos + CurveTangentToCanvas(keys[k].outTangent).normalized * 40f;
|
||||
var inTangent = pos - CurveTangentToCanvas(keys[k].inTangent).normalized * 40f;
|
||||
var inTangentHitRect = new Rect(inTangent.x - 7f, inTangent.y - 7f, 14f, 14f);
|
||||
var outTangentHitrect = new Rect(outTangent.x - 7f, outTangent.y - 7f, 14f, 14f);
|
||||
|
||||
// Draw
|
||||
if (state.showNonEditableHandles)
|
||||
{
|
||||
if (e.type == EventType.Repaint)
|
||||
{
|
||||
var selectedColor = (isCurrentlySelectedCurve && isCurrentlySelectedKeyframe)
|
||||
? settings.selectionColor
|
||||
: state.color;
|
||||
|
||||
// Keyframe
|
||||
EditorGUI.DrawRect(offset.Remove(hitRect), selectedColor);
|
||||
|
||||
// Tangents
|
||||
if (isCurrentlySelectedCurve && (!state.onlyShowHandlesOnSelection || (state.onlyShowHandlesOnSelection && isCurrentlySelectedKeyframe)))
|
||||
{
|
||||
Handles.color = selectedColor;
|
||||
|
||||
if (k > 0 || state.loopInBounds)
|
||||
{
|
||||
Handles.DrawAAPolyLine(state.handleWidth, pos, inTangent);
|
||||
EditorGUI.DrawRect(offset.Remove(inTangentHitRect), selectedColor);
|
||||
}
|
||||
|
||||
if (k < length - 1 || state.loopInBounds)
|
||||
{
|
||||
Handles.DrawAAPolyLine(state.handleWidth, pos, outTangent);
|
||||
EditorGUI.DrawRect(offset.Remove(outTangentHitrect), selectedColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Events
|
||||
if (state.editable)
|
||||
{
|
||||
// Keyframe move
|
||||
if (m_EditMode == EditMode.Moving && e.type == EventType.MouseDrag && isCurrentlySelectedCurve && isCurrentlySelectedKeyframe)
|
||||
{
|
||||
EditMoveKeyframe(animCurve, keys, k);
|
||||
}
|
||||
|
||||
// Tangent editing
|
||||
if (m_EditMode == EditMode.TangentEdit && e.type == EventType.MouseDrag && isCurrentlySelectedCurve && isCurrentlySelectedKeyframe)
|
||||
{
|
||||
bool alreadyBroken = !(Mathf.Approximately(keys[k].inTangent, keys[k].outTangent) || (float.IsInfinity(keys[k].inTangent) && float.IsInfinity(keys[k].outTangent)));
|
||||
EditMoveTangent(animCurve, keys, k, m_TangentEditMode, e.shift || !(alreadyBroken || e.control));
|
||||
}
|
||||
|
||||
// Keyframe selection & context menu
|
||||
if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition))
|
||||
{
|
||||
if (hitRect.Contains(e.mousePosition))
|
||||
{
|
||||
if (e.button == 0)
|
||||
{
|
||||
SelectKeyframe(curve, k);
|
||||
m_EditMode = EditMode.Moving;
|
||||
e.Use();
|
||||
}
|
||||
else if (e.button == 1)
|
||||
{
|
||||
// Keyframe context menu
|
||||
var menu = new GenericMenu();
|
||||
menu.AddItem(new GUIContent("Delete Key"), false, (x) =>
|
||||
{
|
||||
var action = (MenuAction)x;
|
||||
var curveValue = action.curve.animationCurveValue;
|
||||
action.curve.serializedObject.Update();
|
||||
RemoveKeyframe(curveValue, action.index);
|
||||
m_SelectedKeyframeIndex = -1;
|
||||
SaveCurve(action.curve, curveValue);
|
||||
action.curve.serializedObject.ApplyModifiedProperties();
|
||||
}, new MenuAction(curve, k));
|
||||
menu.ShowAsContext();
|
||||
e.Use();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tangent selection & edit mode
|
||||
if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition))
|
||||
{
|
||||
if (inTangentHitRect.Contains(e.mousePosition) && (k > 0 || state.loopInBounds))
|
||||
{
|
||||
SelectKeyframe(curve, k);
|
||||
m_EditMode = EditMode.TangentEdit;
|
||||
m_TangentEditMode = Tangent.In;
|
||||
e.Use();
|
||||
}
|
||||
else if (outTangentHitrect.Contains(e.mousePosition) && (k < length - 1 || state.loopInBounds))
|
||||
{
|
||||
SelectKeyframe(curve, k);
|
||||
m_EditMode = EditMode.TangentEdit;
|
||||
m_TangentEditMode = Tangent.Out;
|
||||
e.Use();
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse up - clean up states
|
||||
if (e.rawType == EventType.MouseUp && m_EditMode != EditMode.None)
|
||||
{
|
||||
m_EditMode = EditMode.None;
|
||||
}
|
||||
|
||||
// Set cursors
|
||||
{
|
||||
EditorGUIUtility.AddCursorRect(hitRect, MouseCursor.MoveArrow);
|
||||
|
||||
if (k > 0 || state.loopInBounds)
|
||||
EditorGUIUtility.AddCursorRect(inTangentHitRect, MouseCursor.RotateArrow);
|
||||
|
||||
if (k < length - 1 || state.loopInBounds)
|
||||
EditorGUIUtility.AddCursorRect(outTangentHitrect, MouseCursor.RotateArrow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Handles.color = Color.white;
|
||||
SaveCurve(curve, animCurve);
|
||||
}
|
||||
|
||||
void OnGeneralUI(Rect rect)
|
||||
{
|
||||
var e = Event.current;
|
||||
|
||||
// Selection
|
||||
if (e.type == EventType.MouseDown)
|
||||
{
|
||||
GUI.FocusControl(null);
|
||||
m_SelectedCurve = null;
|
||||
m_SelectedKeyframeIndex = -1;
|
||||
bool used = false;
|
||||
|
||||
var hit = CanvasToCurve(e.mousePosition);
|
||||
float curvePickValue = CurveToCanvas(hit).y;
|
||||
|
||||
// Try and select a curve
|
||||
foreach (var curve in m_Curves)
|
||||
{
|
||||
if (!curve.Value.editable || !curve.Value.visible)
|
||||
continue;
|
||||
|
||||
var prop = curve.Key;
|
||||
var state = curve.Value;
|
||||
var animCurve = prop.animationCurveValue;
|
||||
float hitY = animCurve.length == 0
|
||||
? state.zeroKeyConstantValue
|
||||
: animCurve.Evaluate(hit.x);
|
||||
|
||||
var curvePos = CurveToCanvas(new Vector3(hit.x, hitY));
|
||||
|
||||
if (Mathf.Abs(curvePos.y - curvePickValue) < settings.curvePickingDistance)
|
||||
{
|
||||
m_SelectedCurve = prop;
|
||||
|
||||
if (e.clickCount == 2 && e.button == 0)
|
||||
{
|
||||
// Create a keyframe on double-click on this curve
|
||||
EditCreateKeyframe(animCurve, hit, true, state.zeroKeyConstantValue);
|
||||
SaveCurve(prop, animCurve);
|
||||
}
|
||||
else if (e.button == 1)
|
||||
{
|
||||
// Curve context menu
|
||||
var menu = new GenericMenu();
|
||||
menu.AddItem(new GUIContent("Add Key"), false, (x) =>
|
||||
{
|
||||
var action = (MenuAction)x;
|
||||
var curveValue = action.curve.animationCurveValue;
|
||||
action.curve.serializedObject.Update();
|
||||
EditCreateKeyframe(curveValue, hit, true, 0f);
|
||||
SaveCurve(action.curve, curveValue);
|
||||
action.curve.serializedObject.ApplyModifiedProperties();
|
||||
}, new MenuAction(prop, hit));
|
||||
menu.ShowAsContext();
|
||||
e.Use();
|
||||
used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e.clickCount == 2 && e.button == 0 && m_SelectedCurve == null)
|
||||
{
|
||||
// Create a keyframe on every curve on double-click
|
||||
foreach (var curve in m_Curves)
|
||||
{
|
||||
if (!curve.Value.editable || !curve.Value.visible)
|
||||
continue;
|
||||
|
||||
var prop = curve.Key;
|
||||
var state = curve.Value;
|
||||
var animCurve = prop.animationCurveValue;
|
||||
EditCreateKeyframe(animCurve, hit, e.alt, state.zeroKeyConstantValue);
|
||||
SaveCurve(prop, animCurve);
|
||||
}
|
||||
}
|
||||
else if (!used && e.button == 1)
|
||||
{
|
||||
// Global context menu
|
||||
var menu = new GenericMenu();
|
||||
menu.AddItem(new GUIContent("Add Key At Position"), false, () => ContextMenuAddKey(hit, false));
|
||||
menu.AddItem(new GUIContent("Add Key On Curves"), false, () => ContextMenuAddKey(hit, true));
|
||||
menu.ShowAsContext();
|
||||
}
|
||||
|
||||
e.Use();
|
||||
}
|
||||
|
||||
// Delete selected key(s)
|
||||
if (e.type == EventType.KeyDown && (e.keyCode == KeyCode.Delete || e.keyCode == KeyCode.Backspace))
|
||||
{
|
||||
if (m_SelectedKeyframeIndex != -1 && m_SelectedCurve != null)
|
||||
{
|
||||
var animCurve = m_SelectedCurve.animationCurveValue;
|
||||
var length = animCurve.length;
|
||||
|
||||
if (m_Curves[m_SelectedCurve].minPointCount < length && length >= 0)
|
||||
{
|
||||
EditDeleteKeyframe(animCurve, m_SelectedKeyframeIndex);
|
||||
m_SelectedKeyframeIndex = -1;
|
||||
SaveCurve(m_SelectedCurve, animCurve);
|
||||
}
|
||||
|
||||
e.Use();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SaveCurve(SerializedProperty prop, AnimationCurve curve)
|
||||
{
|
||||
prop.animationCurveValue = curve;
|
||||
}
|
||||
|
||||
void Invalidate()
|
||||
{
|
||||
m_Dirty = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Keyframe manipulations
|
||||
|
||||
void SelectKeyframe(SerializedProperty curve, int keyframeIndex)
|
||||
{
|
||||
m_SelectedKeyframeIndex = keyframeIndex;
|
||||
m_SelectedCurve = curve;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void ContextMenuAddKey(Vector3 hit, bool createOnCurve)
|
||||
{
|
||||
SerializedObject serializedObject = null;
|
||||
|
||||
foreach (var curve in m_Curves)
|
||||
{
|
||||
if (!curve.Value.editable || !curve.Value.visible)
|
||||
continue;
|
||||
|
||||
var prop = curve.Key;
|
||||
var state = curve.Value;
|
||||
|
||||
if (serializedObject == null)
|
||||
{
|
||||
serializedObject = prop.serializedObject;
|
||||
serializedObject.Update();
|
||||
}
|
||||
|
||||
var animCurve = prop.animationCurveValue;
|
||||
EditCreateKeyframe(animCurve, hit, createOnCurve, state.zeroKeyConstantValue);
|
||||
SaveCurve(prop, animCurve);
|
||||
}
|
||||
|
||||
if (serializedObject != null)
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void EditCreateKeyframe(AnimationCurve curve, Vector3 position, bool createOnCurve, float zeroKeyConstantValue)
|
||||
{
|
||||
float tangent = EvaluateTangent(curve, position.x);
|
||||
|
||||
if (createOnCurve)
|
||||
{
|
||||
position.y = curve.length == 0
|
||||
? zeroKeyConstantValue
|
||||
: curve.Evaluate(position.x);
|
||||
}
|
||||
|
||||
AddKeyframe(curve, new Keyframe(position.x, position.y, tangent, tangent));
|
||||
}
|
||||
|
||||
void EditDeleteKeyframe(AnimationCurve curve, int keyframeIndex)
|
||||
{
|
||||
RemoveKeyframe(curve, keyframeIndex);
|
||||
}
|
||||
|
||||
void AddKeyframe(AnimationCurve curve, Keyframe newValue)
|
||||
{
|
||||
curve.AddKey(newValue);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void RemoveKeyframe(AnimationCurve curve, int keyframeIndex)
|
||||
{
|
||||
curve.RemoveKey(keyframeIndex);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void SetKeyframe(AnimationCurve curve, int keyframeIndex, Keyframe newValue)
|
||||
{
|
||||
var keys = curve.keys;
|
||||
|
||||
if (keyframeIndex > 0)
|
||||
newValue.time = Mathf.Max(keys[keyframeIndex - 1].time + settings.keyTimeClampingDistance, newValue.time);
|
||||
|
||||
if (keyframeIndex < keys.Length - 1)
|
||||
newValue.time = Mathf.Min(keys[keyframeIndex + 1].time - settings.keyTimeClampingDistance, newValue.time);
|
||||
|
||||
curve.MoveKey(keyframeIndex, newValue);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void EditMoveKeyframe(AnimationCurve curve, Keyframe[] keys, int keyframeIndex)
|
||||
{
|
||||
var key = CanvasToCurve(Event.current.mousePosition);
|
||||
float inTgt = keys[keyframeIndex].inTangent;
|
||||
float outTgt = keys[keyframeIndex].outTangent;
|
||||
SetKeyframe(curve, keyframeIndex, new Keyframe(key.x, key.y, inTgt, outTgt));
|
||||
}
|
||||
|
||||
void EditMoveTangent(AnimationCurve curve, Keyframe[] keys, int keyframeIndex, Tangent targetTangent, bool linkTangents)
|
||||
{
|
||||
var pos = CanvasToCurve(Event.current.mousePosition);
|
||||
|
||||
float time = keys[keyframeIndex].time;
|
||||
float value = keys[keyframeIndex].value;
|
||||
|
||||
pos -= new Vector3(time, value);
|
||||
|
||||
if (targetTangent == Tangent.In && pos.x > 0f)
|
||||
pos.x = 0f;
|
||||
|
||||
if (targetTangent == Tangent.Out && pos.x < 0f)
|
||||
pos.x = 0f;
|
||||
|
||||
float tangent;
|
||||
|
||||
if (Mathf.Approximately(pos.x, 0f))
|
||||
tangent = pos.y < 0f ? float.PositiveInfinity : float.NegativeInfinity;
|
||||
else
|
||||
tangent = pos.y / pos.x;
|
||||
|
||||
float inTangent = keys[keyframeIndex].inTangent;
|
||||
float outTangent = keys[keyframeIndex].outTangent;
|
||||
|
||||
if (targetTangent == Tangent.In || linkTangents)
|
||||
inTangent = tangent;
|
||||
if (targetTangent == Tangent.Out || linkTangents)
|
||||
outTangent = tangent;
|
||||
|
||||
SetKeyframe(curve, keyframeIndex, new Keyframe(time, value, inTangent, outTangent));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Maths utilities
|
||||
|
||||
Vector3 CurveToCanvas(Keyframe keyframe)
|
||||
{
|
||||
return CurveToCanvas(new Vector3(keyframe.time, keyframe.value));
|
||||
}
|
||||
|
||||
Vector3 CurveToCanvas(Vector3 position)
|
||||
{
|
||||
var bounds = settings.bounds;
|
||||
var output = new Vector3((position.x - bounds.x) / (bounds.xMax - bounds.x), (position.y - bounds.y) / (bounds.yMax - bounds.y));
|
||||
output.x = output.x * (m_CurveArea.xMax - m_CurveArea.xMin) + m_CurveArea.xMin;
|
||||
output.y = (1f - output.y) * (m_CurveArea.yMax - m_CurveArea.yMin) + m_CurveArea.yMin;
|
||||
return output;
|
||||
}
|
||||
|
||||
Vector3 CanvasToCurve(Vector3 position)
|
||||
{
|
||||
var bounds = settings.bounds;
|
||||
var output = position;
|
||||
output.x = (output.x - m_CurveArea.xMin) / (m_CurveArea.xMax - m_CurveArea.xMin);
|
||||
output.y = (output.y - m_CurveArea.yMin) / (m_CurveArea.yMax - m_CurveArea.yMin);
|
||||
output.x = Mathf.Lerp(bounds.x, bounds.xMax, output.x);
|
||||
output.y = Mathf.Lerp(bounds.yMax, bounds.y, output.y);
|
||||
return output;
|
||||
}
|
||||
|
||||
Vector3 CurveTangentToCanvas(float tangent)
|
||||
{
|
||||
if (!float.IsInfinity(tangent))
|
||||
{
|
||||
var bounds = settings.bounds;
|
||||
float ratio = (m_CurveArea.width / m_CurveArea.height) / ((bounds.xMax - bounds.x) / (bounds.yMax - bounds.y));
|
||||
return new Vector3(1f, -tangent / ratio).normalized;
|
||||
}
|
||||
|
||||
return float.IsPositiveInfinity(tangent) ? Vector3.up : Vector3.down;
|
||||
}
|
||||
|
||||
Vector3[] BezierSegment(Keyframe start, Keyframe end)
|
||||
{
|
||||
var segment = new Vector3[4];
|
||||
|
||||
segment[0] = CurveToCanvas(new Vector3(start.time, start.value));
|
||||
segment[3] = CurveToCanvas(new Vector3(end.time, end.value));
|
||||
|
||||
float middle = start.time + ((end.time - start.time) * 0.333333f);
|
||||
float middle2 = start.time + ((end.time - start.time) * 0.666666f);
|
||||
|
||||
segment[1] = CurveToCanvas(new Vector3(middle, ProjectTangent(start.time, start.value, start.outTangent, middle)));
|
||||
segment[2] = CurveToCanvas(new Vector3(middle2, ProjectTangent(end.time, end.value, end.inTangent, middle2)));
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
Vector3[] HardSegment(Keyframe start, Keyframe end)
|
||||
{
|
||||
var segment = new Vector3[3];
|
||||
|
||||
segment[0] = CurveToCanvas(start);
|
||||
segment[1] = CurveToCanvas(new Vector3(end.time, start.value));
|
||||
segment[2] = CurveToCanvas(end);
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
float ProjectTangent(float inPosition, float inValue, float inTangent, float projPosition)
|
||||
{
|
||||
return inValue + ((projPosition - inPosition) * inTangent);
|
||||
}
|
||||
|
||||
float EvaluateTangent(AnimationCurve curve, float time)
|
||||
{
|
||||
int prev = -1, next = 0;
|
||||
for (int i = 0; i < curve.keys.Length; i++)
|
||||
{
|
||||
if (time > curve.keys[i].time)
|
||||
{
|
||||
prev = i;
|
||||
next = i + 1;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
if (next == 0)
|
||||
return 0f;
|
||||
|
||||
if (prev == curve.keys.Length - 1)
|
||||
return 0f;
|
||||
|
||||
const float kD = 1e-3f;
|
||||
float tp = Mathf.Max(time - kD, curve.keys[prev].time);
|
||||
float tn = Mathf.Min(time + kD, curve.keys[next].time);
|
||||
|
||||
float vp = curve.Evaluate(tp);
|
||||
float vn = curve.Evaluate(tn);
|
||||
|
||||
if (Mathf.Approximately(tn, tp))
|
||||
return (vn - vp > 0f) ? float.PositiveInfinity : float.NegativeInfinity;
|
||||
|
||||
return (vn - vp) / (tn - tp);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: afb349ef0bffd144db2bdd25630f648e
|
||||
timeCreated: 1472650750
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,194 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using UnityEngine.PostProcessing;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
public static class EditorGUIHelper
|
||||
{
|
||||
static EditorGUIHelper()
|
||||
{
|
||||
s_GUIContentCache = new Dictionary<string, GUIContent>();
|
||||
}
|
||||
|
||||
#region GUIContent caching
|
||||
|
||||
static Dictionary<string, GUIContent> s_GUIContentCache;
|
||||
|
||||
public static GUIContent GetContent(string textAndTooltip)
|
||||
{
|
||||
if (string.IsNullOrEmpty(textAndTooltip))
|
||||
return GUIContent.none;
|
||||
|
||||
GUIContent content;
|
||||
|
||||
if (!s_GUIContentCache.TryGetValue(textAndTooltip, out content))
|
||||
{
|
||||
var s = textAndTooltip.Split('|');
|
||||
content = new GUIContent(s[0]);
|
||||
|
||||
if (s.Length > 1 && !string.IsNullOrEmpty(s[1]))
|
||||
content.tooltip = s[1];
|
||||
|
||||
s_GUIContentCache.Add(textAndTooltip, content);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static bool Header(string title, SerializedProperty group, Action resetAction)
|
||||
{
|
||||
var rect = GUILayoutUtility.GetRect(16f, 22f, FxStyles.header);
|
||||
GUI.Box(rect, title, FxStyles.header);
|
||||
|
||||
var display = group == null || group.isExpanded;
|
||||
|
||||
var foldoutRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f);
|
||||
var e = Event.current;
|
||||
|
||||
var popupRect = new Rect(rect.x + rect.width - FxStyles.paneOptionsIcon.width - 5f, rect.y + FxStyles.paneOptionsIcon.height / 2f + 1f, FxStyles.paneOptionsIcon.width, FxStyles.paneOptionsIcon.height);
|
||||
GUI.DrawTexture(popupRect, FxStyles.paneOptionsIcon);
|
||||
|
||||
if (e.type == EventType.Repaint)
|
||||
FxStyles.headerFoldout.Draw(foldoutRect, false, false, display, false);
|
||||
|
||||
if (e.type == EventType.MouseDown)
|
||||
{
|
||||
if (popupRect.Contains(e.mousePosition))
|
||||
{
|
||||
var popup = new GenericMenu();
|
||||
popup.AddItem(GetContent("Reset"), false, () => resetAction());
|
||||
popup.AddSeparator(string.Empty);
|
||||
popup.AddItem(GetContent("Copy Settings"), false, () => CopySettings(group));
|
||||
|
||||
if (CanPaste(group))
|
||||
popup.AddItem(GetContent("Paste Settings"), false, () => PasteSettings(group));
|
||||
else
|
||||
popup.AddDisabledItem(GetContent("Paste Settings"));
|
||||
|
||||
popup.ShowAsContext();
|
||||
}
|
||||
else if (rect.Contains(e.mousePosition) && group != null)
|
||||
{
|
||||
display = !display;
|
||||
|
||||
if (group != null)
|
||||
group.isExpanded = !group.isExpanded;
|
||||
|
||||
e.Use();
|
||||
}
|
||||
}
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
public static bool Header(string title, SerializedProperty group, SerializedProperty enabledField, Action resetAction)
|
||||
{
|
||||
var field = ReflectionUtils.GetFieldInfoFromPath(enabledField.serializedObject.targetObject, enabledField.propertyPath);
|
||||
object parent = null;
|
||||
PropertyInfo prop = null;
|
||||
|
||||
if (field != null && field.IsDefined(typeof(GetSetAttribute), false))
|
||||
{
|
||||
var attr = (GetSetAttribute)field.GetCustomAttributes(typeof(GetSetAttribute), false)[0];
|
||||
parent = ReflectionUtils.GetParentObject(enabledField.propertyPath, enabledField.serializedObject.targetObject);
|
||||
prop = parent.GetType().GetProperty(attr.name);
|
||||
}
|
||||
|
||||
var display = group == null || group.isExpanded;
|
||||
var enabled = enabledField.boolValue;
|
||||
|
||||
var rect = GUILayoutUtility.GetRect(16f, 22f, FxStyles.header);
|
||||
GUI.Box(rect, title, FxStyles.header);
|
||||
|
||||
var toggleRect = new Rect(rect.x + 4f, rect.y + 4f, 13f, 13f);
|
||||
var e = Event.current;
|
||||
|
||||
var popupRect = new Rect(rect.x + rect.width - FxStyles.paneOptionsIcon.width - 5f, rect.y + FxStyles.paneOptionsIcon.height / 2f + 1f, FxStyles.paneOptionsIcon.width, FxStyles.paneOptionsIcon.height);
|
||||
GUI.DrawTexture(popupRect, FxStyles.paneOptionsIcon);
|
||||
|
||||
if (e.type == EventType.Repaint)
|
||||
FxStyles.headerCheckbox.Draw(toggleRect, false, false, enabled, false);
|
||||
|
||||
if (e.type == EventType.MouseDown)
|
||||
{
|
||||
const float kOffset = 2f;
|
||||
toggleRect.x -= kOffset;
|
||||
toggleRect.y -= kOffset;
|
||||
toggleRect.width += kOffset * 2f;
|
||||
toggleRect.height += kOffset * 2f;
|
||||
|
||||
if (toggleRect.Contains(e.mousePosition))
|
||||
{
|
||||
enabledField.boolValue = !enabledField.boolValue;
|
||||
|
||||
if (prop != null)
|
||||
prop.SetValue(parent, enabledField.boolValue, null);
|
||||
|
||||
e.Use();
|
||||
}
|
||||
else if (popupRect.Contains(e.mousePosition))
|
||||
{
|
||||
var popup = new GenericMenu();
|
||||
popup.AddItem(GetContent("Reset"), false, () => resetAction());
|
||||
popup.AddSeparator(string.Empty);
|
||||
popup.AddItem(GetContent("Copy Settings"), false, () => CopySettings(group));
|
||||
|
||||
if (CanPaste(group))
|
||||
popup.AddItem(GetContent("Paste Settings"), false, () => PasteSettings(group));
|
||||
else
|
||||
popup.AddDisabledItem(GetContent("Paste Settings"));
|
||||
|
||||
popup.ShowAsContext();
|
||||
}
|
||||
else if (rect.Contains(e.mousePosition) && group != null)
|
||||
{
|
||||
display = !display;
|
||||
group.isExpanded = !group.isExpanded;
|
||||
e.Use();
|
||||
}
|
||||
}
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
static void CopySettings(SerializedProperty settings)
|
||||
{
|
||||
var t = typeof(PostProcessingProfile);
|
||||
var settingsStruct = ReflectionUtils.GetFieldValueFromPath(settings.serializedObject.targetObject, ref t, settings.propertyPath);
|
||||
var serializedString = t.ToString() + '|' + JsonUtility.ToJson(settingsStruct);
|
||||
EditorGUIUtility.systemCopyBuffer = serializedString;
|
||||
}
|
||||
|
||||
static bool CanPaste(SerializedProperty settings)
|
||||
{
|
||||
var data = EditorGUIUtility.systemCopyBuffer;
|
||||
|
||||
if (string.IsNullOrEmpty(data))
|
||||
return false;
|
||||
|
||||
var parts = data.Split('|');
|
||||
|
||||
if (string.IsNullOrEmpty(parts[0]))
|
||||
return false;
|
||||
|
||||
var field = ReflectionUtils.GetFieldInfoFromPath(settings.serializedObject.targetObject, settings.propertyPath);
|
||||
return parts[0] == field.FieldType.ToString();
|
||||
}
|
||||
|
||||
static void PasteSettings(SerializedProperty settings)
|
||||
{
|
||||
Undo.RecordObject(settings.serializedObject.targetObject, "Paste effect settings");
|
||||
var field = ReflectionUtils.GetFieldInfoFromPath(settings.serializedObject.targetObject, settings.propertyPath);
|
||||
var json = EditorGUIUtility.systemCopyBuffer.Substring(field.FieldType.ToString().Length + 1);
|
||||
var obj = JsonUtility.FromJson(json, field.FieldType);
|
||||
var parent = ReflectionUtils.GetParentObject(settings.propertyPath, settings.serializedObject.targetObject);
|
||||
field.SetValue(parent, obj, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, CultureInfo.CurrentCulture);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7226e17fa48c86148a3d15584e21b4cb
|
||||
timeCreated: 1460477750
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,58 @@
|
|||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
using UnityObject = Object;
|
||||
|
||||
static class EditorResources
|
||||
{
|
||||
static string m_EditorResourcesPath = string.Empty;
|
||||
|
||||
internal static string editorResourcesPath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(m_EditorResourcesPath))
|
||||
{
|
||||
string path;
|
||||
|
||||
if (SearchForEditorResourcesPath(out path))
|
||||
m_EditorResourcesPath = path;
|
||||
else
|
||||
Debug.LogError("Unable to locate editor resources. Make sure the PostProcessing package has been installed correctly.");
|
||||
}
|
||||
|
||||
return m_EditorResourcesPath;
|
||||
}
|
||||
}
|
||||
|
||||
internal static T Load<T>(string name)
|
||||
where T : UnityObject
|
||||
{
|
||||
return AssetDatabase.LoadAssetAtPath<T>(editorResourcesPath + name);
|
||||
}
|
||||
|
||||
static bool SearchForEditorResourcesPath(out string path)
|
||||
{
|
||||
path = string.Empty;
|
||||
|
||||
string searchStr = "/PostProcessing/Editor Resources/";
|
||||
string str = null;
|
||||
|
||||
foreach (var assetPath in AssetDatabase.GetAllAssetPaths())
|
||||
{
|
||||
if (assetPath.Contains(searchStr))
|
||||
{
|
||||
str = assetPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (str == null)
|
||||
return false;
|
||||
|
||||
path = str.Substring(0, str.LastIndexOf(searchStr) + searchStr.Length);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a66d7b0165140a1439be89b5afc000fb
|
||||
timeCreated: 1476177015
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,111 @@
|
|||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
public static class FxStyles
|
||||
{
|
||||
public static GUIStyle tickStyleRight;
|
||||
public static GUIStyle tickStyleLeft;
|
||||
public static GUIStyle tickStyleCenter;
|
||||
|
||||
public static GUIStyle preSlider;
|
||||
public static GUIStyle preSliderThumb;
|
||||
public static GUIStyle preButton;
|
||||
public static GUIStyle preDropdown;
|
||||
|
||||
public static GUIStyle preLabel;
|
||||
public static GUIStyle hueCenterCursor;
|
||||
public static GUIStyle hueRangeCursor;
|
||||
|
||||
public static GUIStyle centeredBoldLabel;
|
||||
public static GUIStyle wheelThumb;
|
||||
public static Vector2 wheelThumbSize;
|
||||
|
||||
public static GUIStyle header;
|
||||
public static GUIStyle headerCheckbox;
|
||||
public static GUIStyle headerFoldout;
|
||||
|
||||
public static Texture2D playIcon;
|
||||
public static Texture2D checkerIcon;
|
||||
public static Texture2D paneOptionsIcon;
|
||||
|
||||
public static GUIStyle centeredMiniLabel;
|
||||
|
||||
static FxStyles()
|
||||
{
|
||||
tickStyleRight = new GUIStyle("Label")
|
||||
{
|
||||
alignment = TextAnchor.MiddleRight,
|
||||
fontSize = 9
|
||||
};
|
||||
|
||||
tickStyleLeft = new GUIStyle("Label")
|
||||
{
|
||||
alignment = TextAnchor.MiddleLeft,
|
||||
fontSize = 9
|
||||
};
|
||||
|
||||
tickStyleCenter = new GUIStyle("Label")
|
||||
{
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
fontSize = 9
|
||||
};
|
||||
|
||||
preSlider = new GUIStyle("PreSlider");
|
||||
preSliderThumb = new GUIStyle("PreSliderThumb");
|
||||
preButton = new GUIStyle("PreButton");
|
||||
preDropdown = new GUIStyle("preDropdown");
|
||||
|
||||
preLabel = new GUIStyle("ShurikenLabel");
|
||||
|
||||
hueCenterCursor = new GUIStyle("ColorPicker2DThumb")
|
||||
{
|
||||
normal = { background = (Texture2D)EditorGUIUtility.LoadRequired("Builtin Skins/DarkSkin/Images/ShurikenPlus.png") },
|
||||
fixedWidth = 6,
|
||||
fixedHeight = 6
|
||||
};
|
||||
|
||||
hueRangeCursor = new GUIStyle(hueCenterCursor)
|
||||
{
|
||||
normal = { background = (Texture2D)EditorGUIUtility.LoadRequired("Builtin Skins/DarkSkin/Images/CircularToggle_ON.png") }
|
||||
};
|
||||
|
||||
wheelThumb = new GUIStyle("ColorPicker2DThumb");
|
||||
|
||||
centeredBoldLabel = new GUIStyle(GUI.skin.GetStyle("Label"))
|
||||
{
|
||||
alignment = TextAnchor.UpperCenter,
|
||||
fontStyle = FontStyle.Bold
|
||||
};
|
||||
|
||||
centeredMiniLabel = new GUIStyle(EditorStyles.centeredGreyMiniLabel)
|
||||
{
|
||||
alignment = TextAnchor.UpperCenter
|
||||
};
|
||||
|
||||
wheelThumbSize = new Vector2(
|
||||
!Mathf.Approximately(wheelThumb.fixedWidth, 0f) ? wheelThumb.fixedWidth : wheelThumb.padding.horizontal,
|
||||
!Mathf.Approximately(wheelThumb.fixedHeight, 0f) ? wheelThumb.fixedHeight : wheelThumb.padding.vertical
|
||||
);
|
||||
|
||||
header = new GUIStyle("ShurikenModuleTitle")
|
||||
{
|
||||
font = (new GUIStyle("Label")).font,
|
||||
border = new RectOffset(15, 7, 4, 4),
|
||||
fixedHeight = 22,
|
||||
contentOffset = new Vector2(20f, -2f)
|
||||
};
|
||||
|
||||
headerCheckbox = new GUIStyle("ShurikenCheckMark");
|
||||
headerFoldout = new GUIStyle("Foldout");
|
||||
|
||||
playIcon = (Texture2D)EditorGUIUtility.LoadRequired("Builtin Skins/DarkSkin/Images/IN foldout act.png");
|
||||
checkerIcon = (Texture2D)EditorGUIUtility.LoadRequired("Icons/CheckerFloor.png");
|
||||
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
paneOptionsIcon = (Texture2D)EditorGUIUtility.LoadRequired("Builtin Skins/DarkSkin/Images/pane options.png");
|
||||
else
|
||||
paneOptionsIcon = (Texture2D)EditorGUIUtility.LoadRequired("Builtin Skins/LightSkin/Images/pane options.png");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8f31cf52f05e80c4ea48570d0c3c8f59
|
||||
timeCreated: 1461744717
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,124 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace UnityEditor.PostProcessing
|
||||
{
|
||||
public static class ReflectionUtils
|
||||
{
|
||||
static Dictionary<KeyValuePair<object, string>, FieldInfo> s_FieldInfoFromPaths = new Dictionary<KeyValuePair<object, string>, FieldInfo>();
|
||||
|
||||
public static FieldInfo GetFieldInfoFromPath(object source, string path)
|
||||
{
|
||||
FieldInfo field = null;
|
||||
var kvp = new KeyValuePair<object, string>(source, path);
|
||||
|
||||
if (!s_FieldInfoFromPaths.TryGetValue(kvp, out field))
|
||||
{
|
||||
var splittedPath = path.Split('.');
|
||||
var type = source.GetType();
|
||||
|
||||
foreach (var t in splittedPath)
|
||||
{
|
||||
field = type.GetField(t, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (field == null)
|
||||
break;
|
||||
|
||||
type = field.FieldType;
|
||||
}
|
||||
|
||||
s_FieldInfoFromPaths.Add(kvp, field);
|
||||
}
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
public static string GetFieldPath<T, TValue>(Expression<Func<T, TValue>> expr)
|
||||
{
|
||||
MemberExpression me;
|
||||
switch (expr.Body.NodeType)
|
||||
{
|
||||
case ExpressionType.Convert:
|
||||
case ExpressionType.ConvertChecked:
|
||||
var ue = expr.Body as UnaryExpression;
|
||||
me = (ue != null ? ue.Operand : null) as MemberExpression;
|
||||
break;
|
||||
default:
|
||||
me = expr.Body as MemberExpression;
|
||||
break;
|
||||
}
|
||||
|
||||
var members = new List<string>();
|
||||
while (me != null)
|
||||
{
|
||||
members.Add(me.Member.Name);
|
||||
me = me.Expression as MemberExpression;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
for (int i = members.Count - 1; i >= 0; i--)
|
||||
{
|
||||
sb.Append(members[i]);
|
||||
if (i > 0) sb.Append('.');
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static object GetFieldValue(object source, string name)
|
||||
{
|
||||
var type = source.GetType();
|
||||
|
||||
while (type != null)
|
||||
{
|
||||
var f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
if (f != null)
|
||||
return f.GetValue(source);
|
||||
|
||||
type = type.BaseType;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static object GetFieldValueFromPath(object source, ref Type baseType, string path)
|
||||
{
|
||||
var splittedPath = path.Split('.');
|
||||
object srcObject = source;
|
||||
|
||||
foreach (var t in splittedPath)
|
||||
{
|
||||
var fieldInfo = baseType.GetField(t, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
if (fieldInfo == null)
|
||||
{
|
||||
baseType = null;
|
||||
break;
|
||||
}
|
||||
|
||||
baseType = fieldInfo.FieldType;
|
||||
srcObject = GetFieldValue(srcObject, t);
|
||||
}
|
||||
|
||||
return baseType == null
|
||||
? null
|
||||
: srcObject;
|
||||
}
|
||||
|
||||
public static object GetParentObject(string path, object obj)
|
||||
{
|
||||
var fields = path.Split('.');
|
||||
|
||||
if (fields.Length == 1)
|
||||
return obj;
|
||||
|
||||
var info = obj.GetType().GetField(fields[0], BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
obj = info.GetValue(obj);
|
||||
|
||||
return GetParentObject(string.Join(".", fields, 1, fields.Length - 1), obj);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 71f7e805a7fc35046afbcf5c2639d116
|
||||
timeCreated: 1466604313
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue