using System.Collections.Generic; using System.Linq; using System.Windows.Media.Media3D; using System.Windows.Media; namespace HelixToolkit { // TODO: under construction... public static class OpacitySortingHelper { // http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Components-PostAttachments/00-04-01-86-12/SceneSortingHelper_2E00_cs /// /// Sort Modelgroups in Farthest to Closest order, to enable transparency /// Should be applied whenever the scene is significantly re-oriented /// public static void AlphaSort(Point3D cameraPosition, Model3DCollection models, Transform3D worldTransform) { var sortedList = models.OrderBy(model => Point3D.Subtract(cameraPosition, worldTransform.Transform(model.Bounds.Location)).Length); models.Clear(); foreach (var model in sortedList) { models.Add(model); } } /// /// Sort scene - first opaque objects, then transparent objects sorted by distance from camera /// /// public static void SortModel(Point3D position, IList model) { var opaqueObjects = new List(); var transparentObjects = new List(); foreach (Visual3D v in model) { if (IsTransparent(v)) transparentObjects.Add(v); else opaqueObjects.Add(v); } model.Clear(); // Sort transparent objects by distance var sortedTransparentObjects = transparentObjects.OrderBy(visual => GetDistanceSquared(position, visual)); foreach (Visual3D v in opaqueObjects) model.Add(v); foreach (Visual3D v in sortedTransparentObjects) model.Add(v); } public static double GetDistanceSquared(Point3D position, Visual3D visual) { var bounds = Visual3DHelper.FindBounds(visual, Transform3D.Identity); return Point3D.Subtract(bounds.Location, position).LengthSquared; } public static double GetDistanceSquared(Point3D position, GeometryModel3D model) { return Point3D.Subtract(model.Bounds.Location, position).LengthSquared; } /// /// Determines whether the specified visual is transparent. /// /// The v. /// /// true if the specified visual is transparent; otherwise, false. /// public static bool IsTransparent(Visual3D v) { var mv3D = v as ModelVisual3D; if (mv3D != null) { // check if Model3D is transparent if (IsTransparent(mv3D.Content)) return true; // check if any child Visual3D are transparent return mv3D.Children.Any(IsTransparent); } return false; } /// /// Determines whether the specified model is transparent. /// /// The model. /// /// true if the specified model is transparent; otherwise, false. /// public static bool IsTransparent(Model3D model) { var gm3D = model as GeometryModel3D; if (gm3D != null) { if (IsTransparent(gm3D)) return true; } var mg = model as Model3DGroup; if (mg != null) { return mg.Children.Any(IsTransparent); } return false; } /// /// Determines whether the specified model is transparent. /// /// The GM3 D. /// /// true if the specified GM3 D is transparent; otherwise, false. /// public static bool IsTransparent(GeometryModel3D gm3D) { if (IsTransparent(gm3D.Material)) return true; if (IsTransparent(gm3D.BackMaterial)) return true; return false; } /// /// Determines whether any part of the specified material is transparent. /// /// The material. /// /// true if the specified material is transparent; otherwise, false. /// public static bool IsTransparent(Material material) { var g = material as MaterialGroup; if (g != null) { if (g.Children.Any(IsTransparent)) { return true; } } var dm = material as DiffuseMaterial; if (dm != null) { if (IsTransparent(dm.Brush)) return true; if (dm.Color.A < 255) return true; } return false; } /// /// Determines whether the specified brush is transparent. /// /// The brush. /// /// true if the specified brush is transparent; otherwise, false. /// public static bool IsTransparent(Brush brush) { if (brush.Opacity < 1) return true; var scb = brush as SolidColorBrush; if (scb != null) return scb.Color.A < 255; var gb = brush as GradientBrush; if (gb != null) { return gb.GradientStops.Any(gs => gs.Color.A < 255); } // todo: tilebrush and bitmapcachebrush return false; } } }