/// <summary> /// Helper function for transforming from world to window coordinates. /// This only works if the cameraEntity has a valid LocalToWorld /// component. Returns windowPos (window position) and windowSize (window size) in /// the same coordinates. /// </summary> public static float2 WorldToWindow(ComponentSystem callingSystem, Entity cameraEntity, float3 worldPos, float2 windowSize) { var mgr = callingSystem.EntityManager; DisplayListCamera dlc = mgr.GetComponentData <DisplayListCamera>(cameraEntity); Camera2D c2d = mgr.GetComponentData <Camera2D>(cameraEntity); float aspect = windowSize.x / windowSize.y; float2 camsize; camsize.x = c2d.halfVerticalSize * aspect; camsize.y = c2d.halfVerticalSize; // transform from world to window float3 viewpos; viewpos = math.transform(dlc.inverseWorld, worldPos); // to normalized window float2 windowPos; windowPos.x = viewpos.x / camsize.x; windowPos.y = viewpos.y / camsize.y; // to output window windowPos.x = (windowPos.x * .5f + .5f) * windowSize.x; windowPos.y = (windowPos.y * .5f + .5f) * windowSize.y; return(windowPos); }
/// <summary> /// Helper function for transforming from window to world coordinates. /// This only works if cameraEntity has a valid LocalToWorld /// component. The windowPos (window position) and windowSize (window size) should be /// in the same coordinates. The Z coordinate is set to 0. /// </summary> public static float3 WindowToWorld(ComponentSystem callingSystem, Entity cameraEntity, float2 windowPos, float2 windowSize) { var mgr = callingSystem.EntityManager; if (!mgr.HasComponent <DisplayListCamera>(cameraEntity) || !mgr.HasComponent <Camera2D>(cameraEntity)) { return(float3.zero); } DisplayListCamera dlc = mgr.GetComponentData <DisplayListCamera>(cameraEntity); Camera2D c2d = mgr.GetComponentData <Camera2D>(cameraEntity); float aspect = windowSize.x / windowSize.y; float2 camsize; camsize.x = c2d.halfVerticalSize * aspect; camsize.y = c2d.halfVerticalSize; float2 normalizedWindow; normalizedWindow.x = (windowPos.x / windowSize.x) * 2.0f - 1.0f; normalizedWindow.y = (windowPos.y / windowSize.y) * 2.0f - 1.0f; float3 viewpos; viewpos.x = normalizedWindow.x * camsize.x; viewpos.y = normalizedWindow.y * camsize.y; viewpos.z = 0; float3 worldPos = math.transform(dlc.world, viewpos); return(worldPos); }
protected bool FinishDisplayListEntry(ref DisplayListEntry de, ref DisplayListCamera dlc, ref LocalToWorld tx, ref PrivateTransformData ptd, bool doNotClip) { de.inSortingGroup = ptd.inSortingGroup; #if UNITY_USE_TINYMATH de.finalMatrix = tinymath.mul(dlc.inverseWorld, tx.Value); #else de.finalMatrix = math.mul(dlc.inverseWorld, tx.Value); #endif if (doNotClip) { return(true); } // z-clip float z = de.finalMatrix[2][3]; if (z < dlc.clipZNear || z > dlc.clipZFar) { return(false); } // bounds clip #if DEBUG if (!(de.inBounds.width > 0.0f) || !(de.inBounds.height > 0.0f)) { Debug.LogFormat("Entity {0} has zero or negative size ({1},{2})! This is checked in DEVELOPMENT builds only!", de.e, de.inBounds.width, de.inBounds.height); return(false); } #endif return(true); }
protected void AddItemsToListByType(IExternalDisplayListEntryMaker dlm, DisplayListCamera dlc, Camera2D c2d, DynamicBuffer <DisplayListEntry> dest, DynamicBuffer <SortedEntity> destSorted) { var mgr = EntityManager; dlm.Update(this); var cachedGetLayerSorting = GetComponentDataFromEntity <LayerSorting>(true); bool doNotClip = dlm.DoNotClip(); var query = Entities; // build the query: Add base filter and dlm, then add per - camera filter dlm.Filter(ref query); // add camera 'layer' filter AddLayerFilter(ref query, c2d); // run query query.ForEach((Entity e, ref PrivateTransformData ptd, ref LocalToWorld tx) => { DisplayListEntry de = default; de.e = e; if (!dlm.MakeEntry(mgr, ref de)) { return; } if (!FinishDisplayListEntry(ref de, ref dlc, ref tx, ref ptd, doNotClip)) { return; } float z = math.dot(de.finalMatrix[3], dlc.sortingDot); // = Dot(de.finalMatrix.GetColumn(3), dlc.camSortingDot); TODO CHECK SortedEntity se = new SortedEntity { e = de.e, idx = dest.Length }; if (cachedGetLayerSorting.Exists(de.e)) { var sortEx = cachedGetLayerSorting[de.e]; se.CombineKey(z, sortEx.layer, sortEx.order); } else { se.CombineKey(z); } se.e = de.e; se.idx = dest.Length; dest.Add(de); destSorted.Add(se); }); }
protected int UpdateOneDisplayListCamera(Entity e, ref Camera2D cam, ref DisplayListCamera dlcCam, ref LocalToWorld tx, float primaryAspect) { var mgr = EntityManager; // get list and sorted list buffers DynamicBuffer <DisplayListEntry> dest = mgr.GetBuffer <DisplayListEntry>(e); DynamicBuffer <SortedEntity> destSorted = mgr.GetBuffer <SortedEntity>(e); dest.Clear(); destSorted.Clear(); #if DEBUG if (!(cam.rect.x >= 0.0f && cam.rect.y >= 0.0f && cam.rect.x + cam.rect.width <= 1.0f && cam.rect.y + cam.rect.height <= 1.0f)) { Debug.LogFormat("The camera {0} has an invalid rect field ({1},{2},{3},{4}). Fixing by clamping it to the unit rectangle (0,0,1,1) in DEVELOPMENT build only.", e, cam.rect.x, cam.rect.y, cam.rect.width, cam.rect.height); cam.rect.Clamp(new Rect(0, 0, 1, 1)); } if (cam.rect.IsEmpty()) { Debug.LogFormat("The camera {0} has an empty rect field. Fixing by setting it to identity in DEVELOPMENT build only.", e); cam.rect = new Rect(0, 0, 1, 1); } if (cam.halfVerticalSize <= 0) { Debug.LogFormat("The camera {0} has an invalid halfVerticalSize size of {1}. Nothing will render for it.", e, cam.halfVerticalSize); return(0); } float mas = MaxAbsScale(tx.Value); if (!(mas > .99f && mas < 1.01f)) { Debug.LogFormat("The entity {0} with a Camera2D has a maximum absolute scaling factor of {1}. Cameras can not be scaled for rendering. Rendering and picking with this camera will likely be wrong.", e, mas); } #endif // get camera sorting axis if (mgr.HasComponent <Camera2DAxisSort>(e)) { var axissort = mgr.GetComponentData <Camera2DAxisSort>(e); dlcCam.sortingDot.xyz = -axissort.axis; dlcCam.sortingDot.w = 0; } else { dlcCam.sortingDot.x = 0.0f; dlcCam.sortingDot.y = 0.0f; dlcCam.sortingDot.z = -1.0f; dlcCam.sortingDot.w = 0.0f; } // copy transform matrix dlcCam.world = tx.Value; dlcCam.inverseWorld = math.inverse(dlcCam.world); // initialize 2d clipping if (mgr.HasComponent <Camera2DRenderToTexture>(e)) { var rtt = mgr.GetComponentData <Camera2DRenderToTexture>(e); float localAspect = (float)rtt.width / (float)rtt.height; dlcCam.clip2D.x = cam.halfVerticalSize * localAspect; dlcCam.clip2D.y = cam.halfVerticalSize; } else { dlcCam.clip2D.x = cam.halfVerticalSize * primaryAspect; dlcCam.clip2D.y = cam.halfVerticalSize; } // initialize near/far clipping if (mgr.HasComponent <Camera2DClippingPlanes>(e)) { var clipz = mgr.GetComponentData <Camera2DClippingPlanes>(e); dlcCam.clipZNear = clipz.near; dlcCam.clipZFar = clipz.far; } else { dlcCam.clipZNear = float.MinValue; dlcCam.clipZFar = float.MaxValue; } #if DEBUG if (dlcCam.clipZNear >= dlcCam.clipZFar) { Debug.LogFormat("The camera {0} has an invalid z clip range [{1}...{2}]. Nothing will render for it.", e, dlcCam.clipZNear, dlcCam.clipZFar); return(0); } #endif // add all items for (int i = 0; i < dlMakerReg.Count; i++) { AddItemsToListByType(dlMakerReg[i], dlcCam, cam, dest, destSorted); } // sort in c++ unsafe { SortExternal(dest.GetUnsafePtr(), destSorted.GetUnsafePtr(), dest.Length); } return(dest.Length); }