Как нарисовать только видимые данные XNA Мой метод не работает

У меня есть 10*10 кубов плоскости. Я хочу рисовать только видимые кубы, поэтому я использую Bounding frustum. Проблема заключается в том, что когда первый куб из сетки (в позиции 0,0) выходит из усеченного конуса, все кубы исчезают.

Вот мой код в 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() метод в 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));
                    }
                }
            }

Я также хотел бы, если вы можете дать мне ссылку на учебник / образец текстурирования атласа, спасибо!

1 ответ

Ваш метод cube.IsVisible(...) не учитывает последнее преобразование, которое вы применяете при рисовании куба, т.е. вы всегда проверяете исходный куб, а не преобразованный.

Пожалуйста, обратитесь к этому ответу, так как он касается как вашей проблемы выбраковки (frustum-box), так и инстанциирования.

Другие вопросы по тегам