private void RenderBatch(IDeviceContext context, SceneSnapshot scene, RenderJobBatch batch)
        {
            context.SetRasterizerConfiguration(batch.Wireframe ? RasterizerConfiguration.WireFrontBack : RasterizerConfiguration.FillFrontBack);

            if (batch.MaterialResourcesIndexOverride != -1)
            {
                RenderBatch_MaterialPerBatch(context, scene, batch);
            }
            else
            {
                RenderBatch_MaterialPerInstance(context, scene, batch);
            }
        }
 private void RenderBatch_MaterialPerBatch(IDeviceContext context, SceneSnapshot scene, RenderJobBatch batch)
 {
     ref var material = ref scene.Materials.store[batch.MaterialResourcesIndexOverride];
        private void RenderScene_Forward(IDeviceContext context, SceneSnapshot scene, IDepthStencilView backBufferDepthStencilView, IRenderTargetView backBufferRenderTargetView)
        {
            RenderShadowMaps(context, scene);

            // Restore backbuffer rendertarget + scene constant buffer + srvs.
            context.SetRenderTargets(backBufferDepthStencilView, backBufferRenderTargetView);
            context.SetViewportRect(new RectangleF(0, 0, backBufferRenderTargetView.Resolution.Width, backBufferRenderTargetView.Resolution.Height));
            UpdateSceneConstantBuffer(context, new Vector4(scene.CameraEye, 1.0f), scene.ProjView, scene.ProjViewInv, scene.ProjView, scene.ProjViewInv, true, true, scene.SpotlightInfos.Count, scene.Time);

            // Clear render/depth, bind srvs after setrendertargets
            context.ClearRenderTarget(Color.Gray);
            context.ClearDepthBuffer(1.0f);
            BindCommonShaderResourceViews(context);

            // Atmosphere
            if (false)
            {
                _techniques.ForwardSkyFromAtmosphere.BeginPass(context, 0);
                context.SetDepthConfiguration(DepthConfiguration.Disabled);
                var(orthoProj, world) = ComputeSceneQuadProjWorld(backBufferRenderTargetView.Resolution, 0, 0, backBufferRenderTargetView.Resolution.Width, backBufferRenderTargetView.Resolution.Height);
                UpdateSceneConstantBuffer(context, new Vector4(scene.CameraEye, 1), orthoProj, MatrixCM.Invert(orthoProj), scene.ProjView, MatrixCM.Invert(scene.ProjView), false, false, scene.SpotlightInfos.Count, scene.Time);
                UpdateBatchConstantBuffer(context, Matrix.Identity, DiffuseTextureSamplingMode.FlatUV, 0);
                DrawScreenQuad(context, world, null);
                context.SetDepthConfiguration(DepthConfiguration.Enabled);
                {
                    var projViewInv = MatrixCM.Invert(scene.ProjView);
                    projViewInv.Transpose();
                    var a = Vector4.Transform(new Vector4(0, 0, 1, 1), projViewInv);
                    a /= a.W;
                    var av = (Vector3)a;
                    av.Normalize();
                    var b = Vector4.Transform(new Vector4(1, 0, 1, 1), projViewInv);
                    b /= b.W;
                    var bv = (Vector3)b;
                    bv.Normalize();
                    var c = Vector4.Transform(new Vector4(0, 1, 1, 1), projViewInv);
                    c /= c.W;
                    var cv = (Vector3)c;
                    cv.Normalize();
                    Console.WriteLine(av + " " + bv + " " + cv);
                }
            }

            // Water
            if (false)
            {
                var pv = scene.ProjView;
                pv.Transpose();
                Console.WriteLine("!!!!!" + Vector3.Transform(new Vector3(-5.00f, -2.18557e-07f, -5.00f), pv));

                _techniques.ForwardWater.BeginPass(context, 0);
                UpdateSceneConstantBuffer(context, new Vector4(scene.CameraEye, 1), scene.ProjView, scene.ProjViewInv, scene.ProjView, scene.ProjViewInv, false, false, scene.SpotlightInfos.Count, scene.Time);
                UpdateBatchConstantBuffer(context, Matrix.Identity, DiffuseTextureSamplingMode.FlatUV, 0);
                var instancingBuffer = PickInstancingBuffer(8192);
                context.SetVertexBuffer(1, instancingBuffer);
                int n = 40;
                using (var updater = context.TakeUpdater(instancingBuffer)) {
                    for (var y = -n; y <= n; y++)
                    {
                        for (var x = -n; x <= n; x++)
                        {
                            updater.Write(new RenderJobDescription {
                                WorldTransform         = MatrixCM.Scaling(10) * MatrixCM.Translation(x, 0, y) * MatrixCM.RotationX(-(float)Math.PI / 2.0f) * MatrixCM.Translation(-0.5f, -0.5f, 0),
                                MaterialProperties     = { Metallic = 0.0f, Roughness = 1.0f },
                                MaterialResourcesIndex = -1,
                                Color = Color.White,
                            });
                        }
                    }
                }
                context.SetShaderResource(30, _graphicsFacade.Presets.SolidTextures[Color4.White], RenderStage.Pixel);
                var mrbu = context.TakeUpdater(_materialResourcesBuffer);
                mrbu.Write(new InternalMaterialResourcesDescription()
                {
                    BaseColor = Color4.White
                }.Resolve(30));
                mrbu.UpdateCloseAndDispose();
                water.Render(context, (2 * n + 1) * (2 * n + 1));
            }

            // Forward render pass
            for (var pass = 0; pass < _techniques.Forward.Passes; pass++)
            {
                _techniques.Forward.BeginPass(context, pass);
                foreach (var batch in scene.RenderJobBatches)
                {
                    RenderBatch(context, scene, batch);
                }
            }
        }