Optimization of drawing 3d models by creating a single grid

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 ...

//draw the main level in a regular way
foreach (LevelObject part in levelData.LevelParts)
{
    partBounds.Center = part.position;
    if (viewFrustum.Intersects(partBounds))
    {
        //Rotate X
        Matrix worldMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(part.Xrotate));
        //Rotate Z
        worldMatrix *= Matrix.CreateRotationZ(MathHelper.ToRadians(part.Zrotate));
        //Rotate Y
        worldMatrix *= Matrix.CreateRotationY(MathHelper.ToRadians(part.Yrotate));

        worldMatrix *= Matrix.CreateWorld(part.position, Vector3.Forward, Vector3.Up);
        Model Object = levelModels[part.modelName];

        //set in the gamers viewport
        foreach (ModelMesh mesh in Object.Meshes)
        {
            foreach (BasicEffect effect in mesh.Effects)
            {
                //effect.EnableDefaultLighting();
                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)
{
    /* NORMAL VIEW */

    //set viewport for everyone
    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;

        //view frustrum object for culling
        BoundingFrustum viewFrustum = new BoundingFrustum(viewMatrix * projectionMatrix);
        BoundingSphere partBounds = new BoundingSphere();
        partBounds.Radius = levelData.scale;

        //draw the main level in a regular way
        foreach (LevelObject part in levelData.LevelParts)
        {
            partBounds.Center = part.position;
            if (viewFrustum.Intersects(partBounds))
            {
                //Rotate X
                Matrix worldMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(part.Xrotate));
                //Rotate Z
                worldMatrix *= Matrix.CreateRotationZ(MathHelper.ToRadians(part.Zrotate));
                //Rotate Y
                worldMatrix *= Matrix.CreateRotationY(MathHelper.ToRadians(part.Yrotate));

                worldMatrix *= Matrix.CreateWorld(part.position, Vector3.Forward, Vector3.Up);
                Model Object = levelModels[part.modelName];

                //set in the gamers viewport
                foreach (ModelMesh mesh in Object.Meshes)
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        //effect.EnableDefaultLighting();
                        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();
                    }
                }
            }
        }

        /* PING VIEW */

        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)
        {

            //apply ping lighting stuffs here
            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))
            {
                //Rotate X
                Matrix worldMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(part.Xrotate));
                //Rotate Z
                worldMatrix *= Matrix.CreateRotationZ(MathHelper.ToRadians(part.Zrotate));
                //Rotate Y
                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)
                {
                    //ok, this is going to be kind of weird, and there got to be a cleaner
                    //or better way to do this.
                    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);

                        //Matrix worldInverseTransposeMatrix = Matrix.Transpose(Matrix.Invert(mesh.ParentBone.Transform * world));
                        //pingTest.Parameters["WorldInverseTranspose"].SetValue(worldInverseTransposeMatrix);
                    }

                    mesh.Draw();

                    //reset the basic effect crap
                    foreach (ModelMeshPart meshpart in mesh.MeshParts)
                    {
                        meshpart.Effect = backup.First();
                        backup.RemoveAt(0);
                    }
                    //
                }
            }
        }

        //Undo the weird things this shader does
        GraphicsDevice.BlendState = BlendState.Opaque;
        GraphicsDevice.DepthStencilState = DepthStencilState.Default;

        /* MINIMAP VIEW */
        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;

        //view frustum for the map
        BoundingFrustum mapFrustum = new BoundingFrustum(viewMatrix * projectionMatrix);

        //draw the main level in a regular way
        foreach (LevelObject part in levelData.LevelParts)
        {
            partBounds.Center = part.position;
            if (mapFrustum.Intersects(partBounds))
            {
                //Rotate X
                Matrix worldMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(part.Xrotate));
                //Rotate Z
                worldMatrix *= Matrix.CreateRotationZ(MathHelper.ToRadians(part.Zrotate));
                //Rotate Y
                worldMatrix *= Matrix.CreateRotationY(MathHelper.ToRadians(part.Yrotate));

                worldMatrix *= Matrix.CreateWorld(part.position, Vector3.Forward, Vector3.Up);
                Model Object = levelModels[part.modelName];

                //set in the gamers viewport
                foreach (ModelMesh mesh in Object.Meshes)
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        //effect.EnableDefaultLighting();
                        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.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.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)
        {
            //apply ping lighting stuffs here
            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))
                {
                    //Rotate X
                    Matrix worldMatrix = Matrix.CreateRotationX(MathHelper.ToRadians(part.Xrotate));
                    //Rotate Z
                    worldMatrix *= Matrix.CreateRotationZ(MathHelper.ToRadians(part.Zrotate));
                    //Rotate Y
                    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)
                    {
                        //ok, this is going to be kind of weird, and there got to be a cleaner
                        //or better way to do this.
                        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);

                            //Matrix worldInverseTransposeMatrix = Matrix.Transpose(Matrix.Invert(mesh.ParentBone.Transform * world));
                            //pingTest.Parameters["WorldInverseTranspose"].SetValue(worldInverseTransposeMatrix);



                        }

                        mesh.Draw();

                        //reset the basic effect crap
                        foreach (ModelMeshPart meshpart in mesh.MeshParts)
                        {
                            meshpart.Effect = backup.First();
                            backup.RemoveAt(0);
                        }
                        //*/
                    }
                }
            }

        //}
        //Undo the weird things this shader does
        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?

+3
3

, . # , , .

:

effect.AmbientLightColor = new Vector3(0.09f, 0.15f, 0.215f);

. Vector3 . 2. , foreach! effect.AmbientLightColor? , . .

- , :

effect.AmbientLightColor.X = 0.09f;
effect.AmbientLightColor.Y = 0.15f;
effect.AmbientLightColor.Z = 0.215f;

, , .

. , , , .

+2

@Heandel. :

? , 3 . , 7 12 , (, ), .

Model Object = levelModels[part.modelName];: - ? ?

3 MathHelper.ToRadians . ?

+1

One thing that exceeds 1/2 the frame rate mesh.Draw(); is in the wrong cycle, you have

mesh.Draw();
}
}

he should be

}
mesh.Draw();
}
+1
source

All Articles