How to draw only visible data XNA My method doesn't work

261 views Asked by At

I have a 10*10 plane of cubes. I want only visible cubes to be drawn, so I use a Bounding frustum. The problem is that when the first cube from the grid (at location 0,0) gets out of the frustum, all cubes disappear.

Here is my code in Cube.cs:

public class Cube
    {
        Vector3 scale;
        float textureScale;

        GraphicsDevice device;
        Effect effect;
        VertexBuffer vertexBuffer;
        Texture2D texture;

        public Vector3 GlobalPosition = new Vector3(0, 0, 0);

        public Vector3[] vertices = new Vector3[36];

        public Cube(Vector3 scale, float textureScale, Effect effect, Texture2D texture, GraphicsDevice device)
        {

            this.scale = scale;
            this.textureScale = textureScale;
            this.device = device;
            this.effect = effect;
            this.texture = texture;

            vertices[0] = new Vector3(-1, 1, -1);
            vertices[1] = new Vector3(-1, -1, -1);
            vertices[2] = new Vector3(1, -1, -1);

            vertices[3] = new Vector3(1, -1, -1);
            vertices[4] = new Vector3(1, 1, -1);
            vertices[5] = new Vector3(-1, 1, -1);

            //Front
            vertices[6] = new Vector3(1, -1, 1);
            vertices[7] = new Vector3(-1, -1, 1);
            vertices[8] = new Vector3(-1, 1, 1);

            vertices[9] = new Vector3(-1, 1, 1);
            vertices[10] = new Vector3(1, 1, 1);
            vertices[11] = new Vector3(1, -1, 1);

            //Bottom
            vertices[12] = new Vector3(-1, -1, -1);
            vertices[13] = new Vector3(-1, -1, 1);
            vertices[14] = new Vector3(1, -1, -1);

            vertices[15] = new Vector3(1, -1, 1);
            vertices[16] = new Vector3(1, -1, -1);
            vertices[17] = new Vector3(-1, -1, 1);

            //Top
            vertices[18] = new Vector3(1, 1, -1);
            vertices[19] = new Vector3(-1, 1, 1);
            vertices[20] = new Vector3(-1, 1, -1);

            vertices[21] = new Vector3(-1, 1, 1);
            vertices[22] = new Vector3(1, 1, -1);
            vertices[23] = new Vector3(1, 1, 1);

            //Left
            vertices[24] = new Vector3(-1, -1, 1);
            vertices[25] = new Vector3(-1, -1, -1);
            vertices[26] = new Vector3(-1, 1, -1);

            vertices[27] = new Vector3(-1, 1, -1);
            vertices[28] = new Vector3(-1, 1, 1);
            vertices[29] = new Vector3(-1, -1, 1);

            //Right
            vertices[30] = new Vector3(1, -1, -1);
            vertices[31] = new Vector3(1, -1, 1);
            vertices[32] = new Vector3(1, 1, -1);

            vertices[33] = new Vector3(1, -1, 1);
            vertices[34] = new Vector3(1, 1, 1);
            vertices[35] = new Vector3(1, 1, -1);

            for (int i = 0; i < 36; i++)
            {
                vertices[i] = vertices[i] * scale + GlobalPosition;
            }

            VertexPositionNormalTexture[] verticesList = GetVPNT();
            vertexBuffer = new VertexBuffer(device, VertexPositionNormalTexture.VertexDeclaration, verticesList.Length, BufferUsage.WriteOnly);
            vertexBuffer.SetData<VertexPositionNormalTexture>(verticesList.ToArray());

        }
        public void Draw(Matrix View, Matrix Projection, Vector3 pos)
        {

            effect.CurrentTechnique = effect.Techniques["Textured"];
            effect.Parameters["xWorld"].SetValue(Matrix.Identity * Matrix.CreateTranslation(pos));
            effect.Parameters["xView"].SetValue(View);
            effect.Parameters["xProjection"].SetValue(Projection);
            effect.Parameters["xTexture"].SetValue(texture);

            effect.Parameters["xEnableLighting"].SetValue(true);
            effect.Parameters["xLightDirection"].SetValue(new Vector3(30, 30, 30));
            effect.Parameters["xAmbient"].SetValue(0.5f);

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                device.SetVertexBuffer(vertexBuffer);
                device.DrawPrimitives(PrimitiveType.TriangleList, 0, vertexBuffer.VertexCount / 3);
            }
        }
        public VertexPositionNormalTexture[] GetVPNT()
        {
            VertexPositionNormalTexture[] vpnt = new VertexPositionNormalTexture[36];

            Vector2[] texCoords = CalculateTexCoords(vertices, "tile");

            for (int i = 0; i < 36; i++)
            {

                vpnt[i] = new VertexPositionNormalTexture(vertices[i], new Vector3(0, 0, 1), texCoords[i]);
            }

            return vpnt;
        }
        public Vector2[] CalculateTexCoords(Vector3[] vec, string type)
        {
            List<Vector2> texCoords = new List<Vector2>();

            for (int i = 0; i < 12; i++)
            {
                if (AllEqual<float>(vertices[i * 3 + 0].X, vertices[i * 3 + 1].X, vertices[i * 3 + 2].X))
                {
                    Vector2[] normvec = new Vector2[3];

                    normvec[0] = TexNorm(new Vector2(vertices[i * 3 + 0].Z, vertices[i * 3 + 0].Y), type);
                    normvec[1] = TexNorm(new Vector2(vertices[i * 3 + 1].Z, vertices[i * 3 + 1].Y), type);
                    normvec[2] = TexNorm(new Vector2(vertices[i * 3 + 2].Z, vertices[i * 3 + 2].Y), type);

                    texCoords.AddRange(normvec);
                }
                if (AllEqual<float>(vertices[i * 3 + 0].Y, vertices[i * 3 + 1].Y, vertices[i * 3 + 2].Y))
                {
                    Vector2[] normvec = new Vector2[3];

                    normvec[0] = TexNorm(new Vector2(vertices[i * 3 + 0].X, vertices[i * 3 + 0].Z), type);
                    normvec[1] = TexNorm(new Vector2(vertices[i * 3 + 1].X, vertices[i * 3 + 1].Z), type);
                    normvec[2] = TexNorm(new Vector2(vertices[i * 3 + 2].X, vertices[i * 3 + 2].Z), type);

                    texCoords.AddRange(normvec);
                }
                if (AllEqual<float>(vertices[i * 3 + 0].Z, vertices[i * 3 + 1].Z, vertices[i * 3 + 2].Z))
                {
                    Vector2[] normvec = new Vector2[3];

                    normvec[0] = TexNorm(new Vector2(vertices[i * 3 + 0].X, vertices[i * 3 + 0].Y), type);
                    normvec[1] = TexNorm(new Vector2(vertices[i * 3 + 1].X, vertices[i * 3 + 1].Y), type);
                    normvec[2] = TexNorm(new Vector2(vertices[i * 3 + 2].X, vertices[i * 3 + 2].Y), type);

                    texCoords.AddRange(normvec);
                }
            }
            return texCoords.ToArray();
        }
        public bool AllEqual<T>(params T[] values)
        {
            if (values == null || values.Length == 0)
                return true;
            return values.All(v => v.Equals(values[0]));
        }
        public Vector2 TexNorm(Vector2 vecIn, string type)
        {
            Vector2 vec = new Vector2();

            //Remove negative coordinates
            if (vecIn.Y < 0)
                vec.Y = 0;
            if (vecIn.X < 0)
                vec.X = 0;

            switch (type)
            {
                case "stretch":
                    {
                        if (vecIn.X > 0)
                            vec.X = 1;
                        if (vecIn.Y > 0)
                            vec.Y = 1;

                        break;
                    }
                case "tile":
                    {
                        if (vecIn.X > 0)
                            vec.X = textureScale;
                        if (vecIn.Y > 0)
                            vec.Y = textureScale;

                        break;
                    }
            }
            return vec;
        }
        public bool IsVisible(Matrix VP)
        {
            BoundingFrustum bf = new BoundingFrustum(VP);

            bool isVis = true;

            //Check weather at least one vertices are out of the frustum
            for (int i = 0; i < 36; i++)
            {
                if (bf.Contains(vertices[i]) != ContainmentType.Contains)
                {
                    isVis = false;
                    break;
                }
            }

            return isVis;
        }
    }

Draw() method in Main.cs:

for (int i = 0; i < 10; i++)
            {
                for (int k = 0; k < 10; k++)
                {
                    Cube cube = new Cube(Vector3.One, 1, effect, woodTexture, device);

                    if (cube.IsVisible(View * Projection))
                    {
                        cube.Draw(View, Projection, new Vector3(2 * i, 0, 2 * k));
                    }
                }
            }

I would also like if you can give me link to an atlas texturing tutorial/sample, Thanks!

1

There are 1 answers

0
Alex On

Your cube.IsVisible(...) method does not take into account latter transformation you're applying when you're drawing the cube, i.e you're always checking against your original cube, not the transformed ones.

Please reference this answer as it touches both your culling problem (frustum-box) as well as instancing.