public void CalculateFrustumCorners_IsFrustumCorners() { var projection = float4x4.CreatePerspectiveFieldOfView(M.PiOver2, 1, 2, 10); var actualCorners = Frustum.CalculateFrustumCorners(projection).ToList(); var expectedCorners = new List <float3>() { new float3(-2, -2, 2), new float3(2, -2, 2), new float3(-2, 2, 2), new float3(2, 2, 2), new float3(-10, -10, 10), new float3(10, -10, 10), new float3(-10, 10, 10), new float3(10, 10, 10), }; Assert.Equal(actualCorners.Count, expectedCorners.Count); for (int i = 0; i < actualCorners.Count; i++) { Assert.Equal(expectedCorners[i].x, actualCorners[i].x, 4); Assert.Equal(expectedCorners[i].y, actualCorners[i].y, 4); Assert.Equal(expectedCorners[i].z, actualCorners[i].z, 4); } }
/// <summary> /// Returns a tuple of the world space frustum corners and the clipping planes for each sub-frustum. /// </summary> /// <param name="numberOfCascades">The number of times the viewing frustum is divided. A Cascade is created for each of the sub-frustum.</param> /// <param name="lambda">A constant value, used to weight the logarithmic split with the uniform split of the viewing frustum.</param> /// <param name="zNear">The near clipping plane of the camera.</param> /// <param name="zFar">The far clipping plane of the camera.</param> /// <param name="width">The window width in px.</param> /// <param name="height">The window height in px.</param> /// <param name="fov">The field of view of the camera.</param> /// <param name="view">The view matrix.</param> private static IEnumerable <Tuple <float3[], float2> > CascadeCornersWorldSpace(int numberOfCascades, float lambda, float zNear, float zFar, int width, int height, float fov, float4x4 view) { var allSplitProjectionMatrices = CascadesProjectionMatrices(numberOfCascades, lambda, zNear, zFar, width, height, fov); foreach (Tuple <float4x4, float2> tuple in allSplitProjectionMatrices) { yield return(new Tuple <float3[], float2>(Frustum.CalculateFrustumCorners(tuple.Item1 * view).ToArray(), tuple.Item2)); } }
// RenderAFrame is called once a frame public override void RenderAFrame() { if (Mouse.RightButton) { _valHorzSnd = Mouse.XVel * 0.003f * DeltaTime; _valVertSnd = Mouse.YVel * 0.003f * DeltaTime; _anlgeHorznd += _valHorzSnd; _angleVertSnd += _valVertSnd; _valHorzSnd = _valVertSnd = 0; _sndCamTransform.FpsView(_anlgeHorznd, _angleVertSnd, Keyboard.WSAxis, Keyboard.ADAxis, DeltaTime * 10); } else if (Mouse.LeftButton) { _valHorzMain = Mouse.XVel * 0.003f * DeltaTime; _valVertMain = Mouse.YVel * 0.003f * DeltaTime; _anlgeHorzMain += _valHorzMain; _angleVertMain += _valVertMain; _valHorzMain = _valVertMain = 0; _mainCamTransform.FpsView(_anlgeHorzMain, _angleVertMain, Keyboard.WSAxis, Keyboard.ADAxis, DeltaTime * 10); } float4x4 viewProjection = _mainCam.GetProjectionMat(Width, Height, out float4 viewport) * float4x4.Invert(_mainCamTransform.Matrix()); _frustum.Vertices = Frustum.CalculateFrustumCorners(viewProjection).ToArray(); Frustum frustum = new Frustum(); frustum.CalculateFrustumPlanes(viewProjection); // Sets a mesh inactive if it does not pass the culling test and active if it does. // The reason for this is to achieve that the cubes don't get rendered in the viewport in the upper right. // Because SceneRenderer.RenderMesh has an early-out if a Mesh is inactive we do not perform the culling test twice. UserSideFrustumCulling(_rocketScene.Children, frustum); _sceneRenderer.Render(RC); _guiRenderer.Render(RC); if (!Mouse.Desc.Contains("Android")) { _sih.CheckForInteractiveObjects(RC, Mouse.Position, Width, Height); } if (Touch.GetTouchActive(TouchPoints.Touchpoint_0) && !Touch.TwoPoint) { _sih.CheckForInteractiveObjects(RC, Touch.GetPosition(TouchPoints.Touchpoint_0), Width, Height); } // Swap buffers: Show the contents of the backbuffer (containing the currently rendered frame) on the front buffer. Present(); }