Рисование большого количества одинаковых моделей с использованием буферов вершин?

Я сталкиваюсь с проблемой, что многие разработчики, вероятно, нашли решение. У меня есть небольшой проект с полом с маленькими кубиками (100X100). Если я превышаю этот лимит, моя игра сильно пострадала, и Lague!

Вот как я рисую свой пол:

//Function to draw my ground ( 100 X 100 X 1)
    public void DrawGround(GameTime gameTime)
    {
        // Copy any parent transforms.
        Matrix[] transforms = new Matrix[this.model.Bones.Count];
        this.model.CopyAbsoluteBoneTransformsTo(transforms);

        //loop 1 cube high
        for (int a = 0; a < 1; a++)
        {
            //loop 100 along cube
            for (int b = 0; b < 100; b++)
            {
                //loop 100 cubic wide
                for (int c = 0; c < 100; c++)
                {
                    // Draw the model. A model can have multiple meshes, so loop.
                    foreach (ModelMesh mesh in this.model.Meshes)
                    {
                        // This is where the mesh orientation is set, as well 
                        // as our camera and projection.
                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.EnableDefaultLighting();
                            effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateTranslation(this.position);
                            effect.View = this.view;
                            effect.Projection = this.projection;


                        }

                        // Draw the mesh, using the effects set above.
                        mesh.Draw();
                    }
                }
            }
        }
    }

Я думаю, что лучше использовать [VertexBuffer] "память о видеокарте", но я не нашел учебник для этого я хочу сделать...

Можете ли вы дать мне пример использования [VertexBuffer] в моей функции "DrawGround"?введите описание изображения здесьБольшое спасибо!

1 ответ

Решение

ТЛ; др;

Используйте аппаратное инстансинг для рисования кубов. При желании используйте View Frustum Culling, чтобы избежать рисования невидимых экземпляров. Начните работу с вершинными и индексными буферами, прочитав Учебник Римера.


Instancing

Идея состоит в том, что буферы вершин и индексов привязываются к устройству один раз, а затем отрисовываются несколько раз за один вызов отрисовки. Экземпляр - это небольшой пакет данных, который содержит только информацию, уникальную для экземпляра модели. Эти данные экземпляра записываются в дополнительный вершинный буфер и связываются с устройством вместе с буферами, содержащими фактические вершины и индексы.

Как вы можете воспользоваться этим?

В вашем случае у вас будет следующая настройка:

  • IndexBuffer, содержащий индексы сетки куба
  • VertexBuffer, содержащий вершины сетки куба
  • второй VertexBuffer, содержащий преобразование всех кубов, которые вы хотите нарисовать
  • специальный макет ввода, который учитывает данные экземпляра

Поскольку ваши кубы различаются только по положению, вам даже не нужно отправлять полные матрицы преобразования в шейдер. Просто отправьте позицию экземпляра и добавьте ее в позицию вершины. Вы также можете отправить другие данные, как цвет для каждого экземпляра.

Как вы это реализуете?

Быстрый поиск в Google дал мне массу результатов для xna instancing, так что вам стоит начать. Вот два случайных результата, которые кажутся многообещающими:


Отбор Frustum

В любое время может быть видна только часть сетки в сцене. Объект может быть закрыт другим объектом или находится полностью вне поля зрения игрока. Процесс удаления этих невидимых сеток перед их рисованием называется отбраковкой. Просмотр Frustum Culling адресует второй случай:

Все тома, которые не пересекаются с громкостью камеры, невидимы.

Каков объем камеры? Ортографическая проекция имеет ограничивающий объем в форме коробки. С перспективной проекцией эта коробка имеет коническую форму, пирамиду, которая обрезается в ближней и дальней плоскостях; отсюда вид усеченного.

Как вы можете воспользоваться этим?

Используйте усеченный конус, чтобы идентифицировать экземпляры, невидимые в текущем кадре. Нарисуйте только те кубы, которые пересекаются с усечением вашей камеры. Ваша нагрузка рендеринга может быть уменьшена до 100%, когда игрок смотрит в небо.;-)

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

Как вы это реализуете?

Xna предоставляет структуру BoundingBox, а также класс BoundingFrustum. Все, что вам нужно сделать, это использовать их.


Крошечный маленький недостаток

Объединение View Frustum Culling и Hardware Instancing может быть сложным. Удаление экземпляров означает, что вам также придется удалить их из экземпляра buffer =>, что означает воссоздание всего этого. Возможно, рассмотрите возможность вычисления видимости куба и обновления буфера экземпляра только каждые несколько кадров или когда камера перемещается быстро. Как и в какой степени вы, наконец, реализуете эти методы, зависит от вас и зависит от ваших требований.


Я только что понял, что вы хотите знать, как работают буферы вершин:

Vertex Buffers

Прежде чем треугольник можно будет нарисовать на экране, графическое устройство должно быть подготовлено. Это включает в себя связывание шейдеров, сэмплеров, текстур и, конечно, связывание ваших данных геометрии. Когда вызывается отрисовка, графическое устройство запускает шейдеры и записывает вывод в цель рендеринга.

В настоящее время вы используете встроенные абстракции XNA, которые упрощают процесс (и берут на себя весь контроль). Связывание шейдеров, констант, входного макета и т. Д. В настоящее время все скрыто в вашем классе Effect, а класс Mesh заботится о геометрической стороне вещей.

Что делает mesh.Draw()?

При создании сетки создаются два буфера, VertexBuffer и IndexBuffer. Создание этих буферов стоит дорого, поэтому хорошо, что это делается только один раз. Когда вы вызываете метод draw, буферы привязываются к устройству, а затем выполняется вызов draw. Сначала необходимо установить состояния эффекта, как вы правильно прокомментировали в своем коде.

Но вы также можете создавать свои собственные буферы вершин и индексов:

// Instantiate the VertexBuffer
var vertexBuffer = new VertexBuffer(
    device, 
    VertexPositionColorNormal.VertexDeclaration, 
    vertices.Length, 
    BufferUsage.WriteOnly
);

// Write data to the buffer
vertexBuffer.SetData(vertices);

// Instantiate the IndexBuffer
var indexBuffer = new IndexBuffer(
    device, 
    typeof(int), 
    indices.Length,      
    BufferUsage.WriteOnly
);

// Write data to the buffer
indexBuffer.SetData(indices);

... и привязать их вручную к устройству:

device.Indices = myIndexBuffer;
device.SetVertexBuffer(myVertexBuffer);

Этот код был взят непосредственно из учебников по XNA Римера:

Посмотрите сайт, он мне очень помог, когда я впервые начал программировать графику.

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