public void AddBlock(List <Vector3> Positions, List <Color> Colours, Bounds BoundingBox, bool Normalise) { // convert into colour data to put into the texture var PositionsAsColour = new List <Color>(); Color PosColour; foreach (var Position in Positions) { var NormPosition = new Vector3(); if (Normalise) { NormPosition.x = PopMath.Range(BoundingBox.min.x, BoundingBox.max.x, Position.x); NormPosition.y = PopMath.Range(BoundingBox.min.y, BoundingBox.max.y, Position.y); NormPosition.z = PopMath.Range(BoundingBox.min.z, BoundingBox.max.z, Position.z); } else { NormPosition = Position; } PosColour.r = NormPosition.x; PosColour.g = NormPosition.y; PosColour.b = NormPosition.z; PosColour.a = 1; PositionsAsColour.Add(PosColour); } AddBlock(BoundingBox, PositionsAsColour, Colours); }
// returns 0-1 for each component inside a min/mac public static Vector2 Range(this Vector2 Value, Vector2 Min, Vector2 Max) { var x = PopMath.Range(Min.x, Max.x, Value.x); var y = PopMath.Range(Min.y, Max.y, Value.y); return(new Vector2(x, y)); }
// negative - inside sphere, positive, distance from sphere. public float Distance(Ray ray, out Vector3 NearestPoint) { NearestPoint = PopMath.NearestToRay3(this.center, ray); var dist = Vector3.Distance(NearestPoint, this.center); dist -= this.radius; return(dist); }
// returns 0-1 for each component inside a min/mac public static Vector3 Range(this Vector3 Value, Vector3 Min, Vector3 Max) { var x = PopMath.Range(Min.x, Max.x, Value.x); var y = PopMath.Range(Min.y, Max.y, Value.y); var z = PopMath.Range(Min.z, Max.z, Value.z); return(new Vector3(x, y, z)); }
float GetLocalHeight(float WorldHeight, float HeightScalar) { var HalfHeight = GetHeightRange(HeightScalar) / 2.0f; var Mid = GetMidHeight(); var Top = Mid - HalfHeight; var Bottom = Mid + HalfHeight; return(PopMath.Range(Bottom, Top, WorldHeight)); }
// returns 0-1 for each component inside a min/mac public static Vector4 Range(this Vector4 Value, Vector4 Min, Vector4 Max) { var x = PopMath.Range(Min.x, Max.x, Value.x); var y = PopMath.Range(Min.y, Max.y, Value.y); var z = PopMath.Range(Min.z, Max.z, Value.z); var w = PopMath.Range(Min.w, Max.w, Value.w); return(new Vector4(x, y, z, w)); }
public void DrawWholeView(Rect Canvas, TimeUnit LeftTime, TimeUnit RightTime, DataBridge Data) { TimeUnit MinTime, MaxTime; Data.GetTimeRange(out MinTime, out MaxTime); var LeftNorm = GetTimeNormalised(MinTime, MaxTime, LeftTime); var RightNorm = GetTimeNormalised(MinTime, MaxTime, RightTime); var RectNorm = new Rect(LeftNorm, 0, RightNorm - LeftNorm, 1); var VisibleRect = PopMath.RectMult(RectNorm, Canvas); //EditorGUI.DrawRect (Canvas, CanvasBackgroundColour); EditorGUI.DrawRect(VisibleRect, Color.red); }
// triangle packing! public static List <Triangle2> AllocateTriangleAtlases(List <Triangle3> MeshTriangles) { var TriangleCount = MeshTriangles.Count; var AtlasWidth = (int)Mathf.Ceil(Mathf.Sqrt((float)TriangleCount)); var AtlasHeight = AtlasWidth; var AtlasTriangles = new List <Triangle2>(); for (int ti = 0; ti < MeshTriangles.Count; ti++) { var MeshTriangle = MeshTriangles[ti]; // get atlas quad var AtlasX = ti % AtlasWidth; var AtlasY = ti / AtlasWidth; var AtlasMinu = PopMath.Range(0, AtlasWidth, AtlasX); var AtlasMaxu = PopMath.Range(0, AtlasWidth, AtlasX + 1); var AtlasMinv = PopMath.Range(0, AtlasHeight, AtlasY); var AtlasMaxv = PopMath.Range(0, AtlasHeight, AtlasY + 1); // todo: get triangle position on it's plane (ie, it's ortho) var AtlasTriangle = new Triangle2(); AtlasTriangle.a = MeshTriangle.a.xz(); AtlasTriangle.b = MeshTriangle.b.xz(); AtlasTriangle.c = MeshTriangle.c.xz(); // fit triangle to quad var AtlasTriangleBounds = new Bounds2(); AtlasTriangleBounds.Min = PopMath.Min(AtlasTriangle.a, AtlasTriangle.b, AtlasTriangle.c); AtlasTriangleBounds.Max = PopMath.Max(AtlasTriangle.a, AtlasTriangle.b, AtlasTriangle.c); AtlasTriangle.a = PopMath.Range(AtlasTriangleBounds.Min, AtlasTriangleBounds.Max, AtlasTriangle.a); AtlasTriangle.b = PopMath.Range(AtlasTriangleBounds.Min, AtlasTriangleBounds.Max, AtlasTriangle.b); AtlasTriangle.c = PopMath.Range(AtlasTriangleBounds.Min, AtlasTriangleBounds.Max, AtlasTriangle.c); // now put it in it's atlas pos AtlasTriangle.a.x = Mathf.Lerp(AtlasMinu, AtlasMaxu, AtlasTriangle.a.x); AtlasTriangle.a.y = Mathf.Lerp(AtlasMinv, AtlasMaxv, AtlasTriangle.a.y); AtlasTriangle.b.x = Mathf.Lerp(AtlasMinu, AtlasMaxu, AtlasTriangle.b.x); AtlasTriangle.b.y = Mathf.Lerp(AtlasMinv, AtlasMaxv, AtlasTriangle.b.y); AtlasTriangle.c.x = Mathf.Lerp(AtlasMinu, AtlasMaxu, AtlasTriangle.c.x); AtlasTriangle.c.y = Mathf.Lerp(AtlasMinv, AtlasMaxv, AtlasTriangle.c.y); AtlasTriangles.Add(AtlasTriangle); } return(AtlasTriangles); }
TimeUnit?PositionToTime(Rect Canvas, Vector2 Position, out float NormalisedY) { var xf = PopMath.Range(Canvas.xMin, Canvas.xMax, Position.x); var yf = PopMath.Range(Canvas.yMin, Canvas.yMax, Position.y); NormalisedY = yf; if (xf < 0 || xf > 1 || yf < 0 || yf > 1) { //Debug.Log ("xf = " + xf + " yf = " + yf); return(null); } // convert to time var MinTime = ScrollTimeLeft.Time; var MaxTime = ScrollTimeRight.Time; var Timef = Mathf.Lerp(MinTime, MaxTime, xf); var TimeMs = (int)Timef; return(new TimeUnit(TimeMs)); }
TimeUnit?PositionToTime(Rect Canvas, Vector2 Position, List <DataStreamMeta> Streams, out int?StreamIndex) { var xf = PopMath.Range(Canvas.xMin, Canvas.xMax, Position.x); var yf = PopMath.Range(Canvas.yMin, Canvas.yMax, Position.y); if (xf < 0 || xf > 1 || yf < 0 || yf > 1) { //Debug.Log ("xf = " + xf + " yf = " + yf); StreamIndex = null; return(null); } // convert to time var MinTime = ScrollTimeLeft.Time; var MaxTime = ScrollTimeRight.Time; var Timef = Mathf.Lerp(MinTime, MaxTime, xf); var TimeMs = (int)Timef; // work out which stream this is StreamIndex = GetStreamIndexOnCanvas(yf); return(new TimeUnit(TimeMs)); }
public static Color NormalToRedGreen(float Normal, Color?OOBColour) { if (Normal < 0.0f && OOBColour.HasValue) { return(OOBColour.Value); } else if (Normal < 0.5f) { Normal = Mathf.Max(Normal, 0); Normal /= 0.5f; return(new Color(1, Normal, 0)); } else if (Normal > 1 && OOBColour.HasValue) { return(OOBColour.Value); } else // >= 0.5f { Normal = Mathf.Min(Normal, 1); float Yellow = PopMath.Range(1.0f, 0.5f, Normal); return(new Color(Yellow, 1, 0)); } }
public void Draw(Rect CanvasRect, TimeUnit LeftTime, TimeUnit RightTime, TimeUnit?SelectedTime, TimeUnit?HoverTime, DataBridge Data, List <DataStreamMeta> Streams, DragMeta DragMeta) { EditorGUI.DrawRect(CanvasRect, CanvasBackgroundColour); //DrawWholeView (Canvas, LeftTime, RightTime, Data); var StreamRects = new Rect[Streams.Count]; for (int s = 0; s < Streams.Count; s++) { var st0 = (s + 0) / (float)Streams.Count; var st1 = (s + 1) / (float)Streams.Count; var StreamBorder = 1; var Top = Mathf.Lerp(CanvasRect.min.y + StreamBorder, CanvasRect.max.y, st0); var Bot = Mathf.Lerp(CanvasRect.min.y + StreamBorder, CanvasRect.max.y, st1) - StreamBorder; var Left = CanvasRect.min.x + StreamBorder; var Right = CanvasRect.max.x - StreamBorder; var StreamRect = new Rect(Left, Top, Right - Left, Bot - Top); StreamRects [s] = StreamRect; } var DrawCap = MaxDataDraws; Rect?FirstSelectionRect = null; // draw streams for (int s = 0; s < Streams.Count; s++) { var StreamRect = StreamRects [s]; var Stream = Streams [s]; EditorGUI.DrawRect(StreamRect, StreamBackgroundColour); var StreamColour = Stream.Colour; // get all the data in the visible region var StreamDatas = Data.GetStreamData(Stream, LeftTime, RightTime); var StreamDataRect = new Rect(0, 0, 1, 1); var MinWidthPx = 1; System.Func <TimeUnit, TimeUnit, Color, DataState, Rect> DrawMarker = (DataTimeLeft, DataTimeRight, Colour, State) => { var LeftNorm = GetTimeNormalised(LeftTime, RightTime, DataTimeLeft); var RightNorm = GetTimeNormalised(LeftTime, RightTime, DataTimeRight); StreamDataRect.x = LeftNorm; StreamDataRect.width = RightNorm - LeftNorm; var DrawStreamDataRect = PopMath.RectMult(StreamDataRect, StreamRect); DrawStreamDataRect.width = Mathf.Max(MinWidthPx, DrawStreamDataRect.width); if (DrawStreamDataRect.width <= 2.0f) { DrawStreamDataRect.width = MinWidthPx; } // giant rects kill performance (CPU renderer??) DrawStreamDataRect = DrawStreamDataRect.ClipToParent(StreamRect); if (State == DataState.Loaded) { EditorGUI.DrawRect(DrawStreamDataRect, Colour); } else { var StripeHeight = 2; int i = 0; var yoffset = (DrawStreamDataRect.height % StripeHeight) - (StripeHeight / 2.0f); for (var y = 0; y < DrawStreamDataRect.height + StripeHeight; y += StripeHeight, i++) { if (i % 3 == 2) { continue; } var Rect = DrawStreamDataRect; Rect.y = y + yoffset + DrawStreamDataRect.yMin; Rect.height = StripeHeight; // clip if (Rect.yMin > DrawStreamDataRect.yMax) { continue; } Rect.yMin = Mathf.Max(Rect.yMin, DrawStreamDataRect.yMin); Rect.yMax = Mathf.Min(Rect.yMax, DrawStreamDataRect.yMax); EditorGUI.DrawRect(Rect, Colour); } } return(DrawStreamDataRect); }; System.Func <TimeUnit, TimeUnit, Color, DataState, Rect> DrawData = (DataTimeLeft, DataTimeRight, Colour, State) => { var DrawStreamDataRect = DrawMarker(DataTimeLeft, DataTimeRight, Colour, State); // put some notches in long data // gr: correct the notches for the clipping change // gr: also, on mega long data, this causes a giant loop. start & end at nearest (also fixes above) var DurationMs = DataTimeRight.Time - DataTimeLeft.Time; var MaxLoopDuration = 10000; var NotchStep = Stream.NotchStepMs.HasValue ? Stream.NotchStepMs.Value : DurationMs; for (int NotchMs = NotchStep; NotchMs < DurationMs && DurationMs < MaxLoopDuration; NotchMs += NotchStep) { var LeftNorm = GetTimeNormalised(LeftTime, RightTime, new TimeUnit(DataTimeLeft.Time + NotchMs)); //var RightNorm = LeftNorm; StreamDataRect.x = LeftNorm; StreamDataRect.width = 0; var NotchDrawStreamDataRect = PopMath.RectMult(StreamDataRect, StreamRect); NotchDrawStreamDataRect.width = MinWidthPx; NotchDrawStreamDataRect = NotchDrawStreamDataRect.ClipToParent(StreamRect); EditorGUI.DrawRect(NotchDrawStreamDataRect, BlockNotchColour); } // change cursor if this is draggable if (Stream.Draggable) { EditorGUIUtility.AddCursorRect(DrawStreamDataRect, MouseCursor.Pan); } return(DrawStreamDataRect); }; System.Func <TimeUnit, Color, Rect> DrawLine = (DataTimeLeft, Colour) => { var SelectedTimeDuration = 16; var DataTimeRight = new TimeUnit(DataTimeLeft.Time + SelectedTimeDuration); return(DrawMarker(DataTimeLeft, DataTimeRight, Colour, DataState.Loaded)); }; // draw hover underneath if (HoverTime.HasValue) { var SelectedTimeLeft = HoverTime.Value; DrawLine(SelectedTimeLeft, HoverColour); } foreach (var StreamData in StreamDatas) { if (DrawCap-- <= 0) { break; } DrawData(StreamData.GetStartTime(), StreamData.GetEndTime(), StreamColour, StreamData.GetStatus()); // draw again offset by drag if (DragMeta != null && DragMeta.Draggable && DragMeta.StreamIndex == s) { var DraggedStartTime = new TimeUnit(StreamData.GetStartTime().Time + DragMeta.DragAmount.Time); var DraggedEndTime = new TimeUnit(StreamData.GetEndTime().Time + DragMeta.DragAmount.Time); DrawData(DraggedStartTime, DraggedEndTime, DragColour, StreamData.GetStatus()); } } // draw selection over the top if (SelectedTime.HasValue) { var SelectedTimeLeft = SelectedTime.Value; var Rect = DrawLine(SelectedTimeLeft, SelectionColour); if (!FirstSelectionRect.HasValue) { FirstSelectionRect = Rect; } } // draw text over that var LabelStyle = new GUIStyle(); LabelStyle.alignment = TextAnchor.LowerLeft; LabelStyle.fontStyle = StreamLabelFontStyle; LabelStyle.normal.textColor = StreamLabelColour; EditorGUI.DropShadowLabel(StreamRect, Stream.Name, LabelStyle); } // draw time labels { var LabelStyle = new GUIStyle(); LabelStyle.alignment = TextAnchor.UpperLeft; LabelStyle.fontStyle = TimeLabelFontStyle; LabelStyle.normal.textColor = TimeLabelColour; EditorGUI.DropShadowLabel(CanvasRect, "|< " + LeftTime.GetLabel(false), LabelStyle); } { var LabelStyle = new GUIStyle(); LabelStyle.alignment = TextAnchor.UpperRight; LabelStyle.fontStyle = TimeLabelFontStyle; LabelStyle.normal.textColor = TimeLabelColour; EditorGUI.DropShadowLabel(CanvasRect, RightTime.GetLabel(false) + " >|", LabelStyle); } if (SelectedTime.HasValue && FirstSelectionRect.HasValue) { var LabelStyle = new GUIStyle(); LabelStyle.alignment = TextAnchor.UpperLeft; LabelStyle.fontStyle = SelectedTimeLabelFontStyle; LabelStyle.normal.textColor = SelectedTimeLabelColour; var Label = "\n<<" + SelectedTime.Value.GetLabel(true); EditorGUI.DropShadowLabel(FirstSelectionRect.Value, Label, LabelStyle); } if (DrawCap <= 0) { Debug.Log("Exceeded draw cap"); } }
public void CullBlocks(List <TTexturePointBlock> AllBlocks, bool AddCulledBlocks, List <TTexturePointBlockAndScore> FilteredBlocks) { // render everything if disabled if (!enabled) { foreach (var Block in AllBlocks) { var BlockScored = new TTexturePointBlockAndScore(); BlockScored.Block = Block; FilteredBlocks.Add(BlockScored); } return; } var Cam = CullCamera; var CameraPos = Cam.transform.position; var CameraForward = Cam.transform.localToWorldMatrix.MultiplyVector(Vector3.forward); float RestoreFov = Cam.fieldOfView; if (OverrideFov > 0) { Cam.fieldOfView = OverrideFov; } var FrustumPlanes = GeometryUtility.CalculateFrustumPlanes(Cam); Cam.fieldOfView = RestoreFov; var CullDistanceNearSq = CullDistanceNear * CullDistanceNear; var CullDistanceFarSq = CullDistanceFar * CullDistanceFar; if (RenderSpecificInstance != -1) { if (RenderSpecificInstance < AllBlocks.Count) { var InstanceScored = new TTexturePointBlockAndScore(); InstanceScored.Block = AllBlocks [RenderSpecificInstance]; InstanceScored.FrustumVisible = GeometryUtility.TestPlanesAABB(FrustumPlanes, InstanceScored.Block.BoundingBox); FilteredBlocks.Add(InstanceScored); } return; } foreach (var Block in AllBlocks) { var InstanceScored = new TTexturePointBlockAndScore(); InstanceScored.Block = Block; Block.Lod = Lod; var Box = Block.BoundingBox; //var InstancePos = Box.center; var InstancePos = Box.ClosestPoint(CameraPos); InstanceScored.DistanceSq = PopMath.Vector3_DistanceSquared(InstancePos, CameraPos); if (LodToDistance) { var Distance = Mathf.Sqrt(InstanceScored.DistanceSq); var CullDistanceFar = Mathf.Sqrt(CullDistanceFarSq); Block.Lod = 1 - (Distance / CullDistanceFar); if (Distance <= LodDistanceMin) { Block.Lod = 1; } Block.Lod *= Lod; } else if (LodToDistanceSquared) { var Distance = InstanceScored.DistanceSq; var CullDistanceFar = CullDistanceFarSq; Block.Lod = 1 - (Distance / CullDistanceFar); if (Distance <= (LodDistanceMin * LodDistanceMin)) { Block.Lod = 1; } Block.Lod *= Lod; } InstanceScored.DistanceVisible = true; if (InstanceScored.DistanceSq > CullDistanceFarSq) { InstanceScored.DistanceVisible = false; } if (InstanceScored.DistanceSq < CullDistanceNearSq) { InstanceScored.DistanceVisible = false; } if (CullByDistance && !AddCulledBlocks && !InstanceScored.DistanceVisible) { continue; } var InstanceForward = InstancePos - CameraPos; InstanceForward.Normalize(); InstanceScored.DotToCamera = Vector3.Dot(InstanceForward, CameraForward); InstanceScored.FrustumVisible = GeometryUtility.TestPlanesAABB(FrustumPlanes, Box); if (CullByFrustum && !AddCulledBlocks && !InstanceScored.FrustumVisible) { continue; } FilteredBlocks.Add(InstanceScored); } FilteredBlocks.Sort((a, b) => { if (FrustumDotRanges > 0) { var Dota = (int)(a.DotToCamera * FrustumDotRanges); var Dotb = (int)(b.DotToCamera * FrustumDotRanges); if (Dota > Dotb) { return(-1); } if (Dota > Dotb) { return(1); } } else { if (a.DotToCamera > b.DotToCamera) { return(-1); } if (a.DotToCamera < b.DotToCamera) { return(1); } } if (a.DistanceSq < b.DistanceSq) { return(-1); } if (a.DistanceSq > b.DistanceSq) { return(1); } return(0); } ); if (!AddCulledBlocks) { // now clip if (FilteredBlocks.Count > MaxInstances) { FilteredBlocks.RemoveRange(MaxInstances, FilteredBlocks.Count - MaxInstances); } int TotalTriangles = 0; for (int i = 0; i < FilteredBlocks.Count; i++) { var InstanceTriangleCount = FilteredBlocks [i].Block.LodPointCount; if (LodToMaxTriangles) { } else { // clip if (TotalTriangles + InstanceTriangleCount > MaxTriangles) { FilteredBlocks.RemoveRange(i, FilteredBlocks.Count - i); break; } } TotalTriangles += InstanceTriangleCount; } int LodToMaxTriangles_TriangleCount = 0; if (TotalTriangles > MaxTriangles && LodToMaxTriangles) { // scale down all the LOD's to fit max triangles float LodScale = MaxTriangles / (float)TotalTriangles; #if UNITY_EDITOR if (EnableDebug) { Debug.Log("LodScale=" + LodScale); } #endif foreach (var Block in FilteredBlocks) { var OldTriangleCount = Block.Block.LodPointCount; Block.Block.Lod *= LodScale; var NewTriangleCount = Block.Block.LodPointCount; LodToMaxTriangles_TriangleCount += NewTriangleCount; } } #if UNITY_EDITOR if (EnableDebug) { Debug.Log("Total triangles=" + TotalTriangles + " (lod'd to " + LodToMaxTriangles_TriangleCount + ") total blocks=" + FilteredBlocks.Count); } #endif } }