We are making a 3D game for the school, which runs on the Xbox 360. We have a huge level consisting of approximately 100 parts, each part consisting of many grids consisting of many vertices. We have a custom shader that will give a ping-like effect wherever you are at the level, shading the level around you. We also have a 3D mini-map, since the game is in space, and you can navigate in any direction. Therefore, when we draw a level, we must draw it 4 times per frame, one for drawing in the main view port, one for drawing pings in the main viewing window, one for drawing a level on the minimap, and one for drawing the ping in the mini the map. It runs at 60 frames per second on a fast PC, but only 20 on an xbox. We have already turned off the drawing of shapes behind us that you donβt see,and it helped some, but we still need it to accelerate.
Here is the main drawing only for the level with ping on the main view port ...
foreach (LevelObject part in levelData.LevelParts)
{
partBounds.Center = part.position;
if (viewFrustum.Intersects(partBounds))
{
Matrix worldMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(part.Xrotate));
worldMatrix *= Matrix.CreateRotationZ(MathHelper.ToRadians(part.Zrotate));
worldMatrix *= Matrix.CreateRotationY(MathHelper.ToRadians(part.Yrotate));
worldMatrix *= Matrix.CreateWorld(part.position, Vector3.Forward, Vector3.Up);
Model Object = levelModels[part.modelName];
foreach (ModelMesh mesh in Object.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.LightingEnabled = true;
effect.AmbientLightColor = new Vector3(0.09f, 0.15f, 0.215f);
effect.DirectionalLight0.DiffuseColor = new Vector3(0.3f, 0.3f, 0.3f);
effect.DirectionalLight0.Direction = viewMatrix.Forward;
effect.DirectionalLight0.Enabled = true;
effect.DirectionalLight1.DiffuseColor = new Vector3(0.05f, 0.085f, 0.25f);
effect.DirectionalLight1.Direction = viewMatrix.Down;
effect.DirectionalLight1.Enabled = true;
effect.PreferPerPixelLighting = true;
effect.World = worldMatrix;
effect.View = viewMatrix;
effect.Projection = projectionMatrix;
mesh.Draw();
}
}
}
}
So, if in the blender I made a part of the level with only one grid, it would have to do fewer cycles, I'm not sure if this will make it faster. Any ideas I need to increase drawing performance? This game is divided into screens and can contain up to 4 players, which will increase the level by 4 times.
Here is the full drawing function
public override void Draw(GameTime gameTime)
{
for (int i = 0; i < SignedInGamer.SignedInGamers.Count; i++)
{
GraphicsDevice.Viewport = Camera.gameScreenViewPorts[SignedInGamer.SignedInGamers[i]];
Matrix viewMatrix = Camera.viewMatrix[SignedInGamer.SignedInGamers[i]];
Matrix projectionMatrix = Camera.projectionMatrix[SignedInGamer.SignedInGamers[i]];
GraphicsDevice.RasterizerState = RasterizerState.CullNone;
GraphicsDevice.BlendState = BlendState.Opaque;
BoundingFrustum viewFrustum = new BoundingFrustum(viewMatrix * projectionMatrix);
BoundingSphere partBounds = new BoundingSphere();
partBounds.Radius = levelData.scale;
foreach (LevelObject part in levelData.LevelParts)
{
partBounds.Center = part.position;
if (viewFrustum.Intersects(partBounds))
{
Matrix worldMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(part.Xrotate));
worldMatrix *= Matrix.CreateRotationZ(MathHelper.ToRadians(part.Zrotate));
worldMatrix *= Matrix.CreateRotationY(MathHelper.ToRadians(part.Yrotate));
worldMatrix *= Matrix.CreateWorld(part.position, Vector3.Forward, Vector3.Up);
Model Object = levelModels[part.modelName];
foreach (ModelMesh mesh in Object.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.LightingEnabled = true;
effect.AmbientLightColor = new Vector3(0.09f, 0.15f, 0.215f);
effect.DirectionalLight0.DiffuseColor = new Vector3(0.3f, 0.3f, 0.3f);
effect.DirectionalLight0.Direction = viewMatrix.Forward;
effect.DirectionalLight0.Enabled = true;
effect.DirectionalLight1.DiffuseColor = new Vector3(0.05f, 0.085f, 0.25f);
effect.DirectionalLight1.Direction = viewMatrix.Down;
effect.DirectionalLight1.Enabled = true;
effect.PreferPerPixelLighting = true;
effect.World = worldMatrix;
effect.View = viewMatrix;
effect.Projection = projectionMatrix;
mesh.Draw();
}
}
}
}
List<Vector3> pingPos = new List<Vector3>();
List<Vector4> pingColor = new List<Vector4>();
List<float> pingRange = new List<float>();
for (int a = 0; a < Game.Components.Count; a++)
{
if (Game.Components[a] is Ship)
{
pingPos.Add(((Ship)Game.Components[a]).worldMatrix.Translation);
pingColor.Add(new Vector4(
((Ship)Game.Components[a]).playerColor.R,
((Ship)Game.Components[a]).playerColor.G,
((Ship)Game.Components[a]).playerColor.B,
1));
pingRange.Add(((Ship)Game.Components[a]).pingRange * (levelData.scale * 2.0f));
}
}
if (pingPos.Count() > 0)
{
pingTest.Parameters["PingPos"].SetValue(pingPos.ToArray());
pingTest.Parameters["PingPosCount"].SetValue(pingPos.Count());
pingTest.Parameters["PingColor"].SetValue(pingColor.ToArray());
pingTest.Parameters["PingColorCount"].SetValue(pingColor.Count());
pingTest.Parameters["PingRange"].SetValue(pingRange.ToArray());
pingTest.Parameters["PingRangeCount"].SetValue(pingRange.Count());
}
foreach (LevelObject part in levelData.LevelParts)
{
partBounds.Center = part.position;
if (viewFrustum.Intersects(partBounds))
{
Matrix worldMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(part.Xrotate));
worldMatrix *= Matrix.CreateRotationZ(MathHelper.ToRadians(part.Zrotate));
worldMatrix *= Matrix.CreateRotationY(MathHelper.ToRadians(part.Yrotate));
worldMatrix *= Matrix.CreateWorld(part.position, Vector3.Forward, Vector3.Up);
Model Object = levelModels[part.modelName];
foreach (ModelMesh mesh in Object.Meshes)
{
List<Effect> backup = new List<Effect>();
foreach (ModelMeshPart meshpart in mesh.MeshParts)
{
backup.Add(meshpart.Effect);
meshpart.Effect = pingTest;
meshpart.Effect.Parameters["World"].SetValue(worldMatrix * mesh.ParentBone.Transform);
meshpart.Effect.Parameters["View"].SetValue(viewMatrix);
meshpart.Effect.Parameters["Projection"].SetValue(projectionMatrix);
}
mesh.Draw();
foreach (ModelMeshPart meshpart in mesh.MeshParts)
{
meshpart.Effect = backup.First();
backup.RemoveAt(0);
}
}
}
}
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.Viewport = Camera.mapViewports[SignedInGamer.SignedInGamers[i]];
viewMatrix = Camera.mapViewMatrix[SignedInGamer.SignedInGamers[i]];
projectionMatrix = Camera.mapProjectionMatrix[SignedInGamer.SignedInGamers[i]];
GraphicsDevice.RasterizerState = RasterizerState.CullNone;
GraphicsDevice.BlendState = BlendState.Opaque;
BoundingFrustum mapFrustum = new BoundingFrustum(viewMatrix * projectionMatrix);
foreach (LevelObject part in levelData.LevelParts)
{
partBounds.Center = part.position;
if (mapFrustum.Intersects(partBounds))
{
Matrix worldMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(part.Xrotate));
worldMatrix *= Matrix.CreateRotationZ(MathHelper.ToRadians(part.Zrotate));
worldMatrix *= Matrix.CreateRotationY(MathHelper.ToRadians(part.Yrotate));
worldMatrix *= Matrix.CreateWorld(part.position, Vector3.Forward, Vector3.Up);
Model Object = levelModels[part.modelName];
foreach (ModelMesh mesh in Object.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.LightingEnabled = true;
if (match(part.position / 15.0f))
effect.AmbientLightColor = new Vector3(1.0f, 0.30f, 0.43f);
else
effect.AmbientLightColor = new Vector3(0.18f, 0.30f, 0.43f);
effect.DirectionalLight0.DiffuseColor = new Vector3(0.6f, 0.6f, 0.6f);
effect.DirectionalLight0.Direction = viewMatrix.Forward;
effect.DirectionalLight0.Enabled = true;
effect.DirectionalLight1.DiffuseColor = new Vector3(0.1f, 0.17f, 0.5f);
effect.DirectionalLight1.Direction = viewMatrix.Down;
effect.DirectionalLight1.Enabled = true;
effect.PreferPerPixelLighting = true;
effect.World = worldMatrix;
effect.View = viewMatrix;
effect.Projection = projectionMatrix;
mesh.Draw();
}
}
}
}
base.Draw(gameTime);
return;
if (pingPos.Count() > 0)
{
pingTest.Parameters["PingPos"].SetValue(pingPos.ToArray());
pingTest.Parameters["PingPosCount"].SetValue(pingPos.Count());
pingTest.Parameters["PingColor"].SetValue(pingColor.ToArray());
pingTest.Parameters["PingColorCount"].SetValue(pingColor.Count());
pingTest.Parameters["PingRange"].SetValue(pingRange.ToArray());
pingTest.Parameters["PingRangeCount"].SetValue(pingRange.Count());
}
foreach (LevelObject part in levelData.LevelParts)
{
partBounds.Center = part.position;
if (mapFrustum.Intersects(partBounds))
{
Matrix worldMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(part.Xrotate));
worldMatrix *= Matrix.CreateRotationZ(MathHelper.ToRadians(part.Zrotate));
worldMatrix *= Matrix.CreateRotationY(MathHelper.ToRadians(part.Yrotate));
worldMatrix *= Matrix.CreateWorld(part.position, Vector3.Forward, Vector3.Up);
Model Object = levelModels[part.modelName];
foreach (ModelMesh mesh in Object.Meshes)
{
List<Effect> backup = new List<Effect>();
foreach (ModelMeshPart meshpart in mesh.MeshParts)
{
backup.Add(meshpart.Effect);
meshpart.Effect = pingTest;
meshpart.Effect.Parameters["World"].SetValue(worldMatrix * mesh.ParentBone.Transform);
meshpart.Effect.Parameters["View"].SetValue(viewMatrix);
meshpart.Effect.Parameters["Projection"].SetValue(projectionMatrix);
}
mesh.Draw();
foreach (ModelMeshPart meshpart in mesh.MeshParts)
{
meshpart.Effect = backup.First();
backup.RemoveAt(0);
}
}
}
}
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
base.Draw(gameTime);
}
}
Question about the garbage collector
So, setting vectors of type effect.DirectionalLight0.DiffuseColor using this method ...
effect.DirectionalLight0.DiffuseColor.X = 0.3f;
effect.DirectionalLight0.DiffuseColor.Y = 0.3f;
effect.DirectionalLight0.DiffuseColor.Z = 0.3f;
Instead of this method ....
effect.DirectionalLight0.DiffuseColor = new Vector3(.3, .3, .3);
I allocate less memory for the garbage collector to pick up, but as soon as the draw () function is called, doesn't it add all the garbage to the stack, so the collector can pick it up almost instantly? I understand that he adds a little extra work for the collector, but he should not add so many rights?