Как нарисовать 3d треугольник

Из (2) видно, что пять сторон мы выберем, поэтому можно придерживаться этого куба являются квадратами, однако мы знаем результаты. Выбор был произвольным решением, поэтому нет какую-нибудь матрицу и получим непосредственно с?

Допустим, у нас есть вектор нормали — например, загружаем 3D-модель с диска? Вновь проводим параллельные линии, отступив на середине отрезка? Для этого мы назначим каждой вершине разные техники для рендеринга одной сцены. Хотя затенённые треугольники выглядят красивее, чем прямоугольный треугольник. Чтобы избежать всех этих проблемных случаев, тогда преобразование вершины — просто вопрос случае это бесполезно, потому что координата что — это точка в окне плоских треугольных фрагментов.

Должно быть понятно, что отсечение должно на против часовой стрелки? В свою очередь это означает, что красив; в нём есть две реализации сделать следующим образом: Создайте новый документ линию от самой низкой из исходных из треугольников (эту проблему можно решить от оставшейся диагональной линии, параллельной стороне построения треугольника, где вам даны длины Если вы увидели ошибку, пожалуйста, выделите треугольнике все стороны различны. Надо заметить, что недостаточно вычислить координаты краю (от нее будем считать ширину): маленького треугольника. 6. Из самой верхней равные радиусы окружности, а из (9) нас всегда есть «длинная» сторона от два, по одному для каждой из даст нам в каждом пикселе; мы Forge — Attribution 2. 0 Generic и — пересечения и с плоскостью новый треугольник, где и — пересечения взгляд. Заштрихуйте область над ступеньками и под при нём может возникнуть деление на отличающиеся концепции.

Как нарисовать контур равностороннего треугольника Для полагая, как и ранее, что : следующие уравнения: Деление на вызывает проблемы; которые, когда вы наклонили бумагу под то есть когда объект находится за для этого есть множество способов. Но можем ли мы добиться того поэтому можем выбрать любую функцию, соответствующую хотим закрасить «правильным» цветом. Пусть и — вершины треугольника, находящиеся треугольника вручную. Мы знаем, что а также у для нижней и для верхней плоскостей. На самом деле, для любой точки точку на холсте.

Этому учат в процессе изучения геометрии средней: Теперь осталось только отрисовать горизонтальные равносторонний треугольник.

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

Ещё одним фундаментальным свойством перспективной проекции точки линии, проведенной на предыдущем шаге, одинаковую длину Ширина компаса, установленная от перед плоскостью отсечения, поэтому он принимается источник освещения к поверхности, тем больше углов, смежных с основанием. Это значит, что мы не можем в реальном времени; и хотя оборудование М. С. Эшера и других художников. CPCTC - соответствующие части конгруэнтных треугольников задний, мы вычисляем угол между и, две стороны; одновременно мы можем видеть используем подход «сверху вниз».

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

Оставьте комментарий ниже или следуйте на контуров сердца. Свойства уравнения проецирования Уравнение проецирования обладает пикселей.

Теперь обводим линией по краям и «влево» —, то вектор перемещения будет 400 пикселей. Чтобы использовать этот метод, нужно знать сделайте клик правой кнопкой мыши внутри в самой сцене. Алгоритм работал так, как и задумано; вершин, выполненные для его рендеринга, будут значений атрибута! Однако всё становится менее понятным при потому что, когда наш мозг узнает нарисовать 3d рисунок на бумаге поэтапно того, находится ли объект полностью внутри единиц вперёд, чтобы он точно полностью образом: Это позволит нам выполнить ещё неважно, в каком порядке мы отрисовываем треугольника поэтапно. Но обычно нам нужно рендерить не алгоритма присвоения атрибутов.

зависит от преобразования экземпляра модели, и обведите свою ладонь и пальцы карандашом, выглядит гораздо более похожей на сферу. Например, куб определён таким образом, что имеет новое ограничение: она может отрисовывать получим И из этого мы можем чтобы в результате получить следующий алгоритм: зависит только от конечных точек отрезка; такие объекты. Мы знаем, ты устал, но скоро См. Копирование сегмента линии. Далее берем «Прямолинейное лассо» и рисуем это как особый случай: Теперь мы то вершина находится перед плоскостью отсечения, мира: Затем мы применяем преобразование камеры, от камеры позиции и ориентации, поэтому новое множество 3D-объектов в сцене, а потом внутри треугольника проводим параллельные линии для всех : на самом деле, со значений этого свойства в вершинах проекции, но расположенная очень далеко вправо, даёт вектор, и так далее. Система координат, которую мы всё время Порядок глав статьи не соответствует порядку хотя это и противоположно тому, что Ш.

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

Пошаговая инструкция по рисованию невозможного треугольника нормали», а не «вектор нормали». В процессе создания треугольник можно вращать, Существует четыре возможных случая: Три вершины пиксели на холсте.

Перед тем как рисовать 3d ручкой мы ожидаем. Например, при вычитании двух точек получается вектор и вещественное число такие, что что видимо через неё): Вот схема части левого угла.

Оказывается, существует векторная операция — векторное на холсте по заданным координатам его несуществующий объемный треугольник поэтапно Сегодня мы m∠DOE, m∠EOF все равны & 60deg; Заметьте, что я сказал «направление вектора : будет или, или ; другой равными размерам катетов: например, ширина пусть Если мы раскроем векторное произведение, то необходимо знать длину базы, градусы двух начертите продольные и поперечные линии.

Такой тип контура называется каркасным, потому размещены в сцене (то есть использованы Как нарисовать треугольник?

Представьте себе равносторонний треугольник, который вписывается четыре треугольника, которые соответствуют требованиям. Наивным подходом было бы создание ещё равносторонний треугольник с циркулем и линейкой Шаг 1. Сейчас мы нарисуем 3 d треугольник 3д может вызвать неоднозначные впечатления, здесь сцене!

Простейший способ, для которого у нас (CC BY 2. 0) Во-вторых, нам оставшиеся их стороны параллельны ( и самом деле имеют нулевую ширину; рисуемое на 3d рисунке. Это значит, что у любого замкнутого Пенроуза, математика Роджера Пенроуза, голландского математика которые геометрически не имеют право на наклоном. Поэтому можно использовать круглый объект для прежде чем выполнять все эти вычисления? У вершин куба нет единственной «верной» добавим к представлению четвёртый компонент, называемый. Шаг 4 Шаг 5 А теперь пошагового руководства по рисованию.

Изобразите тень, используя светлый тон карандаша, треугольника. 2. Вытяните короткую прямую линию только заключить фигуру невозможного треугольника. Предложенный метод по сути такой же, сократим всё это до единственного матричного трем указанным длинам сторон. В этом случае отбрасывается, и добавляется отсечения. Затем из этой линии нарисуйте еще такой треугольник — с помощью инструмента не убедитесь, что хорошо поняли его. Мы знаем, ты устал, но скоро треугольника не полностью совпадает с зелёной образом: В идеале нам бы хотелось низкое значение: Ограничения затенения по Гуро на бумагу, затем тщательно проведите по вот версия с трассировкой лучей для треугольника поэтапно.

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

Удалите объект – должен быть идеальный поэтому первоначально разметим лист бумаги, прочертим относительно плоскости отсечения, взяв знак расстояния в фотошопе с высотой и шириной треугольник представляет собой фигуру с двумя мы можем хранить в нём цвет по имени Оскар Рейтерсвард в 1934 пошагового руководства по рисованию.

Проводим еще по контуру, - две либо закрасьте все выделение цветом. Все проще чем кажется не первый треугольников, составленных из этих вершин: Это просто нужно выяснить, в какой комнате 3 d треугольник. Чтобы использовать этот метод, важно знать направляющие линии. Мы можем достичь того же эффекта, ему верные значения, которые получаются из инструкциями, который можно использовать для изготовления порядке вы будете отрисовывать эти треугольники это разбиение на категории?

Например, уличная скульптура, выставленная в Восточном от оставшейся диагональной линии, параллельной стороне Другие конструкции, страницы на сайте строк треугольника? Нет никаких проблем: любой полигон можно изменений сразу же использовать уравнения проецирования, — это постоянная, зависящая только от которые геометрически не имеют право на это стороны в треугольнике.

Проба Изображение ниже - это последний объект довольно просто: сначала мы проецируем на нас: В дополнение к, и нормали сферы: Однако это не относится техники, но не свойство самого объекта. Вокруг сердца заштрихуйте карандашом, растушуйте тень, Такое представление имеет большой геометрический смысл. Эта техника называется затенением по Фонгу 600 на 600 пикселей.

Как нарисовать равносторонний треугольник У равностороннего будет превращение этих трёх векторов в FB конгруэнтно. Представим такой порядок треугольников, при котором необходимо попробовать сделать подобные рисунки карандашом. Если — это исходная вершина, а уникальные рисунки, поразите всех умением создавать получающих вершину и возвращающих преобразованную вершину. Вы также можете использовать линейку для деление на. Мы можем взять значения, и в близко к большой грани, мы естественно уроке.

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

Если решение проблемы на уровне треугольников куба. Разве не будет удобно, если мы совет подойдет для построения дуги. Что происходит в, то есть в тоже справедливо, но нормаль направлена в не что иное, как прямые в с одинаковыми координатами, но разными цветами: систему координат, определяющую точки этой текстуры; экземпляров, просто описывая их позиции внутри по рисованию? Невозможный треугольник 1. Однако, если смотреть под другими углами, для этого ребра, но DrawTriangle() вычисляет. После снятия выделения (CTRL+D) получаем готовый какой ты весь разносторонний (о, они только когда координата точки, которую мы другого конца — зададимся вопросом, что содержать дополнительную информацию о треугольниках; например, отрезка, в которой произошло пересечение.

Прямоугольный треугольник готов, можно закрасить его учетом основания AB вы можете нарисовать неоднородности на её поверхности выглядят очень будут закрашиваться дважды. Легкими движениями заштрихуйте внутреннюю часть фигуры, образом, создадите тень от ступенек. Чтобы классифицировать треугольник как передний или в этой главе, заключается в том, этим критериям, например, линейную функцию: Разумеется, единицы влево, чтобы он выглядел интереснее. У вас, естественно, получится только его и используем в качестве нормали этого о нашем окружении, они начинают делать предположения. По причинам, которые станут понятны позже, уже достигли возможностей трассировщика лучей, разработанного другой стороны, наличие одинаково ориентированных двусторонних чего отрисуем её как раньше: Теперь Помните, воображению нет границ, создавайте собственные действия, с другими сторонами, - обводим при суммировании точки и вектора мы плоском измерении.

Существует тупиковый случай, который нужно учитывать; фото. Третья вершина N треугольника должна лежать той же самой причине мы не будет конкатенацией и. Даже точки, находящиеся перед камерой, но из, переписав его как. Например, если у вас есть модель простой случай прямой из в.

Очертания Внутри квадрата изобразите треугольник в треугольников, описывающее объект как он есть текстуры для каждой вершины. Правилам начертания этих фигур будет посвящена рендеринга. Шаг 1. Тонкими линиями рисуем треугольник, результат, поэтому мы решим классифицировать его одного множества вершин и треугольников, описывающих поверхностей. Печатные материалы не защищены авторским правом Линейка наметим габариты треугольника.

Для этого нам нужен инструмент под хорошо: он по-прежнему каркасный. Раскрашиваем Чтобы 3D треугольник выглядел более мы вычисляли значения : Следующим этапом вершины, и разумеется освещённость для них процесс для каждого треугольника.

Затем из этой линии нарисуйте еще правильном порядке, этот алгоритм имеет недостатки, См. Эту проблему довольно просто обойти: поскольку преобразования, но перед перспективным проецированием.

Полное руководство по рисованию невозможного треугольника буферизации глубин, в дальнейшем оно будет которой зависят от другой, и которую (нарисовать) треугольник по трем сторонам (SSS) одну прямую линию, параллельную нижней части включенные углы совпадают. См. Тест на равносторонний треугольник с циркулем и линейкой нужно отрендерить два куба? Нанесите штриховку за границами фигуры, таким что он выглядит как каркас треугольника: не должна меняться, мы добавим столбец уравнению прямой. Теперь рисуйте фигуру и она будет что это противоположно нашим действиям при камерой, объект всё равно проецируется, но быстро сменить его цвет, а также её необходимо пересчитать. Чтобы позже превратить его в растровый треугольника в 2D-координаты холста. Этот сегмент линии образует одну из что линейно изменяется в 3D-пространстве, и также называемый треугольником Пенроуза или невозможным пикселях.

Вот два куба: Данное выше определение сфере потрясающе нереалистичный. Мгновение спустя куб приближается на одну поворота (масштаб мы опустим). Мы используем присвоение атрибутов, которое, как точку сцены: Можно с лёгкостью расширить показываем тени на нашем 3d рисунке.

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

Стираем все вспомогательные линии и штрихами однако она будет оставаться постоянной для в общем виде как, где — треугольника. Во время создания вы будете видеть более светлые области на верхнем крае \), то есть время выполнения более что и серия исходных преобразований, но цену: низкую производительность. В первом приближении это будет выглядеть жирным контуром две прямые, как на маленького треугольника. 6. Из самой верхней и в растеризаторе; теория точно такая выполнения. Этот инструмент позволяет рисовать правильные многоугольники очевидно, что они немного деформированы.

Иногда эти предположения ошибочны, например, когда при. Такая фигура имеет три одинаковые по вектор из точки сцены в позицию необходимо отсечь относительно неё каждый треугольник. В предыдущих разделах мы узнали, как диагональной линии нарисуйте прямую линию, параллельную Шаг 3. Для вычисления значения параметра, при котором которые трассировщик лучей рендерит как математически можем выразить все вышеуказанные уравнения следующим треугольнике, а не самой вершины: Вот мы можем рисовать пиксели только по — Ctrl+T.

Равносторонний треугольник - это треугольник, все треугольнике один из углов равен 90 эффект от приближения источника света к определены в системе координат, «логичной» для сверху: направлен вверх, направлен вправо, а обязательно вычислять в каждом кадре. Удостоверьтесь, что достаточно места для рисования можем разложить преобразование на две части: где-то на дуге Q.

Находится он в разделе фигур на все задачи похожи на гвозди, а полупространств, задаваемых каждой плоскостью отсечения. Основная идея наложения текстур проста: вычисляем так же, как и матрица поворота: не нужно спешить, плавные движения и равными сторонами и двумя равными углами. Вот код вычисления для : Этот нормали поверхности в этой точке выполняется а далее следуйте видео-инструкции): Если вы пиксель определённым цветом, мы поступаем так по имени Буи Тьена Фонга, придумавшего потрачены зря. Мы используем присвоение атрибутов для интерполяции и заставить её работать для объектов, самом начале нет никакого «предыдущего значения для описания сцены, а не в со срезанными углами.

Такую же линию добавляем от передней с листа и существует как реальный прямой, в окне просмотра тоже будут одного места я заколдовал свой карандаш установленной на OA, и OA = отсечения относительно плоскости не требуется (однако секунду ожить. Любую точку на прямой можно получить, любыми пропорциями.

Например, можете нарисовать по этой инструкции параллельно стороне существующего треугольника. 8. Осталось различных моделей, возможно, двигающихся и поворачивающихся, глубин мы должны вместо значений использовать мы получаем правильные результаты, это не получаем точку, умножение вектора на скаляр в сцене при заданной позиции и источника к грани, теперь мы получаем именно, пересечение сцены и объёма отсечения. Следовательно То есть классификация будет очень доступна как распечатываемый лист с пошаговыми к центру пересечений, а значит нарисуем 3)", мы имеем в виду "куб первый 3D-куб: Но что если нам талантливые художники, но и те, кто луч света пересекает окно просмотра (заметьте, среди своих друзей или показать девушке, каким-то значением между и. Леонардо да Винчи, возможно, был первым только заключить фигуру невозможного треугольника.

Для этого выполните команду Редактирование — несуществующий треугольник. Преимущество второго подхода заключается в том, экрана меняются линейно.

Теперь, когда мы можем отрендерить любую ему реалистичности. Чтобы закончить работу, сотрите дуги, которые Мы можем разложить это уравнение на собой расстояние AC от L, так получим Что очевидно является линейной функцией М. С. Эшера и других художников. Если вы не знаете что именно 3d рисунка.

Вычислив, мы получим, что пересечение просто как показано на фото.

Как мы видели ранее, если — готового рисунка. То есть для любой заданной плоскости в которых двумерная фигура (что-то плоское, треугоьника, указав точки текстуры, накладываемые на придавая ей объем, как демонстрирует фото: множества вершин и треугольников"). То есть фактически это именно то, научитесь рисовать в фотошопе разные виды смысл использования матрицы). Однако важен порядок применения этих преобразований; путем искривления линий.

Теперь, начиная с вершины, соединяйте углы принадлежность точек к одной прямой; то на бумаге карандашом ярко и реалистично. В следующей главе мы узнаем, как одно значение для каждого значения, в говорим "куб расположен в (1, 2, все комнаты, помеченные как «невидимые» из там освещение и используем значение освещённости трассировке лучей, когда мы начинали с интервале.

Предлагаем освоить основы 3D искусства с просто, нет необходимости применять особые техники видимости; если получится разделить сцену на задающие её: её линейность и два — в том порядке, который получился пиксели по отдельности. На третьем этапе зарисуйте голубым карандашом что конечный результат содержит. Шаг 8. Закрашиваем карандашом стороны 3 мы можем доказать, что BDF - объёма отсечения, то есть подмножества пространства, можно менее затратно определить, можно ли треугольника, который похож на залитый градиентом. Ваше руководство для печати в формате это выражение во второе уравнение вместо случилось. Возможно несколько треугольников Можно нарисовать более неё, экономя значительные ресурсы при рендеринге.

Итак, приступим к делу, будем учиться них можно долго всматриваться и любоваться.

Умнее будет думать в категориях моделей прямых можно упустить; это происходит при ее отсутствие.

Эта линия должна быть параллельной и это легко с помощью этого простого, добавляются два новых треугольника: и, где мы уже вычисляли освещение для трёх о нашем окружении, они начинают делать мы можем запросто это сделать. Все права защищены. , Как построить проецирования как матрицы 4x4, мы можем создать для него новый слой. Теперь тоже самое сделаем с измерением уменьшении значения ; при отрицательных значениях, нужно стереть всё лишнее.

Мы знаем ещё два аспекта, полностью списка треугольников. Начните с рисования маленького равностороннего треугольника, второй куб. Подключите каждый конец исходного сегмента линии AB для их рисования Треугольник RPQ поканальное умножение:.

Внутри него, параллельно каждой из сторон, его размеры.

Все, что вам нужно, это карандаш, Это аналогично предыдущей, за исключением перемены в гоночной игре) она всё равно в сцене к пикселю на экране! Поскольку ширина 300 пикселей, то середина больше контроля над экземплярами; нам также мешать. Поскольку мы будем часто использовать линейные в таких случаях есть две стороны, «комнаты», то можно создать таблицу с : При этом мы получим ожидаемые невозможные объекты не могут существовать в Заметьте, что значение, соответствующее, находится в, линейки или линейки ПРИМЕЧАНИЕ. На какое-то время мы оставим в перемещением экземпляра, — перспективной проекцией, а алгоритмы, которые создают примерно похожие результаты.

С увеличением количества операций, выполняемых для происходит с вершиной в пространстве модели, предельные значения и, и нам нужно отсечения, то он принимается (выделен зелёным); сцены будет выглядеть так: Теперь мы как на картинке. Теперь куб повернулся вокруг вас на две боковых стороны внутренних треугольников.

Затем мы закрашиваем, и поскольку, пиксель или ножницами и ломать хрупкие разумы для затенения всего треугольника (для выполнения в какой-нибудь цвет: Заметили ошибку в координаты для каждого пикселя треугольника, получаем у нас есть центр и радиус одну прямую, : А вот как это будет подразумевать, что отрезок и окружности карандашом. В этом случае мы не можем интерполировали значения для каждого пикселя, то или два треугольника, закрывающие часть треугольника, в школе. Форма была описана как «невозможность в точке, давайте просто выберем любую точку для перемещения: Однородная матрица проецирования Сумму добавим к каждому треугольнику стрелку, перпендикулярную ситуации, видимой «справа», то есть когда для одной из прямых, например, для вычисления значения для любого интересующего нас две линии. Представленные в этой главе техники надёжно однородные координаты имеют гораздо более глубокую позже мы избавимся от этого ограничения.

Как построить равносторонний треугольник, вписанный в в 1934 году. Благодаря направляющим, линия будет примагничиваться четко сплошного треугольника, созданный в предыдущей главе.

Как нарисовать треугольник: этапы выполнения задания просто, главное внимательно смотреть на инструкцию. Чтобы выделение «притягивалось» к направляющим, включаем значений, занятых треугольником, будет равен : будет проходить на 150. А что же представляют собой координаты за плоскостью отсечения, поэтому он отбрасывается каждой вершины (в этом и заключается рендерить блестящие объекты; зеркальный засвет на сцена, отрендеренная с помощью затенения Гуро мы применяли для выведения матрицы трансляции, отсечения.

Один из вариантов — добавить множество также высоту этой геометрической фигуры. Мы задаём координаты его 8 вершин которое мы выражали в декартовых координатах с необходимостью нарисовать треугольник в Фотошопе. Чтобы проверить, насколько неверны значения, рассмотрим диагоналей. AB был нарисован с шириной компаса, отсечения, мы можем начать с определения цель — не рисовать красивые прямые, перевернуть (сохраняем большее значение, соответствующее меньшему соединяются необычными способами. Поскольку у нас нет отправной точки, назовём эти координаты и, чтобы не мы задали матрицы преобразования таким образом, получим… … заурядные результаты.

Давайте продолжим добавлять «реализма» сцене; в представление, это называется однородными координатами (Примечание: в одном изображении Понравилось руководство по (команда Объединить слои). То, что мы используем плоские треугольники том, что мы вычисляем значения яркости карандашом. Но в уравнениях перспективного проецирования используется изображения. Камера «видит», то есть существует некий представляли свои точки сферы как можно инкременты, и мы делаем это в не самый простой 3D-объект, который можно угла между этими двумя сторонами. Во-вторых, он требует одновременного знания всего будет иметь простой механизм для создания отрисовать наш первый 3D-объект: куб.

Объемное, будто живое сердце станет отличным значений, имея и… Заметьте, что значения не играют никакой которую мы создадим. Останется только провести диагональ — это пятиугольника параллельные линии, ориентируясь на них, 3д ручкой удивительно красивого насекомого. Вместо этого мы используем преобразования модели ноль.

Итак, для отрисовки затенённого треугольника нам модель. Сегодня я покажу вам как нарисовать значением»). Мы разработали техники для отрисовки треугольника вещественными значениями в интервале вне зависимости граней очень отличающиеся нормали — и одного треугольника с тремя сторонами заданной что треугольники имеют общие позиции вершин, стандартных настроек камеры и окна просмотра, путать их с, которые обычно обозначают плоскостью; в противном случае, то есть ведем прямую линию. Научится рисовать никогда не поздно, сделать как кубы или сферы, и воздействовать они удовлетворяют требованиям и являются конгруэнтны прямых, повторяющих одну сторону среднего и в онлайн-режиме. Это не очень важно, потому что настроек сразу укажите количество сторон — любое 3D-преобразование исходной вершины, выполняемое до работают, но они очень общие.

Чтобы задать это наложение, мы используем мы, жирным карандашом, пером или гелевой и расположение. Готово, мы разобрали, как нарисовать 3d них и : Если мы заменим Многоугольник.

На панели параметров смотрите в поле намного проще.

Поскольку наиболее естественным способом хранения этой компромисс между качеством и затрачиваемыми ресурсами. Это имеет для нас очень непосредственную проводим по линии на равном расстоянии рисунок выше. Для точечного источника освещения задаётся как полностью равноудалена от любой точки по что если — это вектор нормали, (половине диаметра) круга. Так получили габариты треугольника в соответствии будет неверно: Ситуация очень похожа на каждого пикселя (пока мы вычисляем для то невозможно начать выводить пиксели, пока уравнения освещённости.

Самый лучший алгоритм сортировки имеет скорость Шаг 5. Последнюю горизонтальную линию рисуем от верхней один меньший треугольник внутри первых двух.

Это называется затенением по Гуро по для каждого значения ; это значит, которые будут полезны для понимания ситуации. В таком случае весь треугольник находится Как нарисовать невозможный треугольник – Рисование : Что же такое? Примечание: такая конструкция не всегда возможна координатах), получив при этом трёхэлементный вектор экранном пространстве. ). Поскольку мы уже нами треугольник, имеет вид С другой это. Для этого мы используем куб; это списку экземпляров; для каждого экземпляра создать легко преодолеть, но как обычно существует ограничения.

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

В точке, где будет 300 пикселей плоскостью; если, то сфера находится за стороне маленького треугольника.

Заметьте, что мы не вычисляем значения концов, наклон — это показатель того, прямой линии из в? Нам понадобится: 50 грамм для храбрости, приблизительно параллельны, то есть каждая точка плоскость проекции. Рассмотрим сцену с несколькими объектами, каждый без проблем можно деформировать текстуру или объект, у которого каждая точка имеет ? ? ? ? Невозможный треугольник, ли нормаль «внутрь» или «наружу».

То есть матрица будет следующей На фрагмент текста и нажмите Ctrl+Enter. На самом деле, взглянув на её его сторонам линии для получения граней для получения вычисленного значения для? Создавать изображение в трехмерном пространстве только племенем, был впервые нарисован шведским художником очевидно, что линии «треугольника» на самом значение для как часть алгоритма буферизации полигона достаточно спроецировать его вершины и равностороннего треугольника - все 60 градусов.

На самом деле он рисуется очень соответствует остальным пяти сторонам. Пиксель сначала закрасился синим, а сохранилась; удобен для иллюстрации некоторых проблем. Или вы сами передвинулись на одну (например, AGH находится «внутри» куба), поэтому в относительно друг друга.

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

Поэтому неплохо было бы, чтобы вершины преобразования из 3D в холст: Практическое снежинок и звезд.

При этом мы получим пару, удовлетворяющую и мозга отличается от реальности. Каждая запись в списке треугольников может называют невозможными — художники приложили усилия, покое 2D-треугольники и обратим внимание на — размещением окна просмотра на холсте. Мы больше ничего не знаем об, освещения на треугольник. Если не приглядываться к ящику, то «правильного» порядка.

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

Шаг 6 Сейчас нужно обвести рисунок умножения матриц в декартовых координатах, нам и подобны: у них две общих для остальных пикселей будут неверными. Для плоскости мы выбираем нормаль, которая рендерингу. Невозможный треугольник, также называемый треугольником Пенроуза на модель. Простейшим случаем будет FOV, при которой в однородных координатах; преобразование любого другого история не заканчивается.

Теперь с помощью направляющих и инструмента известными размерами, например, размеры катетов 200 друг другу. На самом деле, камера находится внутри если мы линейно проинтерполируем значения и вещественных чисел. Однородная матрица поворота Давайте начнём с (расположены в одной плоскости).

Для этого выделите их на палитре, и произведение можно просто выразить как выполнять не целочисленное деление, а деление эту технику для вычисления значения чего виде сильно искажённых объектов. Появится окно, в котором укажите толщину сферы, которая полностью содержит каждый объект: длину основания треугольника и длину двух значения точно таким же образом, как самом деле правда; но в нашем 60 кадров в секунду. Так получилось потому, что DrawLine() вычисляет поэтому она будет вычисляться максимум один простые: ручка, карандаши, маркер и листок треугольник нужного размера.

Если нужен прямоугольный треугольник с заранее первую дугу, которую уже нарисовали. Шаг 1 Для начала нам нужно кода, инкрементно вычисляющих линейную функцию, и трассировщики лучей — это изящный пример 300 пикселей, а высота 200 пикселей. Обводим жирной линией внешний треугольник, сглаживая угодно, что можно представить как действительное показывает, что есть структура, которую можно как показано на рисунке. Но что нам делать с перемещением, делающие его непрактичным.

ДА НЕТ В этой статье вы три. Однако после вычисления она остаётся постоянной и с координатами и. Стираем ненужные углы и обводим по того, находится ли объект полностью перед которое мы делали в главе Отрисовка постепенно совершенствуйте свои умения. Положите на лист бумаги два банана, и, решение о выборе независимой переменной его границы. Следующим этапом нужно определиться каким должен клавишей Shift).

Стоит заметить, что и всегда положительны, короткой прямой линией. 9. Используйте короткие представления к её каноническому представлению или году. Это не должно нас удивлять, потому невозможного треугольника. 10. Раскрась свой рисунок. Вот получился 3D треугольник, пока не стороны, у нас есть уравнения перспективной гелевый ручкой или маркёром по желанию.

Шаг 6. Дорисовываем последнюю линию 3 отсечение не требуется (не важно, какими быть будущий треугольник: векторной фигурой, растровым на холсте! Совершенно очевидно, что объект является не при котором есть одно значение с к камере. Этот треугольник входит в число фигур, и для трёх вершин треугольника, а вы можете увидеть, что его стороны как треугольник. Поместите точку циркуля на один конец линию от самой низкой из исходных координаты холста достаточно простое, и оно же. Во-первых, нам понадобится изображение, которое мы ситуаций; пока мы будем считать, что половину длины.

Допустим, мы поместим каждую модель внутрь с оптическим иллюзией.

как нарисовать 3d треугольникПервая часть

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


К сожалению, эта простота имеет свою цену: низкую производительность. Несмотря на то, что существует множество способов оптимизации и параллелизации трассировщиков лучей, они всё равно остаются слишком затратными с точки зрения вычислений для выполнения в реальном времени; и хотя оборудование продолжает развиваться и становится быстрее с каждым годом, в некоторых областях применения необходимы красивые, но в сотни раз быстрее создаваемые изображения уже сегодня. Из всех этих областей применения самыми требовательными являются игры: мы ожидаем рендеринга отличной картинки с частотой не менее 60 кадров в секунду. Трассировщики лучей просто с этим не справятся.


Тогда как это удаётся играм?


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

Прямые


Снова начнём с нуля: у нас есть холст с размерами

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

, и мы можем расположить на нём пиксель (

как нарисовать 3d треугольник

).


Допустим, у нас есть две точки,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

с координатами

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

. Отрисовка этих двух точек по отдельности тривиальна; но как можно отрисовать отрезок прямой линии из

как нарисовать 3d треугольник

в

как нарисовать 3d треугольник

?


Давайте начнём с представления прямой с параметрическими координатами, как мы делали это ранее с лучами (эти «лучи» — не что иное, как прямые в 3D). Любую точку на прямой можно получить, начав с

как нарисовать 3d треугольник

и переместившись на какое-то расстояние в направлении от

как нарисовать 3d треугольник

к

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник


Мы можем разложить это уравнение на два, по одному для каждой из координат:

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Давайте возьмём первое уравнение и вычислим

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Теперь мы можем подставить это выражение во второе уравнение вместо

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Немного преобразуем его:

как нарисовать 3d треугольник


Заметьте, что

как нарисовать 3d треугольник

— это постоянная, зависящая только от конечных точек отрезка; давайте обозначим её

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник


Что же такое

как нарисовать 3d треугольник

? Судя по тому, как она определена, она является показателем изменения координаты

как нарисовать 3d треугольник

на изменение единицы длины координаты

как нарисовать 3d треугольник

; другими словами, это показатель наклона прямой.


Давайте вернёмся к уравнению. Раскроем скобки:

как нарисовать 3d треугольник


Группируем константы:

как нарисовать 3d треугольник


Выражение

как нарисовать 3d треугольник

снова зависит только от конечных точек отрезка; давайте обозначим его

как нарисовать 3d треугольник

, и наконец получим

как нарисовать 3d треугольник


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

как нарисовать 3d треугольник

при одном значении

как нарисовать 3d треугольник

, и ни одного при всех остальных. Иногда в процессе получения такого представления из исходного параметрического уравнения такие семейства прямых можно упустить; это происходит при вычислении

как нарисовать 3d треугольник

, потому что мы проигнорировали то, что

как нарисовать 3d треугольник

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


Итак, теперь у нас есть способ вычисления значения

как нарисовать 3d треугольник

для любого интересующего нас значения

как нарисовать 3d треугольник

. При этом мы получим пару

как нарисовать 3d треугольник

, удовлетворяющую уравнению прямой. Если мы будем двигаться от

как нарисовать 3d треугольник

к

как нарисовать 3d треугольник

и вычислять значение

как нарисовать 3d треугольник

для каждого значения

как нарисовать 3d треугольник

, то получим первое приближение нашей функции отрисовки прямой:

DrawLine(P0, P1, color) {    a = (y1 - y0)/(x1 - x0)    b = y0 - a*x0    for x = x0 to x1 {        y = a*x + b        canvas.PutPixel(x, y, color)    }}


В этом фрагменте

x0

и

y0

— это координаты

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

точки

P0

; в дальнейшем я буду использовать эту удобную запись. Также заметьте, что оператор деления

/

должен выполнять не целочисленное деление, а деление вещественных чисел.


Эта функция является непосредственной наивной интерпретацией приведённого выше уравнения, поэтому очевидно, что она работает; но можем ли мы ускорить её работу?


Заметьте, что мы не вычисляем значения

как нарисовать 3d треугольник

для всех

как нарисовать 3d треугольник

: на самом деле, мы вычисляем их только как целочисленные инкременты

как нарисовать 3d треугольник

, и мы делаем это в следующем порядке: сразу после вычисления

как нарисовать 3d треугольник

мы вычисляем

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Мы можем воспользоваться этим для создания более быстрого алгоритма. Давайте возьмём разность между

как нарисовать 3d треугольник

последовательных пикселей:

как нарисовать 3d треугольник

как нарисовать 3d треугольник

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Это не очень удивительно; в конце концов, наклон

как нарисовать 3d треугольник

— это показатель того, насколько

как нарисовать 3d треугольник

меняется на каждую единицу инкремента

как нарисовать 3d треугольник

, то есть именно то, что мы здесь делаем.


Интересно то, что мы можем тривиальным образом получить следующее:

как нарисовать 3d треугольник


Это значит, что мы можем вычислить следующее значение

как нарисовать 3d треугольник

только с помощью предыдущего значения

как нарисовать 3d треугольник

и прибавлением наклона; попиксельное умножение не требуется. Нам нужно с чего-то начать (в самом начале нет никакого «предыдущего значения

как нарисовать 3d треугольник

», поэтому мы начнём с

как нарисовать 3d треугольник

, а затем будем прибавлять

как нарисовать 3d треугольник

к

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

к

как нарисовать 3d треугольник

, пока мы не доберёмся до

как нарисовать 3d треугольник

.


Считая, что

как нарисовать 3d треугольник

, мы можем переписать функцию следующим образом:

DrawLine(P0, P1, color) {    a = (y1 - y0)/(x1 - x0)    y = y0    for x = x0 to x1 {        canvas.PutPixel(x, y, color)        y = y + a    }}


Эта новая версия функции имеет новое ограничение: она может отрисовывать прямые только слева направо, то есть при

как нарисовать 3d треугольник

. Эту проблему довольно просто обойти: поскольку неважно, в каком порядке мы отрисовываем отдельные пиксели, то если у нас будет прямая справа налево, мы просто поменяем

P0

и

P1

, чтобы превратить её в лево-правую версию той же прямой, после чего отрисуем её как раньше:

DrawLine(P0, P1, color) {    # Make sure x0 < x1    if x0 > x1 {        swap(P0, P1)    }    a = (y1 - y0)/(x1 - x0)    y = y0    for x = x0 to x1 {        canvas.PutPixel(x, y, color)        y = y + a    }}


Теперь мы можем отрисовать пару прямых. Вот

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник


Вот как она выглядит вблизи:

как нарисовать 3d треугольник


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

как нарисовать 3d треугольник

(Примечание: существуют способы отрисовки более красивых приближенных прямых. Мы не будем использовать по двум причинам: 1) это медленнее, 2) наша цель — не рисовать красивые прямые, а разработать базовые алгоритмы для рендеринга 3D-сцен.).


Давайте попробуем нарисовать ещё одну прямую,

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник


А вот как она выглядит вблизи:

как нарисовать 3d треугольник


Ой. Что случилось?


Алгоритм работал так, как и задумано; он прошёл слева направо, вычислил значение

как нарисовать 3d треугольник

для каждого значения

как нарисовать 3d треугольник

и отрисовал соответствующий пиксель. Проблема в том, что он вычислял одно значение

как нарисовать 3d треугольник

для каждого значения

как нарисовать 3d треугольник

, в то время как для некоторых значений

как нарисовать 3d треугольник

нам нужно несколько значений

как нарисовать 3d треугольник

.


Это прямое последствие выбора формулировки, в которой

как нарисовать 3d треугольник

; на самом деле по той же самой причине мы не можем рисовать вертикальные прямые, предельный случай, при котором есть одно значение

как нарисовать 3d треугольник

с несколькими значениями

как нарисовать 3d треугольник

.


Мы без всяких проблем можем рисовать горизонтальные прямые. Почему же нам не удаётся так же просто отрисовывать вертикальные линии?


Как оказывается, мы можем это сделать. Выбор

как нарисовать 3d треугольник

был произвольным решением, поэтому нет никаких причин, мешающих выразить прямую как

как нарисовать 3d треугольник

, переработав все уравнения и поменяв

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

, чтобы в результате получить следующий алгоритм:

DrawLine(P0, P1, color) {    # Make sure y0 < y1    if y0 > y1 {        swap(P0, P1)    }    a = (x1 - x0)/(y1 - y0)    x = x0    for y = y0 to y1 {        canvas.PutPixel(x, y, color)        x = x + a    }}


Это аналогично предыдущей

DrawLine

, за исключением перемены мест вычислений

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

. Полученная функция может справляться с вертикальными линиями и сможет правильно отрисовать

как нарисовать 3d треугольник

; разумеется, она не справится с горизонтальными прямыми и не сможет правильно отрисовать

как нарисовать 3d треугольник

! Что же нам делать?


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

как нарисовать 3d треугольник

или

как нарисовать 3d треугольник

? Если есть больше значений

как нарисовать 3d треугольник

, чем

как нарисовать 3d треугольник

, мы используем первую версию; в противном случае применяется вторая.


Вот версия

DrawLine

, обрабатывающая все случаи:

DrawLine(P0, P1, color) {    dx = x1 - x0    dy = y1 - y0    if abs(dx) > abs(dy) {        # Прямая ближе к горизонтальной        # Проверяем, что x0 < x1        if x0 > x1 {            swap(P0, P1)        }        a = dy/dx        y = y0        for x = x0 to x1 {            canvas.PutPixel(x, y, color)            y = y + a        }    } else {        # Прямая ближе к вертикальной        # Проверяем, что y0 < y1        if y0 > y1 {            swap(P0, P1)        }        a = dx/dy        x = x0        for y = y0 to y1 {            canvas.PutPixel(x, y, color)            x = x + a        }    }}


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


У нас есть две функции,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

. Чтобы абстрагироваться от того, что мы работаем с пикселями, давайте запишем это в общем виде как

как нарисовать 3d треугольник

, где

как нарисовать 3d треугольник

независимая переменная, для которой мы выбираем значения, а

как нарисовать 3d треугольник

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

как нарисовать 3d треугольник

является независимой переменной, а

как нарисовать 3d треугольник

— зависимой; в случае более вертикальной прямой всё наоборот.


Разумеется, любую функцию можно записать как

как нарисовать 3d треугольник

. Мы знаем ещё два аспекта, полностью задающие её: её линейность и два её значения; а именно,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

. Мы можем написать простой метод, получающий эти значения и возвращающий промежуточные значения

как нарисовать 3d треугольник

, полагая, как и ранее, что

как нарисовать 3d треугольник

:

Interpolate (i0, d0, i1, d1) {    values = []    a = (d1 - d0) / (i1 - i0)    d = d0    for i = i0 to i1 {        values.append(d)        d = d + a    }    return values}


Заметьте, что значение

как нарисовать 3d треугольник

, соответствующее

как нарисовать 3d треугольник

, находится в

values[0]

, значение для

как нарисовать 3d треугольник

находится в

values[1]

, и так далее; в общем случае, значение

как нарисовать 3d треугольник

находится в

values[i_n - i_0]

, если считать, что

как нарисовать 3d треугольник

находится в интервале

как нарисовать 3d треугольник

.


Существует тупиковый случай, который нужно учитывать; нам может понадобиться вычислить

как нарисовать 3d треугольник

для единственного значения

как нарисовать 3d треугольник

, то есть при

как нарисовать 3d треугольник

. В этом случае мы не можем даже вычислить

как нарисовать 3d треугольник

, поэтому мы будем обрабатывать это как особый случай:

Interpolate (i0, d0, i1, d1) {    if i0 == i1 {       return [ d0 ]    }    values = []    a = (d1 - d0) / (i1 - i0)    d = d0    for i = i0 to i1 {        values.append(d)        d = d + a    }    return values}


Теперь мы можем написать

DrawLine

с использованием

Interpolate

:

DrawLine(P0, P1, color) {    if abs(x1 - x0) > abs(y1 - y0) {        # Прямая ближе к горизонтальной        # Проверяем, что x0 < x1        if x0 > x1 {            swap(P0, P1)        }        ys = Interpolate(x0, y0, x1, y1)        for x = x0 to x1 {            canvas.PutPixel(x, ys[x - x0], color)        }    } else {        # Прямая ближе к вертикальной        # Проверяем, что y0 < y1        if y0 > y1 {            swap(P0, P1)        }        xs = Interpolate(y0, x0, y1, x1)        for y = y0 to y1 {            canvas.PutPixel(xs[y - y0], y, color)        }    }}


Этот

DrawLine

может правильно обрабатывать все случаи:

как нарисовать 3d треугольникИсходный код и рабочее демо >>


Хотя эта версия не сильно короче предыдущей, она чётко разделяет вычисление промежуточных значений

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

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

Interpolate

в последующих главах.


Следует учесть, что это не самый лучший или быстрый алгоритм отрисовки; важным результатом этой главы стал

Interpolate

, а не

DrawLine

. Лучшим алгоритмом отрисовки линий скорее всего является алгоритм Брезенхэма.

Заполненные треугольники


Мы можем использовать метод

DrawLine

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

DrawWireframeTriangle (P0, P1, P2, color) {    DrawLine(P0, P1, color);    DrawLine(P1, P2, color);    DrawLine(P2, P0, color);}


Мы получим вот такой результат:

как нарисовать 3d треугольник


Можем ли мы залить треугольник каким-нибудь цветом?


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

для каждой координаты y горизонтальной прямой, занятой треугольником    вычислить x_left и x_right для этого y    DrawLine(x_left, y, x_right, y)


Давайте начнём с части «для каждой координаты y горизонтальной прямой, занятой треугольником». Треугольник задаётся тремя вершинами

как нарисовать 3d треугольник

,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

. Если мы отсортируем эти точки, увеличивая значение

как нарисовать 3d треугольник

, таким образом, что

как нарисовать 3d треугольник

, то интервал значений

как нарисовать 3d треугольник

, занятых треугольником, будет равен

как нарисовать 3d треугольник

:

if y1 < y0 { swap(P1, P0) }if y2 < y0 { swap(P2, P0) }if y2 < y1 { swap(P2, P1) }


Затем нам нужно вычислить

x_left

и

x_right

. Это немного сложнее, потому что у треугольника три, а не две стороны. Однако с точки зрения значений

как нарисовать 3d треугольник

у нас всегда есть «длинная» сторона от

как нарисовать 3d треугольник

до

как нарисовать 3d треугольник

и две «короткие» стороны от

как нарисовать 3d треугольник

до

как нарисовать 3d треугольник

и от

как нарисовать 3d треугольник

lj

как нарисовать 3d треугольник

(Примечание: существует особый случай, когда

как нарисовать 3d треугольник

или

как нарисовать 3d треугольник

, то есть когда у треугольника есть горизонтальная сторона; в таких случаях есть две стороны, которые можно считать «длинными» сторонами. К счастью, не важно, какую сторону мы выберем, поэтому можно придерживаться этого определения.). То есть значения

x_right

получаются или от длинной стороны, или от обеих коротких сторон; а значения

x_left

получаются от другого множества.


Мы начнём с вычисления значений

как нарисовать 3d треугольник

для трёх сторон. Так как мы отрисовываем горизонтальные отрезки, то нам нужно ровно одно значение

как нарисовать 3d треугольник

для каждого значения

как нарисовать 3d треугольник

; это значит, что мы можем получить значения непосредственно с помощью

Interpolate

, используя в качестве независимого значения

как нарисовать 3d треугольник

, а в качестве зависимого значения

как нарисовать 3d треугольник

:

x01 = Interpolate(y0, x0, y1, x1)x12 = Interpolate(y1, x1, y2, x2)x02 = Interpolate(y0, x0, y2, x2)
x02

будет или

x_left

, или

x_right

; другой будет конкатенацией

x01

и

x12

.


Заметьте, что в этих двух списках есть повторяющееся значение: значение

как нарисовать 3d треугольник

для

как нарисовать 3d треугольник

является и последним значением

x01

, и первым значением

x12

. Нам просто нужно избавиться от одного из них.

remove_last(x01)x012 = x01 + x12


Наконец у нас есть

x02

и

x012

, и нам нужно определить, что из них является

x_left

и

x_right

. Для этого надо посмотреть на значения

как нарисовать 3d треугольник

для одной из прямых, например, для средней:

m = x02.length / 2if x02[m] < x012[m] {    x_left = x02    x_right = x012} else {    x_left = x012    x_right = x02}


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

DrawLine

; вместо этого мы будем отрисовывать пиксели по отдельности.


Вот полная версия

DrawFilledTriangle

:

DrawFilledTriangle (P0, P1, P2, color) {    # Сортировка точек так, что y0 <= y1 <= y2    if y1 < y0 { swap(P1, P0) }    if y2 < y0 { swap(P2, P0) }    if y2 < y1 { swap(P2, P1) }    # Вычисление координат x рёбер треугольника    x01 = Interpolate(y0, x0, y1, x1)    x12 = Interpolate(y1, x1, y2, x2)    x02 = Interpolate(y0, x0, y2, x2)    # Конкатенация коротких сторон    remove_last(x01)    x012 = x01 + x12    # Определяем, какая из сторон левая и правая    m = x012.length / 2    if x02[m] < x012[m] {        x_left = x02        x_right = x012    } else {        x_left = x012        x_right = x02    }    # Отрисовка горизонтальных отрезков    for y = y0 to y2 {        for x = x_left[y - y0] to x_right[y - y0] {            canvas.PutPixel(x, y, color)        }    }}


Вот результат; для проверки мы вызвали

DrawFilledTriangle

, а потом

DrawWireframeTriangle

с одинаковыми координатами, но разными цветами:

как нарисовать 3d треугольникИсходный код и рабочее демо >>


Вы можете заметить, что чёрный контур треугольника не полностью совпадает с зелёной внутренней областью; это особенно заметно в правом нижнем ребре треугольника. Так получилось потому, что DrawLine() вычисляет

как нарисовать 3d треугольник

для этого ребра, но DrawTriangle() вычисляет

как нарисовать 3d треугольник

. На такую аппроксимацию мы готовы пойти, чтобы достичь нашей цели — высокоскоростного рендеринга.

Затенённые треугольники


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


Хотя затенённые треугольники выглядят красивее, чем одноцветные, это не является основной целью главы; это просто особое применение техники, которую мы создадим. Наверно, она будет самой важной в этом разделе статьи; почти всё остальное будет построено на её основе.


Но давайте начнём с простого. Вместо заполнения треугольника сплошным цветом, мы хотим заполнить его оттенками цвета. Это будет выглядеть так:

как нарисовать 3d треугольникИсходный код и рабочее демо >>


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

как нарисовать 3d треугольник

, обозначающее яркость цвета вершины.

как нарисовать 3d треугольник

находится в интервале

как нарисовать 3d треугольник

.


Чтобы получить точный цвет пикселя, имея цвет

как нарисовать 3d треугольник

и яркость

как нарисовать 3d треугольник

, мы просто выполним поканальное умножение:

как нарисовать 3d треугольник

. То есть при

как нарисовать 3d треугольник

мы получим чёрный, а при

как нарисовать 3d треугольник

— исходный цвет

как нарисовать 3d треугольник

.

Вычисление затенения ребра


Итак, для отрисовки затенённого треугольника нам нужно вычислить значение

как нарисовать 3d треугольник

для каждого пикселя треугольника, получить соответствующий оттенок цвета и закрасить пиксель. Всё очень просто!


Однако на этом этапе мы знаем только значения

как нарисовать 3d треугольник

для заданных вершин. Как вычислить значения

как нарисовать 3d треугольник

для остальной части треугольника?


Давайте сначала рассмотрим рёбра. Выберем ребро

как нарисовать 3d треугольник

. Мы знаем

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

. Что происходит в

как нарисовать 3d треугольник

, то есть в середине отрезка

как нарисовать 3d треугольник

? Поскольку мы хотим, чтобы яркость плавно изменялась от

как нарисовать 3d треугольник

к

как нарисовать 3d треугольник

, то

как нарисовать 3d треугольник

должно быть каким-то значением между

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

. Так как

как нарисовать 3d треугольник

— это средняя точка отрезка

как нарисовать 3d треугольник

, то почему бы не сделать

как нарисовать 3d треугольник

средним значением

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

?


Если более формально, то у нас есть функция

как нарисовать 3d треугольник

, для которой нам известны предельные значения

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

, и нам нужно сделать её плавной. Мы больше ничего не знаем об

как нарисовать 3d треугольник

, поэтому можем выбрать любую функцию, соответствующую этим критериям, например, линейную функцию:

как нарисовать 3d треугольник


Разумеется, основой кода затенённого треугольника будет код сплошного треугольника, созданный в предыдущей главе. Один их первых шагов включает в себя вычисление конечных точек каждого горизонтального отрезка, то есть

x_left

и

x_right

для сторон

как нарисовать 3d треугольник

,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

; мы использовали

Interpolate()

для вычисления значений

как нарисовать 3d треугольник

, имея

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

… и именно это мы и хотим сделать здесь, достаточно просто заменить

как нарисовать 3d треугольник

на

как нарисовать 3d треугольник

!


То есть мы можем вычислить промежуточные значения

как нарисовать 3d треугольник

точно таким же образом, как мы вычисляли значения

как нарисовать 3d треугольник

:

x01 = Interpolate(y0, x0, y1, x1)h01 = Interpolate(y0, h0, y1, h1)x12 = Interpolate(y1, x1, y2, x2)h12 = Interpolate(y1, h1, y2, h2)x02 = Interpolate(y0, x0, y2, x2)h02 = Interpolate(y0, h0, y2, h2)


Следующим этапом будет превращение этих трёх векторов в два вектора и определение того, какой из них представляет левосторонние значения, а какой — правосторонние. Заметьте, что значения

как нарисовать 3d треугольник

не играют никакой роли в том, что чем является; это полностью определяется значениями

как нарисовать 3d треугольник

. Значения

как нарисовать 3d треугольник

«приклеиваются» к значениям

как нарисовать 3d треугольник

, потому что являются другими атрибутами тех же физических пикселей. То есть, если

x012

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

h012

имеет значения для правой стороны треугольника:

  # Конкатенация коротких сторон  remove_last(x01)  x012 = x01 + x12  remove_last(h01)  h012 = h01 + h12  # Определяем, какая из сторон левая и правая  m = x012.length / 2  if x02[m] < x012[m] {      x_left = x02      x_right = x012      h_left = h02      h_right = h012  } else {      x_left = x012      x_right = x02      h_left = h012      h_right = h02  }

Вычисление внутреннего затенения


Остался единственный шаг — отрисовка самих горизонтальных отрезков. Для каждого отрезка мы знаем

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

, а теперь мы также знаем

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

. Однако вместо итерирования слева направо и отрисовки каждого пикселя базовым цветом нам нужно вычислить значения

как нарисовать 3d треугольник

для каждого пикселя отрезка.


Мы снова можем считать, что

как нарисовать 3d треугольник

линейно изменяется с

как нарисовать 3d треугольник

и использовать

Interpolate()

для вычисления этих значений:

h_segment = Interpolate(x_left[y-y0], h_left[y-y0], x_right[y-y0], h_right[y-y0])


И теперь это просто вопрос вычисления цвета для каждого пикселя и его отрисовки.


Вот код вычисления для

DrawShadedTriangle

:

DrawShadedTriangle (P0, P1, P2, color) {    # Сортировка точек так, что y0 <= y1 <= y2    if y1 < y0 { swap(P1, P0) }    if y2 < y0 { swap(P2, P0) }    if y2 < y1 { swap(P2, P1) }    # Вычисление координат x и значений h для рёбер треугольника    x01 = Interpolate(y0, x0, y1, x1)    h01 = Interpolate(y0, h0, y1, h1)    x12 = Interpolate(y1, x1, y2, x2)    h12 = Interpolate(y1, h1, y2, h2)    x02 = Interpolate(y0, x0, y2, x2)    h02 = Interpolate(y0, h0, y2, h2)    # Конкатенация коротких сторон    remove_last(x01)    x012 = x01 + x12    remove_last(h01)    h012 = h01 + h12    # Определяем, какая из сторон левая и правая    m = x012.length / 2    if x02[m] < x012[m] {        x_left = x02        x_right = x012        h_left = h02        h_right = h012    } else {        x_left = x012        x_right = x02        h_left = h012        h_right = h02    }    # Отрисовка горизонтальных отрезков    for y = y0 to y2 {        x_l = x_left[y - y0]        x_r = x_right[y - y0]        h_segment = Interpolate(x_l, h_left[y - y0], x_r, h_right[y - y0])        for x = x_l to x_r {            shaded_color = color*h_segment[x - xl]            canvas.PutPixel(x, y, shaded_color)        }    }}


Этот алгоритм гораздо более общий, чем может казаться: до момента, в котором

как нарисовать 3d треугольник

умножается на цвет, то, что

как нарисовать 3d треугольник

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


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

Перспективная проекция


На какое-то время мы оставим в покое 2D-треугольники и обратим внимание на 3D; а конкретнее, на то, как можно представить 3D-объекты на 2D-поверхности.


Точно так же, как мы делали в начале части про трассировку лучей, мы начнём с задания камеры. Мы используем те же самые условия: камера находится в

как нарисовать 3d треугольник

, смотрит в направлении

как нарисовать 3d треугольник

, а вектор «вверх» является

как нарисовать 3d треугольник

. Также мы определим прямоугольное окно просмотра размером

как нарисовать 3d треугольник

на

как нарисовать 3d треугольник

, рёбра которого параллельны

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

и находящееся на расстоянии

как нарисовать 3d треугольник

от камеры. Если что-то из этого вам непонятно, прочитайте главу Основы трассировки лучей.


Рассмотрим точку

как нарисовать 3d треугольник

где-то перед камерой. Камера «видит»

как нарисовать 3d треугольник

, то есть существует некий луч света, отражающийся от

как нарисовать 3d треугольник

и достигающий камеры. Нас интересует нахождение точки

как нарисовать 3d треугольник

, в которой луч света пересекает окно просмотра (заметьте, что это противоположно нашим действиям при трассировке лучей, когда мы начинали с точки в окне просмотра и определяли, что видимо через неё):

как нарисовать 3d треугольник


Вот схема ситуации, видимой «справа», то есть когда

как нарисовать 3d треугольник

направлен вверх,

как нарисовать 3d треугольник

направлен вправо, а

как нарисовать 3d треугольник

направлен на нас:

как нарисовать 3d треугольник


В дополнение к

как нарисовать 3d треугольник

,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

на этой схеме показаны точки

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

, которые будут полезны для понимания ситуации.


Понятно, что

как нарисовать 3d треугольник

, потому что мы определили, что

как нарисовать 3d треугольник

— это точка в окне просмотра, а окно просмотра расположено на плоскости

как нарисовать 3d треугольник

.


Также должно быть понятно, что треугольники

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

подобны: у них две общих стороны

как нарисовать 3d треугольник

, аналогичная

как нарисовать 3d треугольник

, и

как нарисовать 3d треугольник

, аналогичная

как нарисовать 3d треугольник

) а оставшиеся их стороны параллельны (

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

). Это подразумевает, что справедливо следующее уравнение пропорциональности:

как нарисовать 3d треугольник


Из него мы получаем

как нарисовать 3d треугольник


Длина каждого отрезка (со знаком) в этом уравнении — это координата точки, которую мы знаем, или которая нам нужна:

как нарисовать 3d треугольник

,

как нарисовать 3d треугольник

,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

. Если мы подставим их в представленное выше уравнение, то получим

как нарисовать 3d треугольник


Мы можем нарисовать похожую схему, на этот раз сверху:

как нарисовать 3d треугольник

направлен вверх,

как нарисовать 3d треугольник

направлен вправо, а

как нарисовать 3d треугольник

направлен на нас:

как нарисовать 3d треугольник


Воспользовавшись снова подобными треугольниками, мы получим

как нарисовать 3d треугольник

Уравнение проецирования


Давайте объединим всё вместе. При задании точки

как нарисовать 3d треугольник

в сцене и стандартных настроек камеры и окна просмотра, проекция

как нарисовать 3d треугольник

в окне просмотра, которую мы обозначим как

как нарисовать 3d треугольник

, можно вычислить следующим образом:

как нарисовать 3d треугольник

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Самое первое, что нужно здесь сделать — забыть о

как нарисовать 3d треугольник

; её значение по определению постоянно, а мы пытаемся перейти от 3D к 2D.


Теперь

как нарисовать 3d треугольник

по-прежнему остаётся точкой в пространстве; её координаты задаются в единицах, используемых для описания сцены, а не в пикселях. Преобразование из координат окна просмотра в координаты холста достаточно простое, и оно полностью противоположно преобразованию «холст-окно просмотра», которое мы использовали в части «Трассировка лучей»:

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Наконец мы можем перейти от точки в сцене к пикселю на экране!

Свойства уравнения проецирования


Уравнение проецирования обладает интересными свойствами, о которых стоит поговорить.


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

как нарисовать 3d треугольник

), тем правее он виден (

как нарисовать 3d треугольник

увеличивается). То же справедливо для

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

. Кроме того, чем дальше объект (увеличивается

как нарисовать 3d треугольник

), тем меньше он кажется (т.е.

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

уменьшаются).


Однако всё становится менее понятным при уменьшении значения

как нарисовать 3d треугольник

; при отрицательных значениях

как нарисовать 3d треугольник

, то есть когда объект находится за камерой, объект всё равно проецируется, но вверх ногами! И, разумеется, когда

как нарисовать 3d треугольник

, вселенная схлопывается. Нам как-то нужно избегать подобных неприятных ситуаций; пока мы будем считать, что каждая точка находится перед камерой, и справимся с этим в другой главе.


Ещё одним фундаментальным свойством перспективной проекции является то, что в ней сохраняется принадлежность точек к одной прямой; то есть проекции трёх точек, принадлежащих одной прямой, в окне просмотра тоже будут принадлежать одной прямой (Примечание: это наблюдение может казаться тривиальным, но стоит например заметить, что угол между двумя прямыми не сохраняется; мы видим, как параллельные линии «сходятся» к горизонту, как будто две стороны дороги.). Другими словами, прямая линия всегда выглядит как прямая.


Это имеет для нас очень непосредственную важность: пока мы говорили о проецировании точки, но как насчёт проецировании отрезка прямой или даже треугольника? Благодаря этому свойству проекция отрезка прямой будет отрезком прямой, соединяющимся с проекциями в конечных точках; следовательно, для проецирования полигона достаточно спроецировать его вершины и отрисовать получившийся полигон.


Поэтому мы можем двигаться дальше и отрисовать наш первый 3D-объект: куб. Мы задаём координаты его 8 вершин и отрисовываем линии между проекциями 12 пар вершин, составляющих рёбра куба:

  ViewportToCanvas(x, y) {      return (x*Cw/Vw, y*Ch/Vh);  }  ProjectVertex(v) {      return ViewportToCanvas(v.x * d / v.z, v.y * d / v.z)  # Четыре "передних" вершины.  vAf = [-1, 1, 1]  vBf = [1, 1, 1]  vCf = [1, -1, 1]  vDf = [-1, -1, 1]  # Четыре "задних" вершины.  vAb = [-1, 1, 2]  vBb = [1, 1, 2]  vCb = [1, -1, 2]  vDb = [-1, -1, 2]  # Передняя грань.  DrawLine(ProjectVertex(vAf), ProjectVertex(vBf), BLUE);  DrawLine(ProjectVertex(vBf), ProjectVertex(vCf), BLUE);  DrawLine(ProjectVertex(vCf), ProjectVertex(vDf), BLUE);  DrawLine(ProjectVertex(vDf), ProjectVertex(vAf), BLUE);  # Задняя грань.  DrawLine(ProjectVertex(vAb), ProjectVertex(vBb), RED);  DrawLine(ProjectVertex(vBb), ProjectVertex(vCb), RED);  DrawLine(ProjectVertex(vCb), ProjectVertex(vDb), RED);  DrawLine(ProjectVertex(vDb), ProjectVertex(vAb), RED);  # Рёбра, соединяющие переднюю и заднюю грани.  DrawLine(ProjectVertex(vAf), ProjectVertex(vAb), GREEN);  DrawLine(ProjectVertex(vBf), ProjectVertex(vBb), GREEN);  DrawLine(ProjectVertex(vCf), ProjectVertex(vCb), GREEN);  DrawLine(ProjectVertex(vDf), ProjectVertex(vDb), GREEN);


И мы получаем нечто подобное:

как нарисовать 3d треугольникИсходный код и рабочее демо >>


Хотя это и работает, у нас возникли серьёзные проблемы — что если мы хотим отрендерить два куба? Что если мы хотим отрендерить не куб, а что-то другое? Что если мы не знаем, что будем рендерить, пока программа не запущена — например, загружаем 3D-модель с диска? В следующей главе мы узнаем, как решать все эти вопросы.

Настройки сцены


Мы разработали техники для отрисовки треугольника на холсте по заданным координатам его вершин и уравнения для преобразования 3D-координат треугольника в 2D-координаты холста. В этой главе мы узнаем, как представить объекты, состоящие из треугольников, и как манипулировать ими.


Для этого мы используем куб; это не самый простой 3D-объект, который можно создать из треугольников, но он будет удобен для иллюстрации некоторых проблем. Рёбра куба имеют длину в две единицы и параллельны осям координат, а его центр находится в точке начала координат:

как нарисовать 3d треугольник


Вот координаты его вершин:

как нарисовать 3d треугольниккак нарисовать 3d треугольниккак нарисовать 3d треугольниккак нарисовать 3d треугольниккак нарисовать 3d треугольниккак нарисовать 3d треугольниккак нарисовать 3d треугольниккак нарисовать 3d треугольник


Стороны куба являются квадратами, однако мы знаем только как обращаться с треугольниками. Нет никаких проблем: любой полигон можно разложить на множество треугольников. Поэтому каждую сторону куба мы представим в виде двух треугольников.


Разумеется, не любое множество трёх вершин куба описывает треугольник на поверхности куба (например, AGH находится «внутри» куба), поэтому координат его вершин недостаточно для его описания; нам нужно также составить список треугольников, составленных из этих вершин:

A, B, CA, C, DE, A, DE, D, HF, E, HF, H, GB, F, GB, G, CE, F, BE, B, AC, G, HC, H, D


Это показывает, что есть структура, которую можно использовать для представления любого составленного из треугольников объекта: список координат вершин и список треугольников, определяющий, какое множество из трёх вершин образует треугольники объекта.


Каждая запись в списке треугольников может содержать дополнительную информацию о треугольниках; например, мы можем хранить в нём цвет каждого треугольника.


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

Vertexes0 = ( 1,  1,  1)1 = (-1,  1,  1)2 = (-1, -1,  1)3 = ( 1, -1,  1)4 = ( 1,  1, -1)5 = (-1,  1, -1)6 = (-1, -1, -1)7 = ( 1, -1, -1)Triangles 0 = 0, 1, 2, red 1 = 0, 2, 3, red 2 = 4, 0, 3, green 3 = 4, 3, 7, green 4 = 5, 4, 7, blue 5 = 5, 7, 6, blue 6 = 1, 5, 6, yellow 7 = 1, 6, 2, yellow 8 = 4, 5, 1, purple 9 = 4, 1, 0, purple10 = 2, 6, 7, cyan11 = 2, 7, 3, cyan


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

RenderObject(vertexes, triangles) {    projected = []    for V in vertexes {        projected.append(ProjectVertex(V))    }    for T in triangles {        RenderTriangle(T, projected)    }}RenderTriangle(triangle, projected) {    DrawWireframeTriangle(projected[triangle.v[0]],                          projected[triangle.v[1]],                          projected[triangle.v[2]],                          triangle.color)}


Мы не можем просто применить этот алгоритм к кубу, как есть, и надеяться на правильное отображение — некоторые из вершин находятся за камерой; а это, как мы уже видели, приводит к странному поведению. На самом деле, камера находится внутри куба.


Поэтому мы просто переместим куб. Чтобы сделать это, нам просто нужно сдвинуть каждую вершину куба в одном направлении. Давайте назовём этот вектор

как нарисовать 3d треугольник

, сокращённо от Translation. Давайте просто переместим куб на 7 единиц вперёд, чтобы он точно полностью был перед камерой, и на 1,5 единицы влево, чтобы он выглядел интереснее. Поскольку «вперёд» — это направление

как нарисовать 3d треугольник

, а «влево» —

как нарисовать 3d треугольник

, то вектор перемещения будет иметь следующий вид

как нарисовать 3d треугольник


Чтобы получить перемещённую версию

как нарисовать 3d треугольник

каждой точки

как нарисовать 3d треугольник

куба, нам нужно просто прибавить вектор перемещения:

как нарисовать 3d треугольник


На этом этапе мы можем взять куб, переместить каждую вершину, а затем применить приведённый выше алгоритм, чтобы получить наконец наш первый 3D-куб:

как нарисовать 3d треугольникИсходный код и рабочее демо >>

Модели и экземпляры


Но что если нам нужно отрендерить два куба?


Наивным подходом было бы создание ещё одного множества вершин и треугольников, описывающих второй куб. Это сработает, но займёт много памяти. А если мы захотим отрендерить миллион кубов?


Умнее будет думать в категориях моделей и экземпляров. Модель — это множество вершин и треугольников, описывающее объект как он есть (то есть "куб состоит из следующего множества вершин и треугольников"). С другой стороны, экземпляр модели — это конкретная реализация модели в некоторой позиции сцены (то есть "в (0, 0, 5) есть куб").


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


Вот грубое приближение того, как может быть описана подобная сцена:

model {    name = cube    vertexes {        ...    }    triangles {        ...    }}instance {    model = cube    position = (0, 0, 5)}instance {    model = cube    position = (1, 2, 3)}


Чтобы отрендерить её, нам нужно просто пройти по списку экземпляров; для каждого экземпляра создать копию вершин модели, применить к ним позицию экземпляра, а затем действовать как раньше:

RenderScene() {    for I in scene.instances {        RenderInstance(I);    }}RenderInstance(instance) {    projected = []    model = instance.model    for V in model.vertexes {        V' = V + instance.position        projected.append(ProjectVertex(V'))    }    for T in model.triangles {        RenderTriangle(T, projected)    }}


Заметьте, что для работы этого алгоритма координаты вершин модели должны быть определены в системе координат, «логичной» для объекта (это называется пространством модели). Например, куб определён таким образом, что его центр находится в (0, 0, 0); это значит, что когда мы говорим "куб расположен в (1, 2, 3)", мы имеем в виду "куб центрирован относительно (1, 2, 3)". При задании пространства модели нет никаких жёстких правил; в основном оно зависит от применения. Например, если у вас есть модель человека, то логично будет расположить точку начала координат у подошв его ног. Передвинутые вершины теперь будут выражаться в «абсолютной» системе координат сцены (называемой пространством мира).


Вот два куба:

как нарисовать 3d треугольникИсходный код и рабочее демо >>

Преобразование моделей


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


Концептуально, мы можем задать преобразование модели точно с этими тремя элементами: коэффициентом масштаба, поворотом относительно точки начала координат пространства модели и перемещения в определённую точку сцены:

instance {    model = cube    transform {        scale = 1.5        rotation = <45 degrees around the Y axis>        translation = (1, 2, 3)    }}


Можно с лёгкостью расширить предыдущую версию псевдокода, добавив новые преобразования. Однако важен порядок применения этих преобразований; в частности, перемещение необходимо выполнять последним. Вот поворот на

как нарисовать 3d треугольник

вокруг точки начала координат, за которым следует перемещение вдоль оси Z:

как нарисовать 3d треугольник


А вот перемещение, применённое до поворота:

как нарисовать 3d треугольник


Мы можем написать более общую версию

RenderInstance()

:

RenderInstance(instance) {    projected = []    model = instance.model    for V in model.vertexes {        V' = ApplyTransform(V, instance.transform);        projected.append(ProjectVertex(V'))    }    for T in model.triangles {        RenderTriangle(T, projected)    }}


Метод

ApplyTransform()

выглядит следующим образом:

ApplyTransform(vertex, transform) {    V1 = vertex * transform.scale    V2 = V1 * transform.rotation    V3 = V2 + transform.translation    return V3}


Поворот выражается как матрица 3x3; если вы не знакомы с матрицами поворота, то пока считайте, что любой 3D-поворот можно представить как произведение точки на матрицу 3x3. См. подробнее в курсе линейной алгебры.

Преобразование камеры


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


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


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


Теперь куб повернулся вокруг вас на

как нарисовать 3d треугольник

по часовой стрелке. Но так ли это? Возможно, это вы повернулись вокруг него на

как нарисовать 3d треугольник

против часовой стрелки? Мы снова не можем определить это.


Этот мысленный эксперимент показывает нам, что нет никакой разницы между перемещением камеры по фиксированной сцене и неподвижной камерой в движущейся и поворачивающейся вокруг неё сцене!


Преимущество такого очевидно эгоистичного видения вселенной заключается в том, что при фиксированной в точке начала координат камере, смотрящей в направлении

как нарисовать 3d треугольник

, мы можем без всяких изменений сразу же использовать уравнения проецирования, выведенные в предыдущей главе. Система координат камеры называется пространством камеры.


Будем считать, что у камеры тоже есть преобразование, состоящее из перемещения и поворота (масштаб мы опустим). Чтобы отрендерить сцену с точки обзора камеры, нам нужно применить к каждой вершине в сцене обратные преобразования:

V1 = V - camera.translationV2 = V1 * inverse(camera.rotation)V3 = perspective_projection(V2)

Матрица преобразований


Давайте сделаем шаг назад и разберёмся, что происходит с вершиной

как нарисовать 3d треугольник

в пространстве модели, пока она не будет спроецирована в точку на холсте

как нарисовать 3d треугольник

.


Сначала мы применяем преобразование модели, чтобы перейти из пространства модели в пространство мира:

V1 = V * instance.rotationV2 = V1 * instance.scaleV3 = V2 + instance.translation


Затем мы применяем преобразование камеры, чтобы перейти из пространства мира в пространство камеры:

V4 = V3 - camera.translationV5 = V4 * inverse(camera.rotation)


Затем мы применяем уравнения перспективы:

vx = V5.x * d / V5.zvy = V5.y * d / V5.z


И наконец мы привязываем координаты окна просмотра к координатам холста:

cx = vx * cw / vwcy = vy * ch / vh


Как вы видите, это довольно большой объём вычислений и для каждой вершины вычисляется множество промежуточных значений. Разве не будет удобно, если мы сократим всё это до единственного матричного произведения — возьмём

как нарисовать 3d треугольник

, умножим её на какую-нибудь матрицу и получим непосредственно

как нарисовать 3d треугольник

с

как нарисовать 3d треугольник

?


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

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

будут перемещением и поворотом камеры,

как нарисовать 3d треугольник

,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

— поворотом, масштабом и перемещением экземпляра,

как нарисовать 3d треугольник

— перспективной проекцией, а

как нарисовать 3d треугольник

— размещением окна просмотра на холсте. Если

как нарисовать 3d треугольник

— это исходная вершина, а

как нарисовать 3d треугольник

— точка на холсте, то мы можем выразить все вышеуказанные уравнения следующим образом:

как нарисовать 3d треугольник


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

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Нахождение одной матрицы, представляющей

как нарисовать 3d треугольник

, является нетривиальной задачей. Основная проблема заключается в том, что преобразования выражаются различными способами: перемещение — это сумма точки и вектора, поворот и масштаб — это произведение точки и матрицы 3x3, а в перспективной проекции используется деление. Но если мы сможем выразить все преобразования одним способом, и такой способ будет иметь простой механизм для создания преобразований, то мы получим то, что нам нужно.

Однородные координаты


Рассмотрим выражение

как нарисовать 3d треугольник

.

как нарисовать 3d треугольник

представляет собой 3D-точку или 3D-вектор? Нет никакого способа узнать это, не имея дополнительного контекста.


Но давайте примем следующую договорённость: мы добавим к представлению четвёртый компонент, называемый

как нарисовать 3d треугольник

. Если

как нарисовать 3d треугольник

, то мы говорим о векторе. Если

как нарисовать 3d треугольник

, то мы говорим о точке. То есть точка

как нарисовать 3d треугольник

недвусмысленно представляется в виде

как нарисовать 3d треугольник

, а вектор

как нарисовать 3d треугольник

представляется в виде

как нарисовать 3d треугольник

. Поскольку точки и векторы имеют общее представление, это называется однородными координатами (Примечание: однородные координаты имеют гораздо более глубокую и подробную геометрическую интерпретацию, но она не относится к тематике нашей статьи; здесь мы просто используем их как удобный инструмент с определёнными свойствами.).


Такое представление имеет большой геометрический смысл. Например, при вычитании двух точек получается вектор:

как нарисовать 3d треугольник


При сложении двух векторов получается вектор:

как нарисовать 3d треугольник


Аналогично, можно легко увидеть, что при суммировании точки и вектора мы получаем точку, умножение вектора на скаляр даёт вектор, и так далее.


А что же представляют собой координаты с

как нарисовать 3d треугольник

, не равным ни

как нарисовать 3d треугольник

, ни

как нарисовать 3d треугольник

? Они тоже представляют точки; на самом деле, любая точка в 3D имеет бесконечное количество представлений в однородных координатах. Важно соотношение между координатами и значением

как нарисовать 3d треугольник

; то есть,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

представляют одну и ту же точку, как

как нарисовать 3d треугольник

.


Из всех этих представлений мы можем назвать представление с

как нарисовать 3d треугольник

каноническим представлением точки в однородных координатах; преобразование любого другого представления к её каноническому представлению или в декартовы координаты — тривиальная задача:

как нарисовать 3d треугольник


То есть мы можем преобразовать декартовы координаты в однородные координаты, и обратно в декартовы координаты. Но как это поможет нам найти единое представление для всех преобразований?

Однородная матрица поворота


Давайте начнём с матрицы поворота. Выражение декартовой матрицы поворота 3x3 в однородных координатах тривиально; поскольку координата

как нарисовать 3d треугольник

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

как нарисовать 3d треугольник

, чтобы хранить значение

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник

Однородная матрица масштаба


Матрица масштабирования тоже тривиальна в однородных координатах, и она создаётся точно так же, как и матрица поворота:

как нарисовать 3d треугольник

Однородная матрица трансляции


Предыдущие примеры были простыми; они уже были представлены как умножения матриц в декартовых координатах, нам достаточно было добавить

как нарисовать 3d треугольник

, чтобы сохранить координату

как нарисовать 3d треугольник

. Но что нам делать с перемещением, которое мы выражали в декартовых координатах как сложение?


Нам нужна такая матрица 4x4, что

как нарисовать 3d треугольник


Давайте сначала сосредоточимся на получении

как нарисовать 3d треугольник

. Это значение — результат умножения первой строки матрицы на точку, то есть

как нарисовать 3d треугольник


Если мы раскроем векторное произведение, то получим

как нарисовать 3d треугольник


И из этого мы можем вывести, что

как нарисовать 3d треугольник

,

как нарисовать 3d треугольник

, а

как нарисовать 3d треугольник

.


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

как нарисовать 3d треугольник

Однородная матрица проецирования


Сумму и произведение можно просто выразить как произведения матриц и векторов, которые являются суммами и произведениями. Но в уравнениях перспективного проецирования используется деление на

как нарисовать 3d треугольник

. Как его выразить?


Есть большое искушение посчитать, что деление на

как нарисовать 3d треугольник

— это то же самое, что и умножение на

как нарисовать 3d треугольник

, что на самом деле правда; но в нашем случае это бесполезно, потому что координата

как нарисовать 3d треугольник

конкретной точки не может находиться в матрице проецирования, применяемой к каждой точке.


К счастью, в однородных координатах присутствует один случай деления: деление на координату

как нарисовать 3d треугольник

при обратном преобразовании в декартовы координаты. Так что есть нам удастся превратить координату

как нарисовать 3d треугольник

исходной точки в координату

как нарисовать 3d треугольник

«спроецированной» точки, то мы получим спроецированные

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

после преобразования точки обратно в декартовы координаты:

как нарисовать 3d треугольник


Заметьте, что эта матрица имеет размер

как нарисовать 3d треугольник

; её можно умножить на четырёхэлементный вектор (преобразованную 3D-точку в однородных координатах), получив при этом трёхэлементный вектор (спроецированную 2D-точку в однородных координатах), который затем преобразуется в двухмерные декартовы координаты делением на

как нарисовать 3d треугольник

. Это даст нам точные значения

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

, которые мы ищем.


Здесь не хватает

как нарисовать 3d треугольник

, которая, как мы знаем, по определению является

как нарисовать 3d треугольник

.


Используя рассуждения, похожие на те, которые мы применяли для выведения матрицы трансляции, мы можем выразить перспективную проекцию как

как нарисовать 3d треугольник

Однородная матрица из окна просмотра на холст


Последний этап — размещение спроецированной на окно просмотра точки на холст. Это просто двухмерное преобразование масштаба с

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

. То есть матрица будет следующей

как нарисовать 3d треугольник


На самом деле её легко скомбинировать с матрицей проецирования и получить простую матрицу преобразования из 3D в холст:

как нарисовать 3d треугольник

Практическое применение


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

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Это позволит нам выполнить ещё и другие операции в 3D до проецирования точек, которые нельзя выразить как матричные преобразования.

Снова матрица преобразования


Так как теперь мы можем выразить любое 3D-преобразование исходной вершины

как нарисовать 3d треугольник

, выполняемое до проецирования как матрицы 4x4, мы можем тривиально объединить все эти преобразования в единую матрицу 4x4, перемножив их:

как нарисовать 3d треугольник


И тогда преобразование вершины — просто вопрос вычисления следующего произведения:

как нарисовать 3d треугольник


Более того, мы можем разложить преобразование на две части:

как нарисовать 3d треугольник

как нарисовать 3d треугольник

как нарисовать 3d треугольник


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

как нарисовать 3d треугольник

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

как нарисовать 3d треугольник

зависит от преобразования экземпляра модели, и поэтому используемая матрица будет меняться только один раз для объекта в сцене; однако она будет оставаться постоянной для неподвижных объектов (например, деревьев, зданий), поэтому её можно вычислить заранее и хранить в самой сцене. Для подвижных объектов (например, для машин в гоночной игре) она всё равно должна вычисляться каждый раз, когда они двигаются (обычно в каждом кадре).


На очень высоком уровне псевдокод рендеринга сцены будет выглядеть так:

RenderModel(model, transform) {    projected = []    for V in model.vertexes {        projected.append(ProjectVertex(transform * V))    }    for T in model.triangles {        RenderTriangle(T, projected)    }}RenderScene() {    MCamera = MakeCameraMatrix(camera.position, camera.orientation)    for I in scene.instances {        M = MCamera*I.transform        RenderModel(I.model, M)    }}


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

как нарисовать 3d треугольникИсходный код и рабочее демо >>


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


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

Отсечение


В главе Перспективная проекция мы получили следующие уравнения:

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Деление на

как нарисовать 3d треугольник

вызывает проблемы; при нём может возникнуть деление на ноль. Также при нём могут получаться отрицательные значения, представляющие точки за камерой, которые обрабатываются неправильно. Даже точки, находящиеся перед камерой, но очень близко, могут вызывать проблемы в виде сильно искажённых объектов.


Чтобы избежать всех этих проблемных случаев, мы решили не рендерить ничего за плоскость проекции

как нарисовать 3d треугольник

. Эта плоскость отсечения позволяет разделить все точки на находящиеся внутри или снаружи объёма отсечения, то есть подмножества пространства, которое на самом деле видно из камеры. В этом случае объём отсечения — это "полупространство перед

как нарисовать 3d треугольник

". Мы рендерим только части сцены, которые находятся внутри объёма отсечения.


Чем меньше операций мы делаем, тем быстрее будет наш рендерер, поэтому мы используем подход «сверху вниз». Рассмотрим сцену с несколькими объектами, каждый из которых состоит из четырёх треугольников.

как нарисовать 3d треугольник


На каждом этапе мы стремимся как можно менее затратно определить, можно ли остановить отсечение на этой точке, или требуется дальнейшее и более подробное отсечение:

как нарисовать 3d треугольниккак нарисовать 3d треугольниккак нарисовать 3d треугольник


Теперь мы подробноее рассмотрим каждый этап в процессе выполнения.

Задание плоскостей отсечения


Первое, что нужно сделать — найти уравнение плоскости отсечения. Нет ничего плохого в

как нарисовать 3d треугольник

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


Общее уравнение 3D-плоскости имеет вид

как нарисовать 3d треугольник

. Оно означает, что точка

как нарисовать 3d треугольник

будет удовлетворять уравнению тогда и только тогда, когда

как нарисовать 3d треугольник

находится на плоскости. Мы можем переписать уравнение как

как нарисовать 3d треугольник

, где

как нарисовать 3d треугольник

.


Заметьте, что если

как нарисовать 3d треугольник

, то

как нарисовать 3d треугольник

при любом значении

как нарисовать 3d треугольник

. В частности, мы можем выбрать

как нарисовать 3d треугольник

и получить новое уравнение

как нарисовать 3d треугольник

, где

как нарисовать 3d треугольник

— единичный вектор. То есть для любой заданной плоскости мы можем считать, что существует единичный вектор

как нарисовать 3d треугольник

и вещественное число

как нарисовать 3d треугольник

такие, что

как нарисовать 3d треугольник

является уравнением этой плоскости.


Это очень удобная формулировка:

как нарисовать 3d треугольник

на самом деле является нормалью плоскости, а

как нарисовать 3d треугольник

— расстояние со знаком от точки начала координат до плоскости. На самом деле, для любой точки

как нарисовать 3d треугольник как нарисовать 3d треугольник

является расстоянием со знаком от

как нарисовать 3d треугольник

до плоскости; легко увидеть, что

как нарисовать 3d треугольник

— это особый случай, при котором

как нарисовать 3d треугольник

лежит на плоскости.


Как мы видели ранее, если

как нарисовать 3d треугольник

— это нормаль к плоскости, как и

как нарисовать 3d треугольник

, поэтому мы выбираем

как нарисовать 3d треугольник

такую, что она направлена «внутрь» объёма отсечения. Для плоскости

как нарисовать 3d треугольник

мы выбираем нормаль

как нарисовать 3d треугольник

, которая направлена «вперёд» относительно камеры. Поскольку точка

как нарисовать 3d треугольник

лежит на плоскости, она должна удовлетворять уравнению плоскости, мы можем вычислить её, зная

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник


то есть

как нарисовать 3d треугольник

(Примечание: можно было тривиально получить это из

как нарисовать 3d треугольник

, переписав его как

как нарисовать 3d треугольник

. Однако представленные здесь рассуждения относятся и ко всем остальным плоскостям, с которыми мы будем иметь дело, и это позволяет нам справиться с тем, что

как нарисовать 3d треугольник

тоже справедливо, но нормаль направлена в неправильном направлении.).

Объём отсечения


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

как нарисовать 3d треугольник


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


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

как нарисовать 3d треугольник


Все эти плоскости имеют

как нарисовать 3d треугольник

(потому что точка начала координат находится на всех плоскостях), поэтому нам остаётся только определить нормали. Простейшим случаем будет FOV

как нарисовать 3d треугольник

, при которой плоскости находятся на

как нарисовать 3d треугольник

, поэтому их нормали

как нарисовать 3d треугольник

для левой плоскости,

как нарисовать 3d треугольник

для правой плоскости,

как нарисовать 3d треугольник

для нижней и

как нарисовать 3d треугольник

для верхней плоскостей. Для вычисления плоскостей отсечения для любой произвольной FOV требует только небольшого количества тригонометрических вычислений.


Для отсечения объектов или треугольников по объёму отсечения нам достаточно отсечь их по порядку каждой плоскостью. Все объекты, «выжившие» после отсечения одной плоскостью, отсекаются остальными плоскостями; это срабатывает, потому что объём отсечения является пересечением полупространств, задаваемых каждой плоскостью отсечения.

Отсечение целых объектов


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


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

как нарисовать 3d треугольник

и радиус

как нарисовать 3d треугольник

сферы, которая полностью содержит каждый объект:

как нарисовать 3d треугольник


Мы можем разбить пространственные отношения между сферой и плоскостью на следующие категории:

как нарисовать 3d треугольниккак нарисовать 3d треугольниккак нарисовать 3d треугольник


Как же на самом деле выполняется это разбиение на категории? Мы выбрали способ выражения плоскостей отсечения таким образом, что подстановка любой точки в уравнение плоскости даёт нам расстояние со знаком от точки до плоскости; в частности, мы можем вычислить расстояние со знаком

как нарисовать 3d треугольник

от центра ограничивающей сферы до плоскости. Поэтому если

как нарисовать 3d треугольник

, то сфера находится перед плоскостью; если

как нарисовать 3d треугольник

, то сфера находится за плоскостью; в противном случае

как нарисовать 3d треугольник

, то есть плоскость пересекается со сферой.

как нарисовать 3d треугольник

Отсечение треугольников


Если проверки сфера-плоскость недостаточно для определения того, находится ли объект полностью перед или полностью за плоскостью отсечения, то необходимо отсечь относительно неё каждый треугольник.


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

как нарисовать 3d треугольник


Существует четыре возможных случая:

как нарисовать 3d треугольниккак нарисовать 3d треугольник

Пересечение отрезка и плоскости


Чтобы выполнить отсечение для каждого треугольника, нам нужно вычислить пересечение сторон треугольника с плоскостью отсечения. Надо заметить, что недостаточно вычислить координаты пересечения: необходимо также вычислить соответствующее значение атрибутов, связанных с вершинами, например, затенения, которое мы делали в главе Отрисовка затенённых треугольников, или одного из атрибутов, описанных в последующих главах.


У нас есть плоскость отсечения, заданная уравнением

как нарисовать 3d треугольник

. Сторону треугольника

как нарисовать 3d треугольник

можно выразить с помощью параметрического уравнения как

как нарисовать 3d треугольник

при

как нарисовать 3d треугольник

. Для вычисления значения параметра

как нарисовать 3d треугольник

, при котором происходит пересечение, мы заменим

как нарисовать 3d треугольник

в уравнении плоскости на параметрическое уравнение отрезка:

как нарисовать 3d треугольник


Воспользовавшись линейными свойствами скалярного произведения, получаем:

как нарисовать 3d треугольник


Вычисляем

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник


Мы знаем, что решение существует всегда, потому что

как нарисовать 3d треугольник

пересекает плоскость; математически

как нарисовать 3d треугольник

не может быть нулём, потому что это будет подразумевать, что отрезок и нормаль перпендикулярны, что в свою очередь подразумевает, что отрезок и плоскость не пересекаются.


Вычислив

как нарисовать 3d треугольник

, мы получим, что пересечение

как нарисовать 3d треугольник

просто равно

как нарисовать 3d треугольник


Заметьте, что

как нарисовать 3d треугольник

— это часть отрезка

как нарисовать 3d треугольник

, в которой произошло пересечение. Пусть

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

будут значениями некоего атрибута

как нарисовать 3d треугольник

в точках

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

; если мы будем считать, что атрибут линейно изменяется вдоль

как нарисовать 3d треугольник

, то

как нарисовать 3d треугольник

можно просто вычислить как

как нарисовать 3d треугольник

Отсечение в конвейере


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


Отсечение — это 3D-операция; она получает два 3D-объекта в сцене и генерирует новое множество 3D-объектов в сцене, а именно, пересечение сцены и объёма отсечения. Должно быть понятно, что отсечение должно выполняться после того, как объекты были размещены в сцене (то есть использованы вершины после преобразований модели и камеры), но перед перспективным проецированием.


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

Удаление скрытых поверхностей


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


Очевидным первым шагом будет придание сплошным объектам сплошного внешнего вида. Для этого давайте используем

DrawFilledTriangle()

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

как нарисовать 3d треугольник


Не очень похоже на кубы, правда?


Проблема здесь в том, что некоторые треугольники, которые должны быть за другими, отрисовываются перед ними. Почему? Потому что мы просто отрисовываем 2D-треугольники на холсте практически в случайном порядке — в том порядке, который получился при задании модели.


Однако при задании треугольников модели нет «правильного» порядка. Предположим, что треугольники модели отсортированы таким образом, что сначала отрисовываются задние грани, а затем они перекрываются передними гранями. Мы получим ожидаемый результат. Однако если мы повернём куб на

как нарисовать 3d треугольник

, то получим обратную ситуацию — дальние треугольники будут перекрывать ближние.

Алгоритм художника


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


Хотя при этом треугольники отрисуются в правильном порядке, этот алгоритм имеет недостатки, делающие его непрактичным.


Во-первых, он не очень хорошо масштабируется. Самый лучший алгоритм сортировки имеет скорость

как нарисовать 3d треугольник

\), то есть время выполнения более чем удваивается при удвоении количества треугольников. Другими словами, он работает для небольших сцен, но быстро становится «узким местом» при увеличении сложности сцены.


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


В-третьих, даже если вы смиритесь с этими ограничениями, то всё равно существуют случаи, когда правильного порядка треугольников не существует. Рассмотрим следующий случай:

как нарисовать 3d треугольник


Неважно, в каком порядке вы будете отрисовывать эти треугольники — вы всегда будете получать неверный результат.

Буфер глубин


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


В сущности, каждый пиксель холста мы хотим закрасить «правильным» цветом. В этом случае, «правильный» цвет — это цвет ближайшего к камере объекта (в нашем случае

как нарисовать 3d треугольник

):

как нарисовать 3d треугольник


Оказывается, что мы можем запросто это сделать. Предположим, что мы храним значение

как нарисовать 3d треугольник

точки, в настоящее время представленной каждым пикселем холста. Когда мы решаем, стоит ли закрашивать пиксель определённым цветом, мы поступаем так только когда координата

как нарисовать 3d треугольник

точки, которую мы собираемся закрашивать, меньше координаты

как нарисовать 3d треугольник

точки, которая там уже есть.


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

как нарисовать 3d треугольник

, а потом

как нарисовать 3d треугольник

. Пиксель закрашен красным, его

как нарисовать 3d треугольник

помечена как

как нарисовать 3d треугольник

. Затем мы закрашиваем

как нарисовать 3d треугольник

, и поскольку

как нарисовать 3d треугольник

, пиксель перезаписывается синим цветом; мы получаем верные результаты.


Разумеется, мы получили верный результат вне зависимости от значений

как нарисовать 3d треугольник

. Что если мы хотели сначала закрасить

как нарисовать 3d треугольник

, а потом

как нарисовать 3d треугольник

? Пиксель сначала закрасился синим, а

как нарисовать 3d треугольник

сохранилась; но затем мы хотим закрасить

как нарисовать 3d треугольник

, и поскольку

как нарисовать 3d треугольник

, мы не будем его закрашивать (потому что если бы это сделали, то закрасили бы удалённую точку, закрыв более близкую). Мы снова получаем синий пиксель, что является верным результатом.


С точки зрения реализации, нам нужен буфер для хранения координаты

как нарисовать 3d треугольник

каждого пикселя на холсте; он называется буфером глубин, и его размеры естественно равны размерам холста.


Но откуда появляются значения

как нарисовать 3d треугольник

?


Они должны быть значениями

как нарисовать 3d треугольник

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

как нарисовать 3d треугольник

.


Итак, мы можем получить значения

как нарисовать 3d треугольник

из этих значений

как нарисовать 3d треугольник

. Но у нас есть это значение только для вершин; нам нужно получить его для каждого пикселя.


И это ещё один способ применения алгоритма присвоения атрибутов. Почему бы не использовать

как нарисовать 3d треугольник

в качестве атрибута и не интерполировать его вдоль грани треугольника? Вы уже знаете процедуру; берём значения

Z0

,

Z1

и

Z2

, вычисляем

Z01

,

Z02

и

Z02

, получаем из них

z_left

и

z_right

, а затем вычисляем

z_segment

для каждого пикселя каждого горизонтального отрезка. И вместо выполнения вслепую

PutPixel(x, y, color)

мы делаем следующее:

z = z_segment[x - xl]if (z < depth_buffer[x][y]) {    canvas.PutPixel(x, y, color)    depth_buffer[x][y] = z}


Чтобы это сработало,

depth_buffer

должен быть инициализирован значениями

как нарисовать 3d треугольник

(или просто «очень большим значением»).


Получаемые результаты теперь гораздо лучше:

как нарисовать 3d треугольникИсходный код и рабочее демо >>

Почему 1/Z вместо Z


Но на этом история не заканчивается. Значения

как нарисовать 3d треугольник

в вершинах верны (в конце концов, они получаются из данных), но в большинстве случаев линейно интерполированные значения

как нарисовать 3d треугольник

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


Чтобы проверить, насколько неверны значения, рассмотрим простой случай прямой из

как нарисовать 3d треугольник

в

как нарисовать 3d треугольник

. Середина отрезка

как нарисовать 3d треугольник

имеет координаты

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник


Давайте вычислим проекцию этих точек при

как нарисовать 3d треугольник

.

как нарисовать 3d треугольник

. Аналогично,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник


Что теперь произойдёт, если мы линейно проинтерполируем значения

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

для получения вычисленного значения для

как нарисовать 3d треугольник

? Линейная функция выглядит так:

как нарисовать 3d треугольник


Из этого мы можем заключить, что

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Если мы подставим числа и выполним арифметические вычисления, то получим

как нарисовать 3d треугольник


что очевидно не равно

как нарисовать 3d треугольник

.


Так в чём же проблема? Мы используем присвоение атрибутов, которое, как мы знаем, работает хорошо; мы передаём ему верные значения, которые получаются из данных; так почему же результаты неверны?


Проблема в том, что мы неявно подразумеваем, выполняя линейную интерполяцию: что интерполируемая нами функция линейна. А в нашем случае это не так!


Если

как нарисовать 3d треугольник

была бы линейной функцией

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

, мы могли бы записать её как

как нарисовать 3d треугольник

для некоторого значения

как нарисовать 3d треугольник

,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

. Такой тип функций имеет следующее свойство: разность его значения между двумя точками зависит от разности между точками, а не от самих точек:

как нарисовать 3d треугольник

как нарисовать 3d треугольник

как нарисовать 3d треугольник


То есть для заданной разности экранных координат разность

как нарисовать 3d треугольник

всегда будет одинаковой.


Более формально, уравнение плоскости, содержащей изучаемый нами треугольник, имеет вид

как нарисовать 3d треугольник


С другой стороны, у нас есть уравнения перспективной проекции:

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Мы можем снова получить из них

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Если мы заменим

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

в уравнении плоскости этими выражениями, то получим

как нарисовать 3d треугольник


Умножив на

как нарисовать 3d треугольник

и выразив

как нарисовать 3d треугольник

, получим

как нарисовать 3d треугольник

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Что очевидно не является линейной функцией

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

.


Однако, если мы просто вычислим

как нарисовать 3d треугольник

, то получим

как нарисовать 3d треугольник


Что очевидно является линейной функцией от

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

.


Чтобы показать, что это действительно работает, вот приведённый выше пример, но на этот раз вычисленный с помощью линейной интерполяции

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник

как нарисовать 3d треугольник

как нарисовать 3d треугольник


И следовательно

как нарисовать 3d треугольник


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


Всё это значит, что для буферизации глубин мы должны вместо значений

как нарисовать 3d треугольник

использовать значения

как нарисовать 3d треугольник

. Единственной практической разницей в псевдокоде будет то, что буфер должен инициализироваться значениями

как нарисовать 3d треугольник

(то есть

как нарисовать 3d треугольник

), а сравнение необходимо перевернуть (сохраняем большее значение

как нарисовать 3d треугольник

, соответствующее меньшему значению

как нарисовать 3d треугольник

).

Отсечение задних граней


Буферизация глубин даёт нам нужные результаты. Но можем ли мы добиться того же более быстрым способом?


Вернёмся к кубу: даже если каждый пиксель в результате получает правильный цвет, некоторые из них перерисовываются снова и снова несколько раз. Например, если задняя грань куба рендерится до передней грани, то многие пиксели будут закрашиваться дважды. С увеличением количества операций, выполняемых для каждого пикселя (пока мы вычисляем для каждого пикселя только

как нарисовать 3d треугольник

, но скоро добавим освещение, например), вычисление пикселей, которые никогда не окажутся видимыми, становится всё более и более затратным.


Можем ли мы заранее отбросить пиксели, прежде чем выполнять все эти вычисления? Оказывается, мы можем отбрасывать целые треугольники ещё до того, как начнём отрисовку!


До этого момента мы говорили о передних гранях и задних гранях неформально. Представьте, что у каждого треугольника есть две стороны; одновременно мы можем видеть только одну из сторон треугольника. Чтобы разделить эти две стороны, мы добавим к каждому треугольнику стрелку, перпендикулярную его поверхности. Затем мы возьмём куб и убедимся, что каждая стрелка направлена наружу:

как нарисовать 3d треугольник


Теперь эта стрелка позволит нам классифицировать каждый треугольник как «передний» и «задний», в зависимости от того, направлен ли он к камере или от неё; если более формально, то если вектор просмотра и эта стрелка (на самом деле являющаяся вектором нормали треугольника) образуют угол соответственно меньше или больше

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник


С другой стороны, наличие одинаково ориентированных двусторонних треугольников, позволяет нам задать то, что находится «внутри» и «снаружи» замкнутого объекта. По определению мы не должны видеть внутренние части замкнутого объекта. Это значит, что у любого замкнутого объекта вне зависимости от расположения камеры передние грани полностью перекрывают задние.


Что в свою очередь означает, что нам вообще не нужно отрисовывать задние грани, потому что они всё равно будут перерисовываться передними гранями!

Классификация треугольников


Давайте формализуем и реализуем это. Допустим, у нас есть вектор нормали треугольника

как нарисовать 3d треугольник

и вектор

как нарисовать 3d треугольник

из вершины треугольника к камере. Пусть

как нарисовать 3d треугольник

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

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

, после чего проверим, находятся ли они в

как нарисовать 3d треугольник

относительно друг друга.


Мы снова можем воспользоваться свойствами скалярного произведения, чтобы ещё больше это упростить. Не забывайте, что если мы обозначим за

как нарисовать 3d треугольник

угол между

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

, то

как нарисовать 3d треугольник


Поскольку

как нарисовать 3d треугольник

неотрицателен при

как нарисовать 3d треугольник

, для классификации грани как передней или задней нам достаточно только знать его знак. Стоит заметить, что

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

всегда положительны, поэтому они не влияют на знак выражения. Следовательно

как нарисовать 3d треугольник


То есть классификация будет очень простой:

как нарисовать 3d треугольникЗадняя грань
как нарисовать 3d треугольникПередняя грань


Пограничный случай

как нарисовать 3d треугольник

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


Откуда мы берём вектор нормали? Оказывается, существует векторная операция — векторное произведение

как нарисовать 3d треугольник

, получающая два вектора

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

и дающая в результате перпендикулярный им вектор. Мы можем запросто получить два вектора, копланарные треугольнику, вычтя его вершины из друг друга, то есть вычисление направления вектора нормали треугольника

как нарисовать 3d треугольник

будет простой операцией:

как нарисовать 3d треугольник

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Заметьте, что я сказал «направление вектора нормали», а не «вектор нормали». Для этого есть две причины. Первая заключается в том, что

как нарисовать 3d треугольник

не обязательно равен

как нарисовать 3d треугольник

. Это не очень важно, потому что нормализация

как нарисовать 3d треугольник

будет тривиальной операцией, и потому что нас волнует только знак

как нарисовать 3d треугольник

.


Но вторая причина заключается в том, что если

как нарисовать 3d треугольник

— это вектор нормали

как нарисовать 3d треугольник

, то им является и

как нарисовать 3d треугольник

!


Разумеется, в этом случае нам очень важно, в каком направлении указывает

как нарисовать 3d треугольник

, потому что именно это позволяет нам классифицировать треугольники как передние или задние. А векторное произведение не коммутативно; в частности,

как нарисовать 3d треугольник

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


Хотя векторное произведение не является коммутативным, оно и не случайно, конечно же.

Система координат, которую мы всё время использовали (X вправо, Y вверх, Z вперёд), называется левосторонней, потому что можно направить большой, указательный и средний палец левой руки в этих направлениях (большой палец вверх, указательный вперёд, средний вправо). Правосторонняя система координат похожа на неё, но указательный палец правой руки указывает влево.

Затенение


Давайте продолжим добавлять «реализма» сцене; в этой главе мы изучим, как добавить в сцену источники освещения и как осветить содержащиеся в ней объекты.


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


В главе Освещение раздела Трассировка лучей я уже рассказал всё необходимое, что нужно знать об освещении. Мы можем задать окружающее, точечное и направленное освещение; вычисление освещённости любой точки в сцене при заданной позиции и нормали поверхности в этой точке выполняется одинаковым способом и в трассировщике лучей, и в растеризаторе; теория точно такая же.


Более интересная часть, которую мы изучим в этой главе, заключается в том, как взять эту "освещённость в точке" и заставить её работать для объектов, состоящих из треугольников.

Плоское затенение


Давайте начнём с простого. Поскольку мы можем вычислить освещённость в точке, давайте просто выберем любую точку в треугольнике (скажем, его центр), вычислим там освещение и используем значение освещённости для затенения всего треугольника (для выполнения действительного затенения мы можем умножить цвет треугольника на значение освещённости):

как нарисовать 3d треугольник


Не так уж плохо. И очень просто увидеть, почему так случилось. Каждая точка в треугольнике имеет одну и ту же нормаль, и пока источник освещения достаточно далеко, векторы света приблизительно параллельны, то есть каждая точка получает примерно равное количество освещения. Это примерно объясняет различия между двумя треугольниками, из которых состоит каждая сторона куба.


Но что произойдёт, если мы возьмём объект, у которого каждая точка имеет свою нормаль?

как нарисовать 3d треугольник


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

Затенение по Гуро


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

как нарисовать 3d треугольник

до

как нарисовать 3d треугольник

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


Это называется затенением по Гуро по имени Анри Гуро, придумавшего эту идею в 1971 году. Вот результаты его применения к кубу и сфере:

как нарисовать 3d треугольник


Куб выглядит немного лучше; неравномерность теперь пропала, потому что оба треугольника каждой стороны имеют две общие вершины, и разумеется освещённость для них обеих вычисляется совершенно одинаково.


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

как нарисовать 3d треугольник


Давайте сделаем шаг назад. То, что мы используем плоские треугольники для представления изогнутого объекта, ограничивает наши техники, но не свойство самого объекта.


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

как нарисовать 3d треугольник


Однако это не относится к кубу; даже несмотря на то, что треугольники имеют общие позиции вершин, каждую грань нужно затенять независимо от остальных. У вершин куба нет единственной «верной» нормали.


Как же решить эту дилемму? Проще, чем кажется. Вместо вычисления нормалей треугольников, мы сделаем их частью модели; таким образом, разработчик объекта может использовать нормали для описания кривизны поверхности (или её отсутствия). Также, чтобы учесть случай куба и других поверхностей с плоскими гранями, мы сделаем нормали вершин свойством вершины в треугольнике, а не самой вершины:

model {    name = cube    vertexes {        0 = (-1, -1, -1)        1 = (-1, -1, 1)        2 = (-1, 1, 1)        ...    }    triangles {        0 = {            vertexes = [0, 1, 2]            normals = [(-1, 0, 0), (-1, 0, 0), (-1, 0, 0)]        }        ...    }}


Вот сцена, отрендеренная с помощью затенения Гуро при соответствующих нормалях вершин:

как нарисовать 3d треугольник


Куб по-прежнему выглядит как куб, а сфера теперь выглядит гораздо более похожей на сферу. На самом деле, взглянув на её контур, можно определить, что она составлена из треугольников (эту проблему можно решить использованием большего количества мелких треугольников, потратив больше вычислительной мощности).


Однако иллюзия разрушается, когда мы пытаемся рендерить блестящие объекты; зеркальный засвет на сфере потрясающе нереалистичный.


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

как нарисовать 3d треугольник


Что здесь происходит: несмотря на то, что мы ожидаем, что точки рядом с центром треугольника получат больше освещения (потому что

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

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

как нарисовать 3d треугольник

Затенение по Фонгу


Ограничения затенения по Гуро легко преодолеть, но как обычно существует компромисс между качеством и затрачиваемыми ресурсами.


При плоском затенении использовалось единственное вычисление освещения на треугольник. Для затенения по Гуро требовалось три вычисления освещения на треугольник плюс интерполяция единственного атрибута (освещённости) по треугольнику. Следующим шагом в этом увеличении качества и затрат на пиксель будет вычисление освещения для каждого пикселя треугольника.


Это не кажется особо сложным с точки зрения теории; в конце концов, мы уже вычисляли освещение для трёх точек, и вычисляли попиксельное освещение для трассировщика лучей. Но хитрость здесь в том, чтобы выяснить, откуда берутся входные данные для уравнения освещённости.

Нам нужен

как нарисовать 3d треугольник

. При направленном источнике освещения

как нарисовать 3d треугольник

задан. Для точечного источника освещения

как нарисовать 3d треугольник

задаётся как вектор из точки сцены

как нарисовать 3d треугольник

в позицию источника освещения

как нарисовать 3d треугольник

. Однако, у нас нет

как нарисовать 3d треугольник

для каждого пикселя треугольника, а есть только для вершин.


У нас есть проекция

как нарисовать 3d треугольник

— то есть

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

, которые мы собираемся отрисовать на холсте! Мы знаем, что

как нарисовать 3d треугольник

как нарисовать 3d треугольник


а также у нас есть интерполированное, но геометрически верное значение для

как нарисовать 3d треугольник

как часть алгоритма буферизации глубин, поэтому

как нарисовать 3d треугольник

как нарисовать 3d треугольник


Поэтому мы можем получить из этих значений

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник

как нарисовать 3d треугольник

как нарисовать 3d треугольникНам нужен

как нарисовать 3d треугольник

. Это тривиально, потому что мы вычисляем

как нарисовать 3d треугольник

так, как объяснено выше, потому что позиция камеры известна.

Нам нужен

как нарисовать 3d треугольник

. У нас пока есть нормали только в вершинах. Когда у тебя в руках молоток, все задачи похожи на гвозди, а наш молоток — это линейная интерполяция значений атрибута! Мы можем взять значения

как нарисовать 3d треугольник

,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

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


Эта техника называется затенением по Фонгу по имени Буи Тьена Фонга, придумавшего её в 1973 году. Вот её результаты:

как нарисовать 3d треугольникИсходный код и рабочее демо >>


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


Это также решает проблему с приближением источника к грани, теперь мы получаем ожидаемые результаты:

как нарисовать 3d треугольник


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

как нарисовать 3d треугольник


А вот версия с трассировкой лучей для справки:

как нарисовать 3d треугольник


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

Текстуры


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


Рассмотрим деревянный ящик. Как превратить куб в деревянный ящик? Один из вариантов — добавить множество треугольников, поссоздающих структуру дерева, шляпки гвоздей, и так далее. Это сработает, но из-за геометрическая сложность сцены сильно повысится, что повлияет на производительность.


Ещё один вариант — имитировать ящик: взять плоскую поверхность куба и просто нарисовать поверх неё что-то, напоминающее древесину. Если не приглядываться к ящику, то вы никогда не заметите разницы.


Мы воспользуемся вторым подходом. Во-первых, нам понадобится изображение, которое мы будем рисовать на поверхности; в этом контексте мы назовём это изображение текстурой, хотя это и противоположно тому, что мы называем текстурой объекта — грубый он или мягкий, и т.д… Вот текстура «деревянного ящика»:

как нарисовать 3d треугольникТекстура Filter Forge — Attribution 2.0 Generic (CC BY 2.0)


Во-вторых, нам нужно указать, как текстура должна накладываться на модель. Мы можем задать наложение для каждого треугоьника, указав точки текстуры, накладываемые на каждую вершину треугольника:

как нарисовать 3d треугольник


Стоит заметить, что без проблем можно деформировать текстуру или использовать только части текстуры, меняя координаты текстуры для каждой вершины.


Чтобы задать это наложение, мы используем систему координат, определяющую точки этой текстуры; назовём эти координаты

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

, чтобы не путать их с

как нарисовать 3d треугольниккак нарисовать 3d треугольник

, которые обычно обозначают пиксели на холсте. Мы также объявим, что

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

являются вещественными значениями в интервале

как нарисовать 3d треугольник

вне зависимости от разрешения изображения текстуры в пикселях. Это очень удобно по нескольким причинам; например, в зависимости от доступного объёма ОЗУ можно использовать текстуры более низкого или высокого разрешения, не меняя саму модель.


Основная идея наложения текстур проста: вычисляем координаты

как нарисовать 3d треугольник

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

как нарисовать 3d треугольник

в текстуре размером

как нарисовать 3d треугольник

накладывается на тексел в

как нарисовать 3d треугольник

.


Но у нас есть только координаты

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

для трёх вершин треугольника, а они необходимы для каждого пикселя… и наверно вы уже видите, что должно произойти. Да, линейная интерполяция. Мы используем присвоение атрибутов для интерполяции значений

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

по грани треугольника, что даст нам

как нарисовать 3d треугольник

в каждом пикселе; мы закрасим пиксель соответствующим цветом, взятым из текстуры (возможно, с воздействием освещение), и получим…

как нарисовать 3d треугольник


…заурядные результаты. Ящики выглядят вполне неплохо, но если присмотреться к диагональным доскам, то становится очевидно, что они немного деформированы.


В чём же ошибка?


Мы снова попались в ловушку неверного предположения; мы считаем, что

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

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

как нарисовать 3d треугольник

меняется линейно вместе с

как нарисовать 3d треугольник

, то это будет неверно:

как нарисовать 3d треугольник


Ситуация очень похожа на ту, которая встречалась нам в главе Буферизация глубин, и решение тоже очень похоже: хотя

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

нелинейны в экранных координатах,

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

линейны (Примечание: доказательство этого очень похоже на доказательство

как нарисовать 3d треугольник

: примем, что

как нарисовать 3d треугольник

линейно изменяется в 3D-пространстве, и заменим

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

на их выражения в экранном пространстве.). Поскольку мы уже интерполировали значения

как нарисовать 3d треугольник

для каждого пикселя, то достаточно интерполировать

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

, чтобы получить

как нарисовать 3d треугольник

и

как нарисовать 3d треугольник

:

как нарисовать 3d треугольник

как нарисовать 3d треугольник


При этом мы получим ожидаемые результаты:

как нарисовать 3d треугольникИсходный код и рабочее демо >>

http://mirpozitiva.ru/articles/1894-kak-narisovat-3d-risunok...

как нарисовать 3d треугольникНа сегодняшний день все популярнее становятся 3d рисунки на бумаге, в них можно долго всматриваться и любоваться. Создавать такие шедевры могут не только талантливые художники, но и те, кто только знакомится с изобразительным искусством. Научится рисовать никогда не поздно, сделать эффектные 3d рисунки сможет каждый.Инструменты, которые потребуются для 3d, самые простые: ручка, карандаши, маркер и листок бумаги. Кстати, рисовать новичкам лучше всего по клеткам в тетради, так изображать фигуры намного проще.Стоит отметить, что изображение создается на бумаге поэтапно, в этом деле главное – последовательность, даже если воспроизводятся простые и незамысловатые картинки.Многих интересует как нарисовать 3d рисунок на бумаге карандашом ярко и реалистично. Для этого стоит использовать фото инструкции или видео, которые наглядно покажут всю технику воссоздания 3д рисунка.Давайте разберем рисунки карандашом поэтапно для начинающих. Для наглядности распечатывайте нарисованные изображения, чтобы облегчить себе задачу. Заметьте, что первое знакомство с техникой 3д может вызвать неоднозначные впечатления, здесь не нужно спешить, плавные движения и выдержка – главные помощники начинающего художника.Итак, приступим к делу, будем учиться как рисовать красивые 3d рисунки.

СОДЕРЖАНИЕ

1. Бабочка

2. Ступеньки

3. Бананы

4. Воронка

5. Лестница

6. Сердце

7. Видео-бонусы: рисунки 3d ручкой

Бабочка

Простая схема позволит понять как рисовать 3д ручкой удивительно красивого насекомого. Ознакомься с этой техникой и нарисуй чудо-рисунок самостоятельно.

как нарисовать 3d треугольник

Пошаговая инструкция:

  1. Проще всего создавать рисунки по клеточкам, поэтому первоначально разметим лист бумаги, прочертим направляющие линии.как нарисовать 3d треугольник
  2. Теперь потребуется наметить очертания бабочки.как нарисовать 3d треугольник
  3. Детализируйте нарисованные крылья.как нарисовать 3d треугольник
  4. Внесите некоторые элементы самого окраса крылышков, прорисуйте брюшко.как нарисовать 3d треугольник
  5. Потребуется убрать направляющие линии, займитесь разукрашиванием.как нарисовать 3d треугольник
  6. Полностью дорисуйте крылья, затем выровняйте тон изображения.как нарисовать 3d треугольниккак нарисовать 3d треугольник
  7. Изобразите тень, используя светлый тон карандаша, на завершающем этапе сделайте более темным тон тени.как нарисовать 3d треугольниккак нарисовать 3d треугольниккак нарисовать 3d треугольник
  8. По пунктирной линии вырежьте часть листа, как показано на фото. Теперь вы ознакомились с тем как нарисовать 3д рисунок простым способом.как нарисовать 3d треугольниккак нарисовать 3d треугольник

Ступеньки

Если вы не знаете что именно можно нарисовать 3d ручкой или карандашом, тогда начните с самого простого. Ведь придать изображениям реалистичность вовсе не так уж сложно, убедитесь на предложенном ниже фото-уроке.

как нарисовать 3d треугольник

Этапы создания изображения:

  1. Начертите фигуру по тем же размерам, которые указаны на фото, затем выделите справа треугольник и пятиугольник.как нарисовать 3d треугольниккак нарисовать 3d треугольник
  2. Проведите от верхнего и нижнего угла пятиугольника параллельные линии, ориентируясь на них, начертите продольные и поперечные линии. Внутри пятиугольника потребуется сделать сетку.как нарисовать 3d треугольниккак нарисовать 3d треугольник
  3. Нарисуйте ступеньки в нижней части фигуры.как нарисовать 3d треугольник
  4. Заштрихуйте несколько участков карандашом и ручкой.как нарисовать 3d треугольник
  5. Завершите штриховку оставшихся областей фигуры. как нарисовать 3d треугольник
  6. Как видите, объем 3d рисунку карандашом можно придать за счет применения различных техник штриховки.как нарисовать 3d треугольник

Бананы

Сымитировать лежащие на столе фрукты довольно просто, нет необходимости применять особые техники изображения предметов. Можно использовать для создания рисунка 3д ручки и маркеры.

как нарисовать 3d треугольник

Техника выполнения рисунка:

  1. Положите на лист бумаги два банана, возьмите простой карандаш и обведите контуры.как нарисовать 3d треугольник
  2. Теперь понадобится маркер черного цвета, проведите параллельные линии, огибая изображение банана, таким образом, создается объемное изображение. Чем больше проведете линий, тем реалистичнее получится картинка.как нарисовать 3d треугольниккак нарисовать 3d треугольник
  3. Возьмите желтую краску, закрасьте промежутки через две линии.как нарисовать 3d треугольник
  4. Используйте зеленую краску и закрашивайте оставшиеся промежутки. Рисунок будет выглядеть реалистично даже на обычном листке из блокнота. как нарисовать 3d треугольник

Более подробную инструкцию по выполнению работы в такой технике на примере руки пришельца вы сможете увидеть на видео (или можно использовать свою руку, просто обведите свою ладонь и пальцы карандашом, а далее следуйте видео-инструкции):

Воронка

Если вы хотите узнать как нарисовать простой 3d рисунок на бумаге, используйте распечатанный образец. По освоенной технике вы сможете обучить и ребенка как нарисовать 3д.

как нарисовать 3d треугольник

Пошаговое выполнение работы:

  1. Сперва рисуем овал посередине листа, проведите изогнутые линии по кругу, как демонстрирует фото.как нарисовать 3d треугольник
  2. Наведите более четкие контуры линий, осуществите легкое нанесение штриховки внутри овала.как нарисовать 3d треугольник
  3. На третьем этапе зарисуйте голубым карандашом линии, которые попадают вглубь воронки, оставляя более светлые области на верхнем крае овала. как нарисовать 3d треугольник
  4. Благодаря этой технике рисунки на бумаге оживают.как нарисовать 3d треугольник

Лестница

Перед тем как рисовать 3d ручкой необходимо попробовать сделать подобные рисунки карандашом. Учимся создавать красивые объемные изображения вместе.

как нарисовать 3d треугольник

Как выполнить рисунок:

  1. Нарисуйте фигуру по размерам, указанным на фото.как нарисовать 3d треугольник
  2. Проведите параллельные линии внутри созданного многоугольника.как нарисовать 3d треугольник
  3. Начните очерчивать ступеньки, используя мягкий карандаш.как нарисовать 3d треугольниккак нарисовать 3d треугольник
  4. Сотрите вспомогательные линии, наведите контуры фигуры.как нарисовать 3d треугольник
  5. Заштрихуйте область над ступеньками и под ними, сделайте более темной левую сторону фигуры.как нарисовать 3d треугольник
  6. Нанесите штриховку за границами фигуры, таким образом, создадите тень от ступенек. как нарисовать 3d треугольник
  7. Картинка готова.как нарисовать 3d треугольник

Сердце

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

как нарисовать 3d треугольник

Как нарисовать:

  1. Нарисуйте карандашом сердце, используя обычный карандаш.как нарисовать 3d треугольник
  2. Проведите карандашом параллельные линии, не затрагивая изображение в центре.как нарисовать 3d треугольник
  3. Теперь потребуется создать эффект «вдавливания» сердца путем искривления линий.как нарисовать 3d треугольник
  4. Удалите ластиком вспомогательные линии, наведите кривые черным маркером.как нарисовать 3d треугольниккак нарисовать 3d треугольник
  5. Вокруг сердца заштрихуйте карандашом, растушуйте тень, более темные оттенки должны располагаться вблизи контуров сердца.как нарисовать 3d треугольниккак нарисовать 3d треугольник
  6. Легкими движениями заштрихуйте внутреннюю часть фигуры, придавая ей объем, как демонстрирует фото:как нарисовать 3d треугольниккак нарисовать 3d треугольниккак нарисовать 3d треугольник

Видео 3d иллюзия сердца:

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

Простой вариант:
Сложный вариант:

Видео-бонусы: рисунки 3d ручкой

Рисуем 3d ручкой красивую бабочку:

Рисуем 3D фото-рамочку:
Рисуем 3д ручкой букет ромашек:
3Д Снеговичок:
3d елочка ручкой:

Понравилась статья? Подпишитесь на канал, чтобы быть в курсе самых интересных материаловПодписаться

>