diff --git a/ColourMeOKGame/.idea/.idea.ColourMeOKGame/.idea/inspectionProfiles/Project_Default.xml b/ColourMeOKGame/.idea/.idea.ColourMeOKGame/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..ebdfbd6
--- /dev/null
+++ b/ColourMeOKGame/.idea/.idea.ColourMeOKGame/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ColourMeOKGame/Assets/Scenes/GameScene.unity b/ColourMeOKGame/Assets/Scenes/GameScene.unity
index c80fb31..87fe1f5 100644
--- a/ColourMeOKGame/Assets/Scenes/GameScene.unity
+++ b/ColourMeOKGame/Assets/Scenes/GameScene.unity
@@ -143,7 +143,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
- m_IsActive: 0
+ m_IsActive: 1
--- !u!114 &133964671
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -258,7 +258,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
- m_IsActive: 0
+ m_IsActive: 1
--- !u!4 &447905427
Transform:
m_ObjectHideFlags: 0
@@ -476,7 +476,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
- m_IsActive: 0
+ m_IsActive: 1
--- !u!114 &1204483825
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -505,37 +505,6 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
---- !u!1 &1680304394
-GameObject:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- serializedVersion: 6
- m_Component:
- - component: {fileID: 1680304395}
- m_Layer: 0
- m_Name: GameObject
- m_TagString: Untagged
- m_Icon: {fileID: 0}
- m_NavMeshLayer: 0
- m_StaticEditorFlags: 0
- m_IsActive: 1
---- !u!4 &1680304395
-Transform:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 1680304394}
- serializedVersion: 2
- m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: 0, y: 0, z: 0}
- m_LocalScale: {x: 1, y: 1, z: 1}
- m_ConstrainProportionsScale: 0
- m_Children: []
- m_Father: {fileID: 0}
- m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
@@ -545,4 +514,3 @@ SceneRoots:
- {fileID: 133964672}
- {fileID: 447905427}
- {fileID: 1204483826}
- - {fileID: 1680304395}
diff --git a/ColourMeOKGame/Assets/Scripts/Backend.cs b/ColourMeOKGame/Assets/Scripts/Backend.cs
index 3daf4e4..b9a558f 100644
--- a/ColourMeOKGame/Assets/Scripts/Backend.cs
+++ b/ColourMeOKGame/Assets/Scripts/Backend.cs
@@ -546,7 +546,7 @@ public void GetRecentScores(Action
+ /// calculate a similarity percentage from a colour distance
+ ///
+ ///
+ /// the DeltaLabChE object returned by CalculateDistance,
+ ///
+ ///
+ /// the maximum chroma value to use for the similarity percentage calculation,
+ /// defaults to 1.0f
+ ///
+ ///
+ /// the maximum hue value to use for the similarity percentage calculation,
+ /// defaults to 1.0f
+ ///
+ ///
+ /// the maximum lightness value to use for the similarity percentage calculation,
+ /// defaults to 1.0f
+ ///
+ /// a LCh struct with 0-1f values
+ public static LCh CalculateLChSimilarityPercentage(
+ DeltaLabChE delta,
+ double chromaMax = 1.0d,
+ double hueMax = 1.0d,
+ double lightnessMax = 1.0d)
+ {
+ // dL = [-1, 1] lightness difference (negative = template is darker)
+ // dC = [-inf, +inf] chroma difference (negative = template is more chromatic)
+ // dH = [0, +inf] hue difference (zero for grayscale or similar hues)
+ // dE = [0, 1] overall perceptual difference in the oklab colour space
+ // (but since we're using sRGB, we just use 1.0f as the max bounds)
+ return new LCh((float)Math.Clamp(1 - Math.Abs(delta.dL) / lightnessMax, 0, 1),
+ (float)Math.Clamp(1 - Math.Abs(delta.dC) / chromaMax, 0, 1),
+ (float)Math.Clamp(1 - delta.dh / hueMax, 0, 1));
+ }
+
///
/// calculate a 0-100% distance/accuracy between two unity rgba colour objects
///
/// the template colour to compare against
/// the response colour to compare
- /// a DeltaLabCHE struct
- public static DeltaLabCHE CalculateDistance(Color template, Color response)
+ /// a DeltaLabChE struct
+ public static DeltaLabChE CalculateDistance(Color template, Color response)
{
// rgb to oklab
var templateOklab = linear_srgb_to_oklab(new RGB(
@@ -48,7 +83,7 @@ public static DeltaLabCHE CalculateDistance(Color template, Color response)
var deltaH = Math.Max(0d, Math.Sqrt(deltaA * deltaA + deltaB * deltaB - deltaC * deltaC));
var deltaE = Math.Sqrt(deltaL * deltaL + deltaC * deltaC + deltaH * deltaH);
- return new DeltaLabCHE(deltaL, deltaA, deltaB, deltaC, deltaH, deltaE);
+ return new DeltaLabChE(deltaL, deltaA, deltaB, deltaC, deltaH, deltaE);
}
///
@@ -136,7 +171,6 @@ public static RGB gamut_clip_preserve_chroma(RGB rgb)
/// a and b must be normalized so a^2 + b^2 == 1
///
// https://bottosson.github.io/posts/gamutclipping/ (MIT)
- // ReSharper disable once MemberCanBePrivate.Global
public static float find_gamut_intersection(
float a,
float b,
@@ -380,27 +414,27 @@ public static float compute_max_saturation(float a, float b)
}
// ReSharper disable once InconsistentNaming
- public struct DeltaLabCHE
+ public struct DeltaLabChE
{
// ReSharper disable once InconsistentNaming
- public double dL;
+ public readonly double dL;
// ReSharper disable once InconsistentNaming
- public double da;
+ public readonly double da;
// ReSharper disable once InconsistentNaming
- public double db;
+ public readonly double db;
// ReSharper disable once InconsistentNaming
- public double dC;
+ public readonly double dC;
// ReSharper disable once InconsistentNaming
- public double dH;
+ public readonly double dh;
// ReSharper disable once InconsistentNaming
- public double dE;
+ public readonly double dE;
- public DeltaLabCHE(
+ public DeltaLabChE(
// ReSharper disable once InconsistentNaming
double L,
double a,
@@ -416,7 +450,7 @@ public struct DeltaLabCHE
da = a;
db = b;
dC = C;
- dH = H;
+ dh = H;
dE = E;
}
}
@@ -440,6 +474,27 @@ public Lab(float L, float a, float b)
}
}
+ public readonly struct LCh
+ {
+ public readonly float L;
+ public readonly float C;
+
+ // ReSharper disable once InconsistentNaming
+ public readonly float h;
+
+ public LCh(
+ // ReSharper disable once InconsistentNaming
+ float L,
+ // ReSharper disable once InconsistentNaming
+ float C,
+ float h)
+ {
+ this.L = L;
+ this.C = C;
+ this.h = h;
+ }
+ }
+
public readonly struct RGB
{
// ReSharper disable once InconsistentNaming
diff --git a/ColourMeOKGame/Assets/Scripts/GameManager.cs b/ColourMeOKGame/Assets/Scripts/GameManager.cs
index 5c8f6d0..74cf866 100644
--- a/ColourMeOKGame/Assets/Scripts/GameManager.cs
+++ b/ColourMeOKGame/Assets/Scripts/GameManager.cs
@@ -202,24 +202,48 @@ public void SignalGameEnd(List playedRounds)
var roundChromaAcc = 0d;
var roundHueAcc = 0d;
var roundPerceivedAcc = 0d;
-
- var maxDistance = Colorimetry.CalculateDistance(Color.black, Color.white);
-
- foreach (var distance in playedRounds.Select(round =>
- Colorimetry.CalculateDistance(round.TemplateColour, round.ResponseColour)))
+
+ var templateColour = Color.clear;
+ var responseColour = Color.clear;
+ var roundNumber = 1;
+ foreach (var distance in playedRounds.Take(Gameplay.RoundsPerGame).Select(round =>
+ Colorimetry.CalculateDistance(templateColour = round.TemplateColour,
+ responseColour = round.ResponseColour)))
{
- roundLightnessAcc += distance.dL / maxDistance.dL;
- roundChromaAcc += distance.dC / maxDistance.dC;
- roundHueAcc += distance.dH / maxDistance.dH;
- roundPerceivedAcc += distance.dE / maxDistance.dE;
+ var dLCh = Colorimetry.CalculateLChSimilarityPercentage(distance);
+
+ Debug.Log(
+ $"processing round: template={templateColour}, response={responseColour} (dL%={dLCh.L}, dC%={dLCh.C}, dh%={dLCh.h}, dEok={distance.dE:F})");
+
+ roundLightnessAcc += Math.Clamp(dLCh.L * 100d, 0d, 100d);
+ roundChromaAcc += Math.Clamp(dLCh.C * 100d, 0d, 100d);
+ roundHueAcc += Math.Clamp(dLCh.h * 100d, 0d, 100d);
+ roundPerceivedAcc += Math.Clamp((100d - distance.dE) * 100d, 0d, 100d);
+
+ var showcaseTemplate = ui.UI.Q($"ShowcasePair{roundNumber}TemplateColour");
+ var showcaseResponse = ui.UI.Q($"ShowcasePair{roundNumber}ResponseColour");
+ var showcaseInfo = ui.UI.Q