Цель любого алгоритма удаления скрытых поверхностей состоит в том, чтобы время, затраченное на удаление невидимых частей окружения, было как можно меньше времени, необходимого на то, чтобы эти части сцены нарисовать. Возьмем, к примеру, простейшую 3D-сцену.
gfx-05.jpg
Простейшая 3D-сцена со стороны и с точки зрения камеры.
gfx-06.jpg
Белый конус камере не виден, так что и рисовать его не надо.
Легче всего отбросить те объекты, которые находятся позади камеры или по бокам, а также выше и ниже поля ее зрения: умножение на матрицу, несколько сравнений – и готово. Но если объектов много (тысячи, десятки тысяч), то это уже может быть проблемой, потому что потребует больших затрат процессорного времени. Чтобы отбрасывать объекты, части ландшафта или архитектуры уровня максимально эффективно, их объединяют в иерархии – так, что если при проверке отбрасывается верхний узел иерархии, то подчиненные ему узлы и объекты отбрасываются тоже. По этому общему принципу работают знаменитые благодаря хитам id Software BSP-деревья, восьмеричные деревья (octrees), порталы и их многочисленные вариации и комбинации.
gfx-07.jpg
Появление стены сильно усложняет задачу: цилиндр, куб и шар по-прежнему перед камерой, но рисовать их теперь не нужно.
Но отбросить то, что не попадает в поле зрения камеры, – это самая легкая задача. Гораздо труднее выявить объекты, которые будут заслонены другими объектами. Классический пример – камера смотрит в стену, за которой что-то есть. Если мы нарисуем и стену и объект за ней, то благодаря Z-буферу, в котором хранятся дальности всех пикселей изображения, картинка будет правильной, независимо от того, что мы вывели на экран сначала – объект или стену перед ним. Но при этом будет затрачено много лишнего времени на рендеринг объекта, которого на самом деле не видно.
Самый простой выход – отсортировать объекты по дальности и сначала выводить те, что ближе всех. Тогда при попытке нарисовать фрагмент, который на самом деле не виден, умный GPU (а они сейчас все умные) сверится с Z-буфером и отбросит его, сэкономив время шейдерных модулей и растеризаторов. Можно сначала нарисовать сцену только в Z-буфер – это гораздо быстрее, чем рендерить ее в цвете и дает возможность определить, какие объекты не видны совсем, чтобы при рабочем проходе их и не рисовать. Есть и другие методики, основанные на взаимодействии CPU и GPU, но основная тенденция состоит в том, что видеокарты стали значительно больше помогать в удалении скрытых поверхностей и большую часть самой тяжелой работы (например, отбрасывание полигонов на обратной стороне видимых объектов, которое процессору просто бессмысленно поручать) берут на себя, поэтому HSR из основной проблемы превратилось во второстепенную.
Однако и здесь DirectX 10 может быть полезен: с его помощью можно реализовать методику под названием predicated rendering, когда перед рендерингом сложного объекта сначала проверяется будет ли видима окружающая его «коробка» (bounding box) или ее полностью заслоняют лежащие ближе детали архитектуры. Predicated rendering можно было использовать и под DX9, но в DX10 такая методика практически не требует участия центрального процессора, а значит, на порядок более проста и эффективна.
gfx-08.jpg
Пример predicated rendering: сложный объект рисуется только после проверки видимости bounding box
gfx-09.jpg
Если выяснится, что «коробок» заслонен, какой смысл тратить время на отрисовку объекта?