суббота, 5 ноября 2011 г.

Материалы. Часть первая, идем за светом.

Любой современные графический движок просто обязан иметь систему материалов, так как без этого мир становится серым или даже черным :)

Вопрос материалов достаточно тривиален и тема должна быть скучная, но я постараюсь вас убедить в обратном :)

Для начала определимся что же такое материал - материал это набор "физических" свойств, описывающих поведение падающего на него света, как следствие - материал тесно связан с системой освещения. Так как мы не ставим перед собой задачу трассировки света для физически правильной освещенности, то воспользуемся упрощенными понятиями, принятыми в 3D графике и в OpenGL.


Практический взгляд на цвет
OpenGL дает разработчику более широкие, по отношению к физическому миру, возможности для настройки освещения. Если стоит цель создать как можно более реалистичное изображение, то эти возможности нужно использовать весьма аккуратно.
Попробуем разобраться, что такое "цвет материала" и "цвет источника света". В реальном мире любой источник света имеет спектр, который характеризует, свет в каком диапазоне длин волн излучает этот источник. Точно так же материал по-разному отражает/преломляет/поглощает свет с различной длиной волны. Если освещать зеленый предмет красным светом, то он будет казаться серым. В модели освещения OpenGL все идентично, за той лишь разницей, что можно задавать степень отражения для красной, зеленой и синей компонент составляющих освещенности.
Цитата была взята с первого-попавшегося сайта:
http://compgraphics.info/OpenGL/lighting/materials.php
Там же (как и на сотнях других сайтов) можно прочесть о свойствах материала, свойствах источников света и реализацию этого средствами OpenGL, потому не буду на этом задерживаться. Тем не менее, для продолжения дискуссии, нам нужно знать с чем мы будем работать, потому давайте перечислим основные свойства материала:
  • Ambient - фоновая составляющая цвета объекта, просто добавляется к результирующему цвету;
  • Diffuse - передает цвет света, рассеянного от объекта. На практике - просто цвет объекта;
  • Specular - зеркальный цвет, передает оттенок отраженного цвета, виден на бликах;
  • Emission - задает светимость объекта, так же просто добавляется к результирующему цвету;
  • Shininess - показывает степень отражения света, фактически задает размер пятна блика.
В зависимости от модели освещения некоторые из этих свойств могут быть объединены (ambient+diffuse) или пропущены (specular+shininess), но в общем случае они должны присутствовать все. Аналогичные свойства задаются и для источника света, с той разницей что сам источник света не видим и как следствие он не может "излучать свет" и на нем не может быть бликов. Об источнике света поговорим позже, пока продолжим с материалами.

      
В реальном мире нас повсюду окружают материалы, но как часто вы видите чисто зеленый материал или чисто красный? Обычно на любой поверхности есть какой-то "рисунок", будь то царапина, пыль, цветочек или картинка. Материалы же в OpenGL позволяют задать лишь однородный цвет, ну а для "цветочков" существует понятие текстуры. Что же такое текстура - это какой-то рисунок, который подставляется вместо диффузного цвета материала, ну или по крайней мере это делает OpenGL средствами фиксированной функциональности (FFP - Fixed Function Pipeline), используя современные средства (шейдера) пользователь может аналогичным образом подставить текстуру для определения зеркальных частей объекта или указать таким образом прозрачные участки, но об этом позже.

Как было сказано - текстура может подставляться вместо одного из свойств материала, как в редакторе материалов 3ds Max на картинке выше, но это не единственный вариант. Обычно различают несколько вариантов взаимодействия текстуры и материала: Замена (Replace), Умножение (Modulate), Сложение (Add), Смешивание (Blend), Декаль(Decal) и Комбинация (Combine). Подробно о том, как взаимодействует цвет материала с текстурой в каждом из вариантов, можно почитать в любой книжке по OpenGL, нам лишь нужно запомнить что нужно предоставить возможность указать режим текстурирования.

Идем дальше, вспоминаем VBO - помните, мы там задавали еще один атрибут "Color"? Как он стыкуется с материалом и текстурами? Очень просто, мы либо вообще отключаем использование этого атрибута либо указываем вместо какого свойства материала он будет использован (о шейдерах мы пока не говорим). Этот вариант нам так же нужно учесть при разработке системы материалов.

С взаимодействием света с материалом и текстурой мы разобрались, но остается еще взаимодействие объекта со сценой - что объект будет делать со светом, проходящим сквозь него? По русски это звучит - как будет видно (и будет ли видно) объект, находящийся за нашим объектом. Речь идет в первую очередь о прозрачности, но это так же позволяет получить еще множество интересных эффектов. Весь этот процесс называется блендингом (Blending), и хоть это на прямую не связано с материалом, но при выводе объекта мы это тоже должны учитывать.

Ну и осталось упомянуть о самом выводе объектов - оставит ли он после себя "след". Речь идет о записи/чтении в буфер глубины. Это так же напрямую не связано с свойствами материала, но доставляет хлопот, когда нужно вывести полу-прозрачный объект, так как в OpenGL нет понятия "полупрозрачного" буфера глубины, объект либо оставляет "след" в буфере глубины либо нет. Таким образом, если стекло будет первым записано в буфер глубины, то все объекты, отображаемые за стеклом и которые рисовались после стекла не пройдут тест глубины и не будут отрисованы, таким образом стекло станет "дырой в пространстве", через которую будет виден цвет фона и объекты, отрисованные первыми.
[Image]

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

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

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

3 комментария:

  1. Не знаю почему, но в RSS этой статьи, к сожалению, нет.

    ОтветитьУдалить
  2. Думал в это статье будет что то сверхсложными, оказалось нет, все доступное и элементарное (это каждый должен знать ИМХО). Мне нравиться как ты пишешь статьи!)

    ОтветитьУдалить
  3. Я принципиально не пишу ничего сложного, те кто в состоянии этот материал понять - смогут найти его в гугле, к тому же чтоб понятно изложить этот материал - его нужно как минимум понять, а не скопировать из презентации какого-то университета, где толпа математиков пару лет выводила формулы... Так же нет смысла в очередной раз копировать материал из Красной книги, этих копий и так тысячи.

    Был вопрос в самой структуре статей - максимум информации с максимально точным изложением (читай 90% копипаста из других источников), или максимально сжатые статьи, с информацией исключительно по моему движку. Но остановился на ознакомительных статьях в "легкой форме" изложения, дающих общее представление о проблеме.

    Ну и первые статьи ну никак не могли быть сложными, все самое интересное будет дальше ;)

    ОтветитьУдалить