public unsafe void Draw() { if (game.Config.MSAASamples > 0) { if (_mwidth != Game.Width || _mheight != Game.Height) { _mwidth = Game.Width; _mheight = Game.Height; if (msaa != null) { msaa.Dispose(); } msaa = new MultisampleTarget(Game.Width, Game.Height, Game.Config.MSAASamples); } msaa.Bind(); } NebulaRenderer nr = CheckNebulae(); //are we in a nebula? bool transitioned = false; if (nr != null) { transitioned = nr.FogTransitioned(); } rstate.DepthEnabled = true; //Add Nebula light if (GLExtensions.Features430 && ExtraLights) { //TODO: Re-add [LightSource] to the compute shader, it shouldn't regress. PointLight p2; if (nr != null && nr.DoLightning(out p2)) { pointLights.Add(p2); } } //Async calcs for (int i = 0; i < Objects.Count; i += 16) { JThreads.Instance.AddTask((o) => { var offset = (int)o; for (int j = 0; j < 16 && ((j + offset) < Objects.Count); j++) { Objects[j + offset].PrepareRender(camera, nr); } }, i); } JThreads.Instance.BeginExecute(); if (transitioned) { //Fully in fog. Skip Starsphere rstate.ClearColor = nr.Nebula.FogColor; rstate.ClearAll(); } else { rstate.DepthEnabled = false; if (starSystem == null) { rstate.ClearColor = NullColor; } else { rstate.ClearColor = starSystem.BackgroundColor; } rstate.ClearAll(); //Starsphere for (int i = 0; i < StarSphereModels.Length; i++) { Matrix4 ssworld = Matrix4.CreateTranslation(camera.Position); if (StarSphereWorlds != null) { ssworld = StarSphereWorlds[i] * ssworld; } StarSphereModels[i].Draw(rstate, ssworld, Lighting.Empty); } //Render fog transition: if any if (nr != null) { rstate.DepthEnabled = false; nr.RenderFogTransition(); rstate.DepthEnabled = true; } } DebugRenderer.StartFrame(camera, rstate); Polyline.SetCamera(camera); commands.StartFrame(); rstate.DepthEnabled = true; //Optimisation for dictionary lookups LightEquipRenderer.FrameStart(); //Clear depth buffer for game objects rstate.ClearDepth(); game.Billboards.Begin(camera, commands); JThreads.Instance.FinishExecute(); //Make sure visibility calculations are complete if (GLExtensions.Features430 && ExtraLights) { //Forward+ heck yeah! //ISSUES: Z prepass here doesn't work - gives blank texture (investigate DepthMap.cs) //(WORKED AROUND) Lights being culled too aggressively - Pittsburgh planet light, intro_planet_chunks //Z test - cull transparent and opaque differently (opaqueLightBuffer enable) //Optimisation work needs to be done //When these are fixed this can be enabled by default //Copy lights into buffer int plc = pointLights.Count; using (var h = pointLightBuffer.Map()) { var ptr = (PointLight *)h.Handle; for (int i = 0; i < pointLights.Count; i++) { ptr[i] = pointLights[i]; } //Does the rest of the buffer need to be cleared? } pointLights.Clear(); //Setup Visible Buffers var tilesW = (Game.Width + (Game.Width % 16)) / 16; var tilesH = (Game.Height + (Game.Height % 16)) / 16; SystemLighting.NumberOfTilesX = tilesW; if (_twidth != tilesW || _theight != tilesH) { _twidth = tilesW; _theight = tilesH; //if (opaqueLightBuffer != null) opaqueLightBuffer.Dispose(); if (transparentLightBuffer != null) { transparentLightBuffer.Dispose(); } //opaqueLightBuffer = new ShaderStorageBuffer((tilesW * tilesH) * 512 * sizeof(int)); transparentLightBuffer = new ShaderStorageBuffer((tilesW * tilesH) * 512 * sizeof(int)); } //Depth if (_dwidth != Game.Width || _dheight != Game.Height) { _dwidth = Game.Width; _dheight = Game.Height; if (depthMap != null) { depthMap.Dispose(); } depthMap = new DepthMap(Game.Width, game.Height); } depthMap.BindFramebuffer(); rstate.ClearDepth(); rstate.DepthFunction = DepthFunction.Less; for (int i = 0; i < Objects.Count; i++) { if (Objects[i].Visible) { Objects[i].DepthPrepass(camera, rstate); } } rstate.DepthFunction = DepthFunction.LessEqual; RenderTarget2D.ClearBinding(); if (game.Config.MSAASamples > 0) { msaa.Bind(); } //Run compute shader pointLightBuffer.BindIndex(0); transparentLightBuffer.BindIndex(1); //opaqueLightBuffer.BindIndex(2); pointLightCull.Uniform1i("depthTexture", 7); depthMap.BindTo(7); pointLightCull.Uniform1i("numLights", plc); pointLightCull.Uniform1i("windowWidth", Game.Width); pointLightCull.Uniform1i("windowHeight", Game.Height); var v = camera.View; var p = camera.Projection; p.Invert(); pointLightCull.UniformMatrix4fv("viewMatrix", ref v); pointLightCull.UniformMatrix4fv("invProjection", ref p); GL.MemoryBarrier(GL.GL_SHADER_STORAGE_BARRIER_BIT); //I don't think these need to be here - confirm then remove? pointLightCull.Dispatch((uint)tilesW, (uint)tilesH, 1); GL.MemoryBarrier(GL.GL_SHADER_STORAGE_BARRIER_BIT); } else { SystemLighting.NumberOfTilesX = -1; //Simple depth pre-pass rstate.DepthFunction = DepthFunction.Less; for (int i = 0; i < Objects.Count; i++) { if (Objects[i].Visible) { Objects[i].DepthPrepass(camera, rstate); } } rstate.DepthFunction = DepthFunction.LessEqual; } //Actual Drawing for (int i = 0; i < Objects.Count; i++) { if (Objects[i].Visible) { Objects[i].Draw(camera, commands, SystemLighting, nr); } } for (int i = 0; i < AsteroidFields.Count; i++) { AsteroidFields[i].Draw(cache, SystemLighting, commands, nr); } game.Nebulae.NewFrame(); if (nr == null) { for (int i = 0; i < Nebulae.Count; i++) { Nebulae[i].Draw(commands); } } else { nr.Draw(commands); } game.Nebulae.SetData(); game.Billboards.End(); Polyline.FrameEnd(); //Opaque Pass rstate.DepthEnabled = true; commands.DrawOpaque(rstate); //Transparent Pass rstate.DepthWrite = false; commands.DrawTransparent(rstate); rstate.DepthWrite = true; DebugRenderer.Render(); if (Game.Config.MSAASamples > 0) { msaa.BlitToScreen(); } rstate.DepthEnabled = true; }
public unsafe void Draw() { if (gconfig.MSAASamples > 0) { if (_mwidth != Game.Width || _mheight != Game.Height) { _mwidth = Game.Width; _mheight = Game.Height; if (msaa != null) { msaa.Dispose(); } msaa = new MultisampleTarget(Game.Width, Game.Height, gconfig.MSAASamples); } rstate.RenderTarget = msaa; } NebulaRenderer nr = CheckNebulae(); //are we in a nebula? bool transitioned = false; if (nr != null) { transitioned = nr.FogTransitioned(); } rstate.DepthEnabled = true; //Add Nebula light if (GLExtensions.Features430 && ExtraLights) { //TODO: Re-add [LightSource] to the compute shader, it shouldn't regress. PointLight p2; if (nr != null && nr.DoLightning(out p2)) { pointLights.Add(p2); } } //Async calcs objects = new List <ObjectRenderer>(250); /*for (int i = 0; i < World.Objects.Count; i += 16) * { * JThreads.Instance.AddTask((o) => * { * var offset = (int)o; * for (int j = 0; j < 16 && ((j + offset) < World.Objects.Count); j++) World.Objects[j + offset].PrepareRender(camera, nr, this); * }, i); * } * JThreads.Instance.BeginExecute();*/ for (int i = 0; i < World.Objects.Count; i++) { World.Objects[i].PrepareRender(camera, nr, this); } if (transitioned) { //Fully in fog. Skip Starsphere rstate.ClearColor = nr.Nebula.FogColor; rstate.ClearAll(); } else { rstate.DepthEnabled = false; if (starSystem == null) { rstate.ClearColor = NullColor; } else { rstate.ClearColor = starSystem.BackgroundColor; } rstate.ClearAll(); //Starsphere if (camera is ThnCamera thn) { thn.DefaultZ(); } for (int i = 0; i < StarSphereModels.Length; i++) { Matrix4x4 ssworld = Matrix4x4.CreateTranslation(camera.Position); if (StarSphereWorlds != null) { ssworld = StarSphereWorlds[i] * ssworld; } var lighting = Lighting.Empty; if (StarSphereLightings != null) { lighting = StarSphereLightings[i]; } StarSphereModels[i].DrawImmediate(rstate, resman, ssworld, ref lighting); } if (camera is ThnCamera thn2) { thn2.CameraZ(); } //Render fog transition: if any if (nr != null) { rstate.DepthEnabled = false; nr.RenderFogTransition(); rstate.DepthEnabled = true; } } DebugRenderer.StartFrame(camera, rstate); Polyline.SetCamera(camera); commands.StartFrame(rstate); rstate.DepthEnabled = true; //Optimisation for dictionary lookups LightEquipRenderer.FrameStart(); //Clear depth buffer for game objects rstate.ClearDepth(); billboards.Begin(camera, commands); //JThreads.Instance.FinishExecute(); //Make sure visibility calculations are complete if (GLExtensions.Features430 && ExtraLights) { //Forward+ heck yeah! //(WORKED AROUND) Lights being culled too aggressively - Pittsburgh planet light, intro_planet_chunks //Z test doesn't seem to be working (commented out in shader) //May need optimisation int plc = pointLights.Count; using (var h = pointLightBuffer.Map()) { var ptr = (PointLight *)h.Handle; for (int i = 0; i < pointLights.Count; i++) { ptr[i] = pointLights[i]; } } pointLights.Clear(); //Setup Visible Buffers var tilesW = (Game.Width + (Game.Width % 16)) / 16; var tilesH = (Game.Height + (Game.Height % 16)) / 16; SystemLighting.NumberOfTilesX = tilesW; if (_twidth != tilesW || _theight != tilesH) { _twidth = tilesW; _theight = tilesH; //if (opaqueLightBuffer != null) opaqueLightBuffer.Dispose(); if (transparentLightBuffer != null) { transparentLightBuffer.Dispose(); } //opaqueLightBuffer = new ShaderStorageBuffer((tilesW * tilesH) * 512 * sizeof(int)); transparentLightBuffer = new ShaderStorageBuffer((tilesW * tilesH) * 512 * sizeof(int)); } //Depth if (_dwidth != Game.Width || _dheight != Game.Height) { _dwidth = Game.Width; _dheight = Game.Height; if (depthMap != null) { depthMap.Dispose(); } depthMap = new DepthMap(Game.Width, game.Height); } depthMap.BindFramebuffer(); rstate.ClearDepth(); rstate.DepthFunction = DepthFunction.Less; foreach (var obj in objects) { obj.DepthPrepass(camera, rstate); } rstate.DepthFunction = DepthFunction.LessEqual; rstate.RenderTarget = null; if (gconfig.MSAASamples > 0) { rstate.RenderTarget = msaa; } //Run compute shader pointLightBuffer.BindIndex(0); transparentLightBuffer.BindIndex(1); //opaqueLightBuffer.BindIndex(2); pointLightCull.Uniform1i("depthTexture", 7); depthMap.BindTo(7); pointLightCull.Uniform1i("numLights", plc); pointLightCull.Uniform1i("windowWidth", Game.Width); pointLightCull.Uniform1i("windowHeight", Game.Height); var v = camera.View; var p = camera.Projection; Matrix4x4.Invert(p, out p); pointLightCull.UniformMatrix4fv("viewMatrix", ref v); pointLightCull.UniformMatrix4fv("invProjection", ref p); GL.MemoryBarrier(GL.GL_SHADER_STORAGE_BARRIER_BIT); //I don't think these need to be here - confirm then remove? pointLightCull.Dispatch((uint)tilesW, (uint)tilesH, 1); GL.MemoryBarrier(GL.GL_SHADER_STORAGE_BARRIER_BIT); } else { SystemLighting.NumberOfTilesX = -1; //Simple depth pre-pass rstate.ColorWrite = false; rstate.DepthFunction = DepthFunction.Less; foreach (var obj in objects) { obj.DepthPrepass(camera, rstate); } rstate.DepthFunction = DepthFunction.LessEqual; rstate.ColorWrite = true; } //Actual Drawing Beams.Begin(commands, resman, camera); foreach (var obj in objects) { obj.Draw(camera, commands, SystemLighting, nr); } Beams.End(); FxPool.Draw(camera, Polyline, resman, DebugRenderer); for (int i = 0; i < AsteroidFields.Count; i++) { AsteroidFields[i].Draw(cache, SystemLighting, commands, nr); } nebulae.NewFrame(); if (nr == null) { for (int i = 0; i < Nebulae.Count; i++) { Nebulae[i].Draw(commands); } } else { nr.Draw(commands); } nebulae.SetData(); billboards.End(); Polyline.FrameEnd(); //Opaque Pass rstate.DepthEnabled = true; commands.DrawOpaque(rstate); //Transparent Pass rstate.DepthWrite = false; commands.DrawTransparent(rstate); rstate.DepthWrite = true; PhysicsHook?.Invoke(); foreach (var point in debugPoints) { var lX = point + new Vector3(5, 0, 0); var lmX = point + new Vector3(-5, 0, 0); var lY = point + new Vector3(0, -5, 0); var lmY = point + new Vector3(0, 5, 0); var lZ = point + new Vector3(0, 0, 5); var lmZ = point + new Vector3(0, 0, -5); DebugRenderer.DrawLine(lX, lmX); DebugRenderer.DrawLine(lY, lmY); DebugRenderer.DrawLine(lZ, lmZ); } debugPoints = new Vector3[0]; DebugRenderer.Render(); if (gconfig.MSAASamples > 0) { msaa.BlitToScreen(); rstate.RenderTarget = null; } rstate.DepthEnabled = true; }