Skip to content

Commit

Permalink
feat(composition): Implement DistantSpecularEffect and SpotDiffuseEff…
Browse files Browse the repository at this point in the history
…ect + Samples
  • Loading branch information
ahmed605 committed Mar 2, 2024
1 parent 6a153b5 commit be859be
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,7 @@
<Grid x:Name="tempTintGrid" Width="200" Height="200" VerticalAlignment="Top" HorizontalAlignment="Left" ToolTipService.ToolTip="TemperatureAndTintEffect"/>
<Grid x:Name="matrixGrid" Width="200" Height="200" VerticalAlignment="Top" HorizontalAlignment="Left" ToolTipService.ToolTip="ColorMatrixEffect"/>
<Grid x:Name="ddGrid" Width="200" Height="200" VerticalAlignment="Top" HorizontalAlignment="Left" ToolTipService.ToolTip="DistantDiffuseEffect"/>
<Grid x:Name="dsGrid" Width="200" Height="200" VerticalAlignment="Top" HorizontalAlignment="Left" ToolTipService.ToolTip="DistantSpecularEffect"/>
<Grid x:Name="sdGrid" Width="200" Height="200" VerticalAlignment="Top" HorizontalAlignment="Left" ToolTipService.ToolTip="SpotDiffuseEffect"/>
</GridView>
</UserControl>
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,22 @@ private void EffectBrushTests_Loaded(object sender, RoutedEventArgs e)
effectBrush22.SetSourceParameter("sourceBrush", brush);
ddGrid.Background = new XamlCompositionBrush(effectBrush22);
var effect23 = new SimpleDistantSpecularEffect() { Source = new SimpleLuminanceToAlphaEffect() { Source = new CompositionEffectSourceParameter("sourceBrush") }, Azimuth = (float)MathEx.ToRadians(180.0f) };
var factory23 = compositor.CreateEffectFactory(effect23);
var effectBrush23 = factory23.CreateBrush();
effectBrush23.SetSourceParameter("sourceBrush", brush);
dsGrid.Background = new XamlCompositionBrush(effectBrush23);
var effect24 = new SimpleSpotDiffuseEffect() { Source = new SimpleLuminanceToAlphaEffect() { Source = new CompositionEffectSourceParameter("sourceBrush") }, DiffuseAmount = 5.0f, LimitingConeAngle = 0.25f, LightTarget = new Vector3(surface3.DecodedSize.ToVector2(), 0) / 2 };
var factory24 = compositor.CreateEffectFactory(effect24);
var effectBrush24 = factory24.CreateBrush();
effectBrush24.SetSourceParameter("sourceBrush", brush);
sdGrid.Background = new XamlCompositionBrush(effectBrush24);
}
};
#endif
Expand Down Expand Up @@ -1692,7 +1708,7 @@ public void GetNamedPropertyMapping(string name, out uint index, out GraphicsEff
case "LightColor":
{
index = 3;
mapping = GraphicsEffectPropertyMapping.Direct;
mapping = GraphicsEffectPropertyMapping.ColorToVector3;
break;
}
default:
Expand Down Expand Up @@ -1725,6 +1741,202 @@ public object GetProperty(uint index)
public IGraphicsEffectSource GetSource(uint index) => Source;
public uint GetSourceCount() => 1;
}

[Guid("428C1EE5-77B8-4450-8AB5-72219C21ABDA")]
private class SimpleDistantSpecularEffect : IGraphicsEffect, IGraphicsEffectSource, IGraphicsEffectD2D1Interop
{
private string _name = "SimpleDistantSpecularEffect";
private Guid _id = new Guid("428C1EE5-77B8-4450-8AB5-72219C21ABDA");

public string Name
{
get => _name;
set => _name = value;
}

public float Azimuth { get; set; } = 0.0f;

public float Elevation { get; set; } = 0.0f;

public float SpecularExponent { get; set; } = 1.0f;

public float SpecularAmount { get; set; } = 1.0f;

public Color LightColor { get; set; } = Colors.White;

public IGraphicsEffectSource Source { get; set; }

public Guid GetEffectId() => _id;

public void GetNamedPropertyMapping(string name, out uint index, out GraphicsEffectPropertyMapping mapping)
{
switch (name)
{
case "Azimuth":
{
index = 0;
mapping = GraphicsEffectPropertyMapping.RadiansToDegrees;
break;
}
case "Elevation":
{
index = 1;
mapping = GraphicsEffectPropertyMapping.RadiansToDegrees;
break;
}
case "SpecularExponent":
{
index = 2;
mapping = GraphicsEffectPropertyMapping.Direct;
break;
}
case "SpecularAmount":
{
index = 3;
mapping = GraphicsEffectPropertyMapping.Direct;
break;
}
case "LightColor":
{
index = 4;
mapping = GraphicsEffectPropertyMapping.ColorToVector3;
break;
}
default:
{
index = 0xFF;
mapping = (GraphicsEffectPropertyMapping)0xFF;
break;
}
}
}

public object GetProperty(uint index)
{
switch (index)
{
case 0:
return Azimuth;
case 1:
return Elevation;
case 2:
return SpecularExponent;
case 3:
return SpecularAmount;
case 4:
return LightColor;
default:
return null;
}
}

public uint GetPropertyCount() => 5;
public IGraphicsEffectSource GetSource(uint index) => Source;
public uint GetSourceCount() => 1;
}

[Guid("818A1105-7932-44F4-AA86-08AE7B2F2C93")]
private class SimpleSpotDiffuseEffect : IGraphicsEffect, IGraphicsEffectSource, IGraphicsEffectD2D1Interop
{
private string _name = "SimpleSpotDiffuseEffect";
private Guid _id = new Guid("818A1105-7932-44F4-AA86-08AE7B2F2C93");

public string Name
{
get => _name;
set => _name = value;
}

public Vector3 LightPosition { get; set; } = new();

public Vector3 LightTarget { get; set; } = new();

public float Focus { get; set; } = 1.0f;

public float LimitingConeAngle { get; set; } = MathF.PI / 2.0f;

public float DiffuseAmount { get; set; } = 1.0f;

public Color LightColor { get; set; } = Colors.White;

public IGraphicsEffectSource Source { get; set; }

public Guid GetEffectId() => _id;

public void GetNamedPropertyMapping(string name, out uint index, out GraphicsEffectPropertyMapping mapping)
{
switch (name)
{
case "LightPosition":
{
index = 0;
mapping = GraphicsEffectPropertyMapping.Direct;
break;
}
case "LightTarget":
{
index = 1;
mapping = GraphicsEffectPropertyMapping.Direct;
break;
}
case "Focus":
{
index = 2;
mapping = GraphicsEffectPropertyMapping.Direct;
break;
}
case "LimitingConeAngle":
{
index = 3;
mapping = GraphicsEffectPropertyMapping.RadiansToDegrees;
break;
}
case "DiffuseAmount":
{
index = 4;
mapping = GraphicsEffectPropertyMapping.Direct;
break;
}
case "LightColor":
{
index = 5;
mapping = GraphicsEffectPropertyMapping.ColorToVector3;
break;
}
default:
{
index = 0xFF;
mapping = (GraphicsEffectPropertyMapping)0xFF;
break;
}
}
}

public object GetProperty(uint index)
{
switch (index)
{
case 0:
return LightPosition;
case 1:
return LightTarget;
case 2:
return Focus;
case 3:
return LimitingConeAngle;
case 4:
return DiffuseAmount;
case 5:
return LightColor;
default:
return null;
}
}

public uint GetPropertyCount() => 6;
public IGraphicsEffectSource GetSource(uint index) => Source;
public uint GetSourceCount() => 1;
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,7 @@ half4 main()
}
case EffectType.DistantDiffuseEffect:
{
if (effectInterop.GetSourceCount() == 1 && effectInterop.GetPropertyCount() == 4 && effectInterop.GetSource(0) is IGraphicsEffectSource source)
if (effectInterop.GetSourceCount() == 1 && effectInterop.GetPropertyCount() >= 4 && effectInterop.GetSource(0) is IGraphicsEffectSource source)
{
SKImageFilter sourceFilter = GenerateEffectFilter(source, bounds);
if (sourceFilter is null)
Expand All @@ -1176,6 +1176,72 @@ half4 main()
return SKImageFilter.CreateDistantLitDiffuse(new SKPoint3(lightVector.X, lightVector.Y, lightVector.Z), color.ToSKColor(), 1.0f, amount, sourceFilter, new(bounds));
}

return null;
}
case EffectType.DistantSpecularEffect:
{
if (effectInterop.GetSourceCount() == 1 && effectInterop.GetPropertyCount() >= 5 && effectInterop.GetSource(0) is IGraphicsEffectSource source)
{
SKImageFilter sourceFilter = GenerateEffectFilter(source, bounds);
if (sourceFilter is null)
return null;

effectInterop.GetNamedPropertyMapping("Azimuth", out uint azimuthProp, out GraphicsEffectPropertyMapping azimuthMapping);
effectInterop.GetNamedPropertyMapping("Elevation", out uint elevationProp, out GraphicsEffectPropertyMapping elevationMapping);
effectInterop.GetNamedPropertyMapping("SpecularExponent", out uint exponentProp, out _);
effectInterop.GetNamedPropertyMapping("SpecularAmount", out uint amountProp, out _);
effectInterop.GetNamedPropertyMapping("LightColor", out uint colorProp, out _);

float azimuth = (float)effectInterop.GetProperty(azimuthProp);
float elevation = (float)effectInterop.GetProperty(elevationProp);
float exponent = (float)effectInterop.GetProperty(exponentProp);
float amount = (float)effectInterop.GetProperty(amountProp);
Color color = (Color)effectInterop.GetProperty(colorProp);

if (azimuthMapping == GraphicsEffectPropertyMapping.RadiansToDegrees)
azimuth *= 180.0f / MathF.PI;

if (elevationMapping == GraphicsEffectPropertyMapping.RadiansToDegrees)
elevation *= 180.0f / MathF.PI;

Vector3 lightVector = EffectHelpers.GetLightVector(azimuth, elevation);

return SKImageFilter.CreateBlendMode(SKBlendMode.SrcOver, SKImageFilter.CreatePaint(new() { Color = SKColors.Black }), SKImageFilter.CreateDistantLitSpecular(new SKPoint3(lightVector.X, lightVector.Y, lightVector.Z), color.ToSKColor(), 1.0f, amount, exponent, sourceFilter), new(bounds));
}

return null;
}
case EffectType.SpotDiffuseEffect:
{
if (effectInterop.GetSourceCount() == 1 && effectInterop.GetPropertyCount() >= 6 && effectInterop.GetSource(0) is IGraphicsEffectSource source)
{
SKImageFilter sourceFilter = GenerateEffectFilter(source, bounds);
if (sourceFilter is null)
return null;

effectInterop.GetNamedPropertyMapping("LightPosition", out uint positionProp, out _);
effectInterop.GetNamedPropertyMapping("LightTarget", out uint targetProp, out _);
effectInterop.GetNamedPropertyMapping("Focus", out uint focusProp, out _);
effectInterop.GetNamedPropertyMapping("LimitingConeAngle", out uint angleProp, out GraphicsEffectPropertyMapping angleMapping);
effectInterop.GetNamedPropertyMapping("DiffuseAmount", out uint amountProp, out _);
effectInterop.GetNamedPropertyMapping("LightColor", out uint colorProp, out _);

Vector3 position = (Vector3)effectInterop.GetProperty(positionProp);
Vector3 target = (Vector3)effectInterop.GetProperty(targetProp);
float focus = (float)effectInterop.GetProperty(focusProp);
float angle = (float)effectInterop.GetProperty(angleProp);
float amount = (float)effectInterop.GetProperty(amountProp);
Color color = (Color)effectInterop.GetProperty(colorProp);

if (angleMapping == GraphicsEffectPropertyMapping.RadiansToDegrees)
angle *= 180.0f / MathF.PI;

Vector3 lightTarget = EffectHelpers.CalcLightTargetVector(position, target);
//Vector2 coneAngle = EffectHelpers.CalcConeAngle(angle);

return SKImageFilter.CreateSpotLitDiffuse(new SKPoint3(position.X, position.Y, position.Z), new SKPoint3(lightTarget.X, lightTarget.Y, lightTarget.Z), focus, angle, color.ToSKColor(), 1.0f, amount, sourceFilter, new(bounds));
}

return null;
}
case EffectType.Unsupported:
Expand Down
26 changes: 26 additions & 0 deletions src/Uno.UWP/Graphics/Effects/Interop/EffectHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,32 @@ internal static Vector3 GetLightVector(float azimuthInDegrees, float elevationIn
return lightVector;
}

internal static Vector3 CalcLightTargetVector(Vector3 lightPosition, Vector3 lightTarget)
{
Vector3 targetVector = new();

targetVector.X = lightTarget.X - lightPosition.X;
targetVector.Y = lightTarget.Y - lightPosition.Y;
targetVector.Z = lightTarget.Z - lightPosition.Z;

Normalize3DVector(ref targetVector);
return targetVector;
}

/*internal static Vector2 CalcConeAngle(float limitingConeAngle)
{
float limitingConeAngleInRadians = MathF.Abs(limitingConeAngle) * 0.0174532925199433f;
Vector2 coneAngle = new();
coneAngle.X = MathF.Cos(limitingConeAngleInRadians);
if (limitingConeAngle >= 5.0f)
coneAngle.Y = MathF.Cos(limitingConeAngleInRadians + 0.0174532925199433f);
else
coneAngle.Y = MathF.Cos(limitingConeAngleInRadians * 1.2f);
return coneAngle;
}*/

private static void Normalize3DVector(ref Vector3 vector)
{
float fa = 0.0f;
Expand Down

0 comments on commit be859be

Please sign in to comment.