Example #1
0
        public void TestCullerPlaceInTree()
        {
            var           game   = new DX11Game();
            Vector3       radius = new Vector3(100, 1000, 100);
            FrustumCuller culler = new FrustumCuller(new BoundingBox(-radius, radius), 5);


            var visualizer = new QuadTreeVisualizer();

            List <TestCullObject> cullObjects = new List <TestCullObject>();


            TestCullObject obj;

            obj = new TestCullObject(new Vector3(5, 2, 5), 2);
            cullObjects.Add(obj);

            obj = new TestCullObject(new Vector3(-20, 2, -20), 15);
            cullObjects.Add(obj);

            obj = new TestCullObject(new Vector3(100, 2, -20), 4);
            cullObjects.Add(obj);

            obj = new TestCullObject(new Vector3(-50, 9, 24), 20);
            cullObjects.Add(obj);

            for (int i = 0; i < cullObjects.Count; i++)
            {
                culler.AddCullable(cullObjects[i]);
            }

            game.GameLoopEvent +=
                delegate
            {
                for (int i = 0; i < cullObjects.Count; i++)
                {
                    game.LineManager3D.AddBox(cullObjects[i].BoundingBox, Color.Red.dx());
                }
                visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                                                   delegate(FrustumCuller.CullNode node, out Color4 col)
                {
                    col = Color.Green.dx();

                    return(node.Cullables.Count == 0);
                });

                visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                                                   delegate(FrustumCuller.CullNode node, out Color4 col)
                {
                    col = Color.Orange.dx();

                    return(node.Cullables.Count > 0);
                });
            };



            game.Run();
        }
Example #2
0
        public DirectionalLight(FrustumCuller culler)
        {
            LightDirection = Vector3.Normalize(new Vector3(1, 2, 1));
            Color          = new Vector3(1, 1, 0.9f);

            ShadowViews = new FrustumCullerView[4];
            for (int i = 0; i < ShadowViews.Length; i++)
            {
                ShadowViews[i] = culler.CreateView();
            }
        }
Example #3
0
        public SpotLight(FrustumCuller culler)
        {
            LightPosition     = new Vector3(0, 6, 0);
            LightRadius       = 6;
            LightIntensity    = 1;
            SpotDirection     = MathHelper.Down;
            SpotLightAngle    = MathHelper.ToRadians(30);
            SpotDecayExponent = 1;


            Color      = new Vector3(1, 1, 0.9f);
            ShadowView = culler.CreateView();
        }
        public PointLight(FrustumCuller culler)
        {
            LightPosition  = new Vector3(0, 6, 0);
            LightRadius    = 6;
            LightIntensity = 1;

            Color = new Vector3(1, 1, 0.9f);

            Views = new FrustumCullerView[6];
            for (int i = 0; i < Views.Length; i++)
            {
                Views[i] = culler.CreateView();
            }
        }
Example #5
0
        public void TestCullerVisibility()
        {
            var           game   = new DX11Game();
            Vector3       radius = new Vector3(100, 1000, 100);
            FrustumCuller culler = new FrustumCuller(new BoundingBox(-radius, radius), 6);



            QuadTreeVisualizer visualizer = new QuadTreeVisualizer();

            List <TestCullObject> cullObjects = new List <TestCullObject>();


            TestCullObject obj;


            for (int i = 0; i < cullObjects.Count; i++)
            {
                culler.AddCullable(cullObjects[i]);
            }



            SpectaterCamera cullCam = new SpectaterCamera(10f, 80);

            cullCam.Positie         = new Vector3(8, 10, 8);
            cullCam.EnableUserInput = false;

            bool rotate = true;

            int selectedNode = -1;

            var view = culler.CreateView();


            game.GameLoopEvent +=
                delegate
            {
                view.UpdateVisibility(cullCam.ViewProjection);
                if (rotate)
                {
                    cullCam.AngleHorizontal += game.Elapsed * MathHelper.Pi * (1 / 8f);
                }

                if (game.Keyboard.IsKeyPressed(Key.NumberPadPlus))
                {
                    selectedNode++;
                }
                if (game.Keyboard.IsKeyPressed(Key.NumberPadMinus))
                {
                    selectedNode--;
                }

                if (game.Keyboard.IsKeyPressed(Key.Return))
                {
                    int count = -1;
                    visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                                                       delegate(FrustumCuller.CullNode node, out Color4 col)
                    {
                        col = Color.Red.dx();
                        count++;
                        if (count == selectedNode)
                        {
                            node.Tag = "SELECTED!";
                        }
                        return(count == selectedNode);
                    });
                }

                if (game.Keyboard.IsKeyPressed(Key.NumberPad0))
                {
                    rotate = !rotate;
                }



                game.LineManager3D.AddViewFrustum(new global::DirectX11.BoundingFrustum(cullCam.ViewProjection), Color.Black.dx());
                for (int i = 0; i < cullObjects.Count; i++)
                {
                    game.LineManager3D.AddBox(cullObjects[i].BoundingBox, Color.Red.dx());
                }
                visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                                                   delegate(FrustumCuller.CullNode node, out Color4 col)
                {
                    col = Color.Green.dx();

                    return(!view.IsNodeVisible(node));
                });

                visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                                                   delegate(FrustumCuller.CullNode node, out Color4 col)
                {
                    col = Color.Orange.dx();

                    return(view.IsNodeVisible(node));
                });

                cullCam.Update(game.Elapsed, game.Keyboard, game.Mouse);

                /*int count = -1;
                 * visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                 * delegate(Culler.CullNode node, out Color col)
                 * {
                 *  col = Color.Red;
                 *  count++;
                 *  return count == selectedNode;
                 * });*/
            };



            game.Run();
        }
Example #6
0
        public void TestCullerObjects()
        {
            var game = new DX11Game();

            game.InitDirectX();
            Vector3       radius = new Vector3(100, 1000, 100);
            FrustumCuller culler = new FrustumCuller(new BoundingBox(-radius, radius), 6);

            var mesh = RenderingTestsHelper.CreateSimpleTestMesh();

            var texturePool = new TexturePool(game);

            var gBuffer = new GBuffer(game.Device, 800, 600);

            var renderer = new DeferredMeshesRenderer(game, gBuffer, texturePool);
            var final    = new CombineFinalRenderer(game, gBuffer);



            DeferredMeshElement middle = null;

            for (int i = 0; i < 50; i++)
            {
                for (int j = 0; j < 50; j++)
                {
                    var el = renderer.AddMesh(mesh);
                    el.WorldMatrix = Matrix.Translation(MathHelper.Right * i * 2 + Vector3.UnitZ * j * 2);

                    if (i > 20 && i < 30 && j > 20 && j < 30)
                    {
                        el.Delete();
                    }
                    else
                    {
                        culler.AddCullable(el);
                    }
                }
            }

            QuadTreeVisualizer visualizer = new QuadTreeVisualizer();

            List <TestCullObject> cullObjects = new List <TestCullObject>();



            SpectaterCamera cullCam = new SpectaterCamera(10f, 80);

            cullCam.Positie         = new Vector3(8, 10, 8);
            cullCam.EnableUserInput = false;

            bool rotate = true;

            int selectedNode = -1;

            var view = culler.CreateView();


            game.GameLoopEvent +=
                delegate
            {
                view.UpdateVisibility(cullCam.ViewProjection);
                var visibleCullables = view.GetVisibleCullables();

                if (rotate)
                {
                    cullCam.AngleHorizontal += game.Elapsed * MathHelper.Pi * (1 / 8f);
                }

                if (game.Keyboard.IsKeyPressed(Key.NumberPadPlus))
                {
                    selectedNode++;
                }
                if (game.Keyboard.IsKeyPressed(Key.NumberPadMinus))
                {
                    selectedNode--;
                }

                if (game.Keyboard.IsKeyPressed(Key.Return))
                {
                    int count = -1;
                    visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                                                       delegate(FrustumCuller.CullNode node, out Color4 col)
                    {
                        col = Color.Red.dx();
                        count++;
                        if (count == selectedNode)
                        {
                            node.Tag = "SELECTED!";
                        }
                        return(count == selectedNode);
                    });
                }

                if (game.Keyboard.IsKeyPressed(Key.NumberPad0))
                {
                    rotate = !rotate;
                }



                gBuffer.Clear();
                gBuffer.SetTargetsToOutputMerger();
                renderer.Draw();

                game.Device.ImmediateContext.ClearState();
                game.SetBackbuffer();

                final.DrawCombined();


                game.LineManager3D.AddViewFrustum(new BoundingFrustum(cullCam.ViewProjection), Color.White.dx());
                for (int i = 0; i < visibleCullables.Count; i++)
                {
                    game.LineManager3D.AddBox(visibleCullables[i].BoundingBox, Color.Red.dx());
                }
                visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                                                   delegate(FrustumCuller.CullNode node, out Color4 col)
                {
                    col = Color.Green.dx();

                    return(!view.IsNodeVisible(node));
                });

                visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                                                   delegate(FrustumCuller.CullNode node, out Color4 col)
                {
                    col = Color.Orange.dx();

                    return(view.IsNodeVisible(node));
                });

                cullCam.Update(game.Elapsed, game.Keyboard, game.Mouse);


                /*int count = -1;
                 * visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                 * delegate(Culler.CullNode node, out Color col)
                 * {
                 *  col = Color.Red;
                 *  count++;
                 *  return count == selectedNode;
                 * });*/
            };



            game.Run();
        }
Example #7
0
        public void TestPointLightDownViewFrustumVisibility()
        {
            var game = new DX11Game();

            game.InitDirectX();
            Vector3       radius = new Vector3(100, 1000, 100);
            FrustumCuller culler = new FrustumCuller(new BoundingBox(-radius, radius), 6);



            QuadTreeVisualizer visualizer = new QuadTreeVisualizer();

            List <TestCullObject> cullObjects = new List <TestCullObject>();


            TestCullObject obj;


            for (int i = 0; i < cullObjects.Count; i++)
            {
                culler.AddCullable(cullObjects[i]);
            }



            Matrix viewProjection = Matrix.Identity;

            var pos = game.SpectaterCamera.CameraPosition;

            bool rotate = true;

            int selectedNode = -1;

            var view = culler.CreateView();


            game.GameLoopEvent +=
                delegate
            {
                if (game.Keyboard.IsKeyDown(Key.C))
                {
                    pos = game.SpectaterCamera.CameraPosition;
                }

                viewProjection = PointLightRenderer.CreateShadowMapView(pos, 3) *
                                 PointLightRenderer.CreateShadowMapProjection(10);

                view.UpdateVisibility(viewProjection);


                if (game.Keyboard.IsKeyPressed(Key.NumberPadPlus))
                {
                    selectedNode++;
                }
                if (game.Keyboard.IsKeyPressed(Key.NumberPadMinus))
                {
                    selectedNode--;
                }



                game.LineManager3D.AddViewFrustum(new BoundingFrustum(viewProjection), Color.Black.dx());
                for (int i = 0; i < cullObjects.Count; i++)
                {
                    game.LineManager3D.AddBox(cullObjects[i].BoundingBox, Color.Red.dx());
                }


                if (game.Keyboard.IsKeyDown(Key.Return))
                {
                    int count = -1;
                    visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                                                       delegate(FrustumCuller.CullNode node, out Color4 col)
                    {
                        col = Color.Green.dx();

                        count++;
                        if (count == selectedNode)
                        {
                            col = Color.Red.dx();

                            node.Tag = "SELECTED!";
                        }
                        return(count == selectedNode);
                    });
                }
                else
                {
                    visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                                                       delegate(FrustumCuller.CullNode node, out Color4 col)
                    {
                        if (view.IsNodeVisible(node))
                        {
                            col = Color.Orange.dx();
                            return(true);
                        }
                        col = Color.Green.dx();
                        return(false);
                    });
                }

                /*int count = -1;
                 * visualizer.RenderNodeGroundBoundig(game, culler.RootNode,
                 * delegate(Culler.CullNode node, out Color col)
                 * {
                 *  col = Color.Red;
                 *  count++;
                 *  return count == selectedNode;
                 * });*/
            };



            game.Run();
        }
        public DeferredRenderer(DX11Game game)
        {
            this.game = game;
            var device = game.Device;

            context = device.ImmediateContext;

            screenWidth  = game.Form.Form.ClientSize.Width;
            screenHeight = game.Form.Form.ClientSize.Height;
            int width  = screenWidth;
            int height = screenHeight;

            gBuffer     = new GBuffer(game.Device, width, height);
            texturePool = new TexturePool(game);

            meshesRenderer = new DeferredMeshesRenderer(game, gBuffer, TexturePool);

            directionalLightRenderer = new DirectionalLightRenderer(game, GBuffer);
            spotLightRenderer        = new SpotLightRenderer(game, GBuffer);
            pointLightRenderer       = new PointLightRenderer(game, GBuffer);

            combineFinalRenderer = new CombineFinalRenderer(game, GBuffer);

            var desc = new Texture2DDescription
            {
                BindFlags =
                    BindFlags.RenderTarget | BindFlags.ShaderResource,
                Format            = Format.R16G16B16A16_Float,
                Width             = screenWidth,
                Height            = screenHeight,
                ArraySize         = 1,
                SampleDescription = new SampleDescription(1, 0),
                MipLevels         = 1
            };

            hdrImage = new Texture2D(device, desc);

            hdrImageRtv = new RenderTargetView(device, hdrImage);
            hdrImageRV  = new ShaderResourceView(device, hdrImage);

            calculater = new AverageLuminanceCalculater(game, hdrImageRV);

            toneMap = new ToneMapRenderer(game);


            var tempDesc = new Texture2DDescription
            {
                ArraySize         = 1,
                BindFlags         = BindFlags.None,
                CpuAccessFlags    = CpuAccessFlags.Read,
                Format            = Format.R32_Float,
                Height            = 1,
                MipLevels         = 1,
                OptionFlags       = ResourceOptionFlags.None,
                SampleDescription = new SampleDescription(1, 0),
                Usage             = ResourceUsage.Staging,
                Width             = 1
            };

            tempTex = new Texture2D(device, tempDesc);



            ssao = new HorizonSSAORenderer(game, screenWidth, screenHeight);



            Vector3 radius = new Vector3(500, 1000, 500);

            frustumCuller = new FrustumCuller(new BoundingBox(-radius, radius), 1);

            gbufferView           = frustumCuller.CreateView();
            meshesRenderer.Culler = frustumCuller;

            Texture2D skyColorTexture;// = Texture2D.FromFile(game.Device, TWDir.GameData.CreateSubdirectory("Core") + "\\skyColor.bmp");

            var strm = new DataStream(16 * 4, true, true);

            var multiplier = 2;

            strm.Write(new Half4(new Half(135f / 255f * multiplier), new Half(206f / 255f * multiplier), new Half(235 / 255f * multiplier), new Half(1)));
            strm.Position = 0;
            var dataRectangle = new DataRectangle(16 * 4, strm);

            skyColorTexture = new Texture2D(game.Device, new Texture2DDescription
            {
                ArraySize         = 1,
                BindFlags         = BindFlags.ShaderResource,
                CpuAccessFlags    = CpuAccessFlags.None,
                Format            = Format.R16G16B16A16_Float,
                Height            = 1,
                MipLevels         = 1,
                OptionFlags       = ResourceOptionFlags.None,
                SampleDescription = new SampleDescription(1, 0),
                Usage             = ResourceUsage.Default,
                Width             = 1
            }, dataRectangle);

            skyColorRV = new ShaderResourceView(game.Device, skyColorTexture);


            postProcessRT1 = CreateBackbufferLikeRT();
            postProcessRT2 = CreateBackbufferLikeRT();

            fogRenderer = new FogEffect(game);

            backgroundDepthStencilState = DepthStencilState.FromDescription(game.Device, new DepthStencilStateDescription()
            {
                IsDepthEnabled  = true,
                DepthComparison = Comparison.LessEqual,
                DepthWriteMask  = DepthWriteMask.Zero,
            });

            lineManager = new LineManager3D(game.Device);
            updateRasterizerState();
        }
        protected void ComputeProjections(
            List <SSObject> objects,
            Matrix4 cameraView,
            Matrix4 cameraProj,
            float fov, float aspect, float cameraNearZ, float cameraFarZ)
        {
            if (m_light.GetType() != typeof(SSDirectionalLight))
            {
                throw new NotSupportedException();
            }
            SSDirectionalLight dirLight = (SSDirectionalLight)m_light;

            // light-aligned unit vectors
            Vector3 lightZ = dirLight.Direction.Normalized();
            Vector3 lightX, lightY;

            OpenTKHelper.TwoPerpAxes(lightZ, out lightX, out lightY);
            // transform matrix from regular space into light aligned space
            Matrix4 lightTransform = new Matrix4(
                lightX.X, lightX.Y, lightX.Z, 0f,
                lightY.X, lightY.Y, lightY.Z, 0f,
                lightZ.X, lightZ.Y, lightZ.Z, 0f,
                0f, 0f, 0f, 0f
                );

            // Step 0: camera projection matrix (nearZ and farZ modified) for each frustum split
            float prevFarZ = cameraNearZ;

            for (int i = 0; i < c_numberOfSplits; ++i)
            {
                // generate frustum splits using Practical Split Scheme (GPU Gems 3, 10.2.1)
                float iRatio    = (float)(i + 1) / (float)c_numberOfSplits;
                float cLog      = cameraNearZ * (float)Math.Pow(cameraFarZ / cameraNearZ, iRatio);
                float cUni      = cameraNearZ + (cameraFarZ - cameraNearZ) * iRatio;
                float nextFarZ  = LogVsLinearSplitFactor * cLog + (1f - LogVsLinearSplitFactor) * cUni;
                float nextNearZ = prevFarZ;

                // exported to the shader
                m_viewSplits [i] = nextFarZ;

                // create a view proj matrix with the nearZ, farZ values for the current split
                m_frustumViewProjMatrices[i] = cameraView
                                               * Matrix4.CreatePerspectiveFieldOfView(fov, aspect, nextNearZ, nextFarZ);

                // create light-aligned AABBs of frustums
                m_frustumLightBB [i] = SSAABB.FromFrustum(ref lightTransform, ref m_frustumViewProjMatrices [i]);

                prevFarZ = nextFarZ;
            }

            #if true
            // Optional scene-dependent optimization
            for (int i = 0; i < c_numberOfSplits; ++i)
            {
                m_objsLightBB[i]   = new SSAABB(float.PositiveInfinity, float.NegativeInfinity);
                m_splitFrustums[i] = new FrustumCuller(ref m_frustumViewProjMatrices[i]);
                m_shrink[i]        = false;
            }
            foreach (var obj in objects)
            {
                // pass through all shadow casters and receivers
                if (obj.renderState.toBeDeleted || obj.localBoundingSphereRadius <= 0f ||
                    !obj.renderState.visible || !obj.renderState.receivesShadows)
                {
                    continue;
                }
                else
                {
                    for (int i = 0; i < c_numberOfSplits; ++i)
                    {
                        if (m_splitFrustums[i].isSphereInsideFrustum(obj.worldBoundingSphere))
                        {
                            // determine AABB in light coordinates of the objects so far
                            m_shrink[i] = true;
                            Vector3 lightAlignedPos = Vector3.Transform(obj.worldBoundingSphereCenter, lightTransform);
                            Vector3 rad             = new Vector3(obj.worldBoundingSphereRadius);
                            Vector3 localMin        = lightAlignedPos - rad;
                            Vector3 localMax        = lightAlignedPos + rad;

                            m_objsLightBB[i].UpdateMin(localMin);
                            m_objsLightBB[i].UpdateMax(localMax);
                        }
                    }
                }
            }
            #endif

            for (int i = 0; i < c_numberOfSplits; ++i)
            {
                if (m_shrink [i])
                {
                    m_resultLightBB[i].Min = Vector3.ComponentMax(m_frustumLightBB [i].Min,
                                                                  m_objsLightBB [i].Min);
                    m_resultLightBB [i].Max = Vector3.ComponentMin(m_frustumLightBB [i].Max,
                                                                   m_objsLightBB [i].Max);
                }
                else
                {
                    m_resultLightBB [i] = m_frustumLightBB [i];
                }
            }

            for (int i = 0; i < c_numberOfSplits; ++i)
            {
                // Obtain view + projection + crop matrix, need it later
                Matrix4 shadowView, shadowProj;
                viewProjFromLightAlignedBB(ref m_resultLightBB [i], ref lightTransform, ref lightY,
                                           out shadowView, out shadowProj);
                m_shadowViewProjMatrices[i] = shadowView * shadowProj * c_cropMatrices[i];
                // obtain view + projection + clio + bias
                m_shadowViewProjBiasMatrices[i] = m_shadowViewProjMatrices[i] * c_biasMatrix;

                // There is, currently, no mathematically derived solution to how much Poisson spread scaling
                // you need for each split. Current improvisation combines 1) increasing spread for the near
                // splits; reducing spread for the far splits and 2) reducing spread for splits with larger
                // light-aligned areas; increasing spread for splits with smaller light-aligned areas
                m_poissonScaling [i] = m_resultLightBB [i].Diff().Xy / (100f * (float)Math.Pow(3.0, i - 1));
            }

            // Combine all splits' BB into one and extend it to include shadow casters closer to light
            SSAABB castersLightBB = new SSAABB(float.PositiveInfinity, float.NegativeInfinity);
            for (int i = 0; i < c_numberOfSplits; ++i)
            {
                castersLightBB.Combine(ref m_resultLightBB [i]);
            }

            // extend Z of the AABB to cover shadow-casters closer to the light
            foreach (var obj in objects)
            {
                if (obj.renderState.toBeDeleted || obj.localBoundingSphereRadius <= 0f ||
                    !obj.renderState.visible || !obj.renderState.castsShadow)
                {
                    continue;
                }
                else
                {
                    Vector3 lightAlignedPos = Vector3.Transform(obj.worldBoundingSphereCenter, lightTransform);
                    Vector3 rad             = new Vector3(obj.worldBoundingSphereRadius);
                    Vector3 localMin        = lightAlignedPos - rad;
                    Vector3 localMax        = lightAlignedPos + rad;

                    if (localMin.Z < castersLightBB.Min.Z)
                    {
                        if (OpenTKHelper.RectsOverlap(castersLightBB.Min.Xy,
                                                      castersLightBB.Max.Xy,
                                                      localMin.Xy,
                                                      localMax.Xy))
                        {
                            castersLightBB.Min.Z = localMin.Z;
                        }
                    }
                }
            }

            // Generate frustum culler from the BB extended towards light to include shadow casters
            Matrix4 frustumView, frustumProj;
            viewProjFromLightAlignedBB(ref castersLightBB, ref lightTransform, ref lightY,
                                       out frustumView, out frustumProj);
            Matrix4 frustumMatrix = frustumView * frustumProj;
            FrustumCuller = new FrustumCuller(ref frustumMatrix);
        }
Example #10
0
    private void init()
    {
        _frustumCuller = new FrustumCuller();

        if (_command == null)
        {
            _command = new CommandBuffer();
        }

        if (_compute == null)
        {
            _compute = new ComputeBuffer(24, 16);

            PosCol16[] points = new PosCol16[24];

            points[0] = new PosCol16()
            {
                Position = new Vector3(-factor, -factor, -factor), Color = new Color32(255, 255, 255, 255),
            };
            points[1] = new PosCol16()
            {
                Position = new Vector3(-factor, factor, -factor), Color = new Color32(255, 255, 255, 255),
            };
            points[2] = new PosCol16()
            {
                Position = new Vector3(factor, factor, -factor), Color = new Color32(255, 255, 255, 255),
            };
            points[3] = new PosCol16()
            {
                Position = new Vector3(factor, -factor, -factor), Color = new Color32(255, 255, 255, 255),
            };

            points[4] = new PosCol16()
            {
                Position = new Vector3(-factor, factor, -factor), Color = new Color32(255, 255, 255, 255),
            };
            points[5] = new PosCol16()
            {
                Position = new Vector3(factor, factor, -factor), Color = new Color32(255, 255, 255, 255),
            };
            points[6] = new PosCol16()
            {
                Position = new Vector3(factor, -factor, -factor), Color = new Color32(255, 255, 255, 255),
            };
            points[7] = new PosCol16()
            {
                Position = new Vector3(-factor, -factor, -factor), Color = new Color32(255, 255, 255, 255),
            };

            points[8] = new PosCol16()
            {
                Position = new Vector3(-factor, -factor, factor), Color = new Color32(255, 255, 255, 255),
            };
            points[9] = new PosCol16()
            {
                Position = new Vector3(-factor, factor, factor), Color = new Color32(255, 255, 255, 255),
            };
            points[10] = new PosCol16()
            {
                Position = new Vector3(factor, factor, factor), Color = new Color32(255, 255, 255, 255),
            };
            points[11] = new PosCol16()
            {
                Position = new Vector3(factor, -factor, factor), Color = new Color32(255, 255, 255, 255),
            };

            points[12] = new PosCol16()
            {
                Position = new Vector3(-factor, factor, factor), Color = new Color32(255, 255, 255, 255),
            };
            points[13] = new PosCol16()
            {
                Position = new Vector3(factor, factor, factor), Color = new Color32(255, 255, 255, 255),
            };
            points[14] = new PosCol16()
            {
                Position = new Vector3(factor, -factor, factor), Color = new Color32(255, 255, 255, 255),
            };
            points[15] = new PosCol16()
            {
                Position = new Vector3(-factor, -factor, factor), Color = new Color32(255, 255, 255, 255),
            };

            points[16] = new PosCol16()
            {
                Position = new Vector3(-factor, -factor, -factor), Color = new Color32(255, 255, 255, 255),
            };
            points[17] = new PosCol16()
            {
                Position = new Vector3(-factor, -factor, factor), Color = new Color32(255, 255, 255, 255),
            };
            points[18] = new PosCol16()
            {
                Position = new Vector3(-factor, factor, -factor), Color = new Color32(255, 255, 255, 255),
            };
            points[19] = new PosCol16()
            {
                Position = new Vector3(-factor, factor, factor), Color = new Color32(255, 255, 255, 255),
            };

            points[20] = new PosCol16()
            {
                Position = new Vector3(factor, -factor, -factor), Color = new Color32(255, 255, 255, 255),
            };
            points[21] = new PosCol16()
            {
                Position = new Vector3(factor, -factor, factor), Color = new Color32(255, 255, 255, 255),
            };
            points[22] = new PosCol16()
            {
                Position = new Vector3(factor, factor, -factor), Color = new Color32(255, 255, 255, 255),
            };
            points[23] = new PosCol16()
            {
                Position = new Vector3(factor, factor, factor), Color = new Color32(255, 255, 255, 255),
            };

            _compute.SetData(points);

            if (_matProp == null)
            {
                _matProp = new MaterialPropertyBlock();
            }

            _matProp.SetBuffer("_Vertices", _compute);
        }

        if (_mat == null)
        {
            _mat = new Material(Shader.Find("UnityPIC/CB_Unlit"));
        }

        if (_matProp == null)
        {
            _matProp = new MaterialPropertyBlock();
            _matProp.SetBuffer("_Vertices", _compute);
        }
    }
        private void ComputeProjections(List <SSObject> objects,
                                        SSLightBase light,
                                        Matrix4 cameraView, Matrix4 cameraProj)
        {
            if (light.GetType() != typeof(SSDirectionalLight))
            {
                throw new NotSupportedException();
            }
            SSDirectionalLight dirLight = (SSDirectionalLight)light;

            // light-aligned unit vectors
            Vector3 lightZ = dirLight.Direction.Normalized();
            Vector3 lightX, lightY;

            OpenTKHelper.TwoPerpAxes(lightZ, out lightX, out lightY);
            // transform matrix from regular space into light aligned space
            Matrix4 lightTransform = new Matrix4(
                lightX.X, lightX.Y, lightX.Z, 0f,
                lightY.X, lightY.Y, lightY.Z, 0f,
                lightZ.X, lightZ.Y, lightZ.Z, 0f,
                0f, 0f, 0f, 0f
                );

            // Find AABB of frustum corners in light coordinates
            Matrix4 cameraViewProj = cameraView * cameraProj;
            SSAABB  frustumLightBB = SSAABB.FromFrustum(ref lightTransform, ref cameraViewProj);

            bool   shrink      = false;
            SSAABB objsLightBB = new SSAABB(float.PositiveInfinity, float.NegativeInfinity);

            #if true
            // (optional) scene dependent optimization
            // Trim the light-bounding box by the shadow receivers (only in light-space x,y,maxz)
            FrustumCuller cameraFrustum = new FrustumCuller(ref cameraViewProj);

            foreach (var obj in objects)
            {
                // pass through all shadow casters and receivers
                if (obj.renderState.toBeDeleted || obj.localBoundingSphereRadius <= 0f ||
                    !obj.renderState.visible || !obj.renderState.receivesShadows)
                {
                    continue;
                }
                else if (cameraFrustum.isSphereInsideFrustum(obj.worldBoundingSphere))
                {
                    // determine AABB in light coordinates of the objects so far
                    shrink = true;
                    Vector3 lightAlignedPos = Vector3.Transform(obj.worldBoundingSphereCenter, lightTransform);
                    Vector3 rad             = new Vector3(obj.worldBoundingSphereRadius);
                    Vector3 localMin        = lightAlignedPos - rad;
                    Vector3 localMax        = lightAlignedPos + rad;
                    objsLightBB.UpdateMin(localMin);
                    objsLightBB.UpdateMax(localMax);
                }
            }
            #endif

            // Optimize the light-frustum-projection bounding box by the object-bounding-box
            SSAABB resultLightBB = new SSAABB(float.PositiveInfinity, float.NegativeInfinity);
            if (shrink)
            {
                // shrink the XY & far-Z coordinates..
                resultLightBB.Min.Xy = Vector2.ComponentMax(frustumLightBB.Min.Xy, objsLightBB.Min.Xy);
                resultLightBB.Min.Z  = objsLightBB.Min.Z;
                resultLightBB.Max    = Vector3.ComponentMin(frustumLightBB.Max, objsLightBB.Max);
            }
            else
            {
                resultLightBB = frustumLightBB;
            }

            // View and projection matrices, used by the scene later
            viewProjFromLightAlignedBB(ref resultLightBB, ref lightTransform, ref lightY,
                                       out m_shadowViewMatrix, out m_shadowProjMatrix);

            // Now extend Z of the result AABB to cover shadow-casters closer to the light inside the
            // original box
            foreach (var obj in objects)
            {
                if (obj.renderState.toBeDeleted || obj.localBoundingSphereRadius <= 0f ||
                    !obj.renderState.visible || !obj.renderState.castsShadow)
                {
                    continue;
                }
                Vector3 lightAlignedPos = Vector3.Transform(obj.worldBoundingSphereCenter, lightTransform);
                Vector3 rad             = new Vector3(obj.worldBoundingSphereRadius);
                Vector3 localMin        = lightAlignedPos - rad;
                if (localMin.Z < resultLightBB.Min.Z)
                {
                    Vector3 localMax = lightAlignedPos + rad;
                    if (OpenTKHelper.RectsOverlap(resultLightBB.Min.Xy,
                                                  resultLightBB.Max.Xy,
                                                  localMin.Xy,
                                                  localMax.Xy))
                    {
                        resultLightBB.Min.Z = localMin.Z;
                    }
                }
            }

            // Generate frustum culler from the BB extended towards light to include shadow casters
            Matrix4 frustumView, frustumProj;
            viewProjFromLightAlignedBB(ref resultLightBB, ref lightTransform, ref lightY,
                                       out frustumView, out frustumProj);
            Matrix4 frustumMatrix = frustumView * frustumProj;
            FrustumCuller = new FrustumCuller(ref frustumMatrix);
        }