Вам не нужно сохранять структуру памяти, строго упорядоченную Z. Вместо этого вам нужно хранить свои объекты в структуре пространственного разбиения, ориентированной вдоль поверхности просмотра.
Типичная структура разбиения, представляет собой квадрат , в 2D. Вы можете использовать двоичное дерево , вы можете использовать сетку , или вы можете использовать пространственную схему хеширования . Вы можете даже смешивать эти методы и объединять их друг с другом.
Нет «лучшего», но вы можете добавить в баланс легкость написания и поддержания кода. И память у вас есть.
Давайте рассмотрим сетку, она будет самой простой в реализации, быстрее всего доступной и простой для прохождения. (перемещение - это факт перехода к ячейкам окрестности)
Представьте, что вы позволяете себе использовать 20 МБ ОЗУ для скелета сетки, учитывая, что содержимое ячейки - это всего лишь небольшой объект (например, std :: vector или aC# List), скажем, 50 байт. для 10k пикселей квадратуры вы затем:
sqrt(20*1024*1024/50) = 647
Вы получаете 647 клеток для одного измерения, поэтому 10k/647 = 15 пикселей в ширину ячеек.
Все еще очень маленький, поэтому я полагаю, что это абсолютно приемлемо. Вы можете настроить номера, чтобы получить ячейки размером 512 пикселей. Он должен хорошо подходить, когда несколько ячеек подходят к окну просмотра.
Тогда тривиально легко определить, какие ячейки активированы в окне просмотра, деля верхний левый угол на размер ячейки и полы, которые приводят к результату, это дает вам индекс непосредственно в ячейке. (при условии, что пространство вашего пространства просмотра и пространство сетки начинаются с 0,0 и то же.в противном случае вам необходимо смещать)
Наконец, возьмите нижний правый угол, определите координату сетки для ячейки; и вы можете сделать двойной цикл (x и y) между min и max для итерации по активированным ячейкам.
При обработке ячейки вы можете нарисовать объекты, которые она содержит, пройдя список объектов, которые вы ранее уложили.
Опасайтесь предметов, которые охватывают более 2 ячеек или более. Вам нужно сделать выбор, либо сохранить их один раз и только, но тогда ваши поисковые алгоритмы всегда будут знать размер самого большого элемента в регионе, а также искать списки соседних ячеек (по мере необходимости обязательно покройте хотя бы размер этого самого большого элемента).
Или вы можете сохранить его несколько раз (мой предпочтительный путь) и просто убедиться, что когда вы повторяете ячейки, вы обрабатываете объекты один раз только для каждого кадра. Это очень легко достигается с помощью идентификатора кадра в структуре объекта (в качестве изменяемого элемента).
Эта же логика применяется для более гибкого парирования, такого как бинарные деревья.
У меня есть реализация для обоих имеющихся в моем двигателе, проверьте код, оно может помочь вам получить через детали: http://sourceforge.net/projects/carnage-engine/
Заключительные слова о вашей Z Заказ, если у вас несколько хранения памяти для каждого Z, то вы уже сделали пространственное разбиение, просто не вдоль хорошей оси.
Это можно назвать расслоением.
Что вы можете сделать, как оптимизация, это вместо того, чтобы хранить списки объектов в ваших клетках, вы можете хранить (заказать) map
сек объектов и их ключи их Z, поэтому итерация будет упорядочен по Z.
Но это заставляет вас объединить порядок Z для каждого объекта в видимых ведрах каждого кадра, верно? В противном случае большие объекты, перекрывающие несколько ведер, будут отображаться в неправильном порядке Z. Я думаю, что делать все, что слияние каждого кадра, вероятно, будет слишком накладным. – AshleysBrain
Вы беспокоитесь о слиянии Z-заказов из 4 разных ведер? Это не кажется слишком плохим. Если у вас есть N объектов видимых, вы собираетесь взять O (N) время, чтобы их визуализировать, если вы не ожидаете, что многие из них будут обрезаны вещами впереди. – arghbleargh