Дубликаты не найдены

+65
Э-э-э... А помедленней можно?
раскрыть ветку 12
+57
раскрыть ветку 10
+34
Медленнее)
раскрыть ветку 9
0
Чувак, извини, я слоупок, только сейчас увидел :)
+21
Интересно посмотреть на невозможный трезубец в таком исполнении.
раскрыть ветку 9
+44
слишком просто, даже не хочу браться:
Иллюстрация к комментарию
раскрыть ветку 7
+1
Я прошу прощение, уже, наверное, спрашивали не один раз, не видел, в какой программе работаете?
раскрыть ветку 2
+1
Соль в том, что их делают композом, накладывая два изображения друг на друга. А я предлагаю сделать одной фигурой и с оборотом камеры вокруг.
раскрыть ветку 1
+1
как это сделали??
раскрыть ветку 1
+5
ну вот так снимали невозможный трезубец
Иллюстрация к комментарию
+19
Иллюстрация к комментарию
Иллюстрация к комментарию
раскрыть ветку 7
+10
Читер! )) А вообще я знаю такой способ, даже в реале из бумаги собирал такую. По моей задумке - она без разрывов ) Ну и, конечно же, основной целью было постебаться ))
+2
Inventor?:)
раскрыть ветку 5
+1
точно
раскрыть ветку 4
+12
У меня забор такой был в деревне...
+5
раскрыть ветку 4
+7
ага, гиперкуб. Куча времени требуется, что осознать его существование.
раскрыть ветку 3
+4
Или тессеракт.
+2
А в чем сложность его осознания?
раскрыть ветку 1
+3
чем строил модель?
раскрыть ветку 1
+3
3dsmax, я редко другими 3д пакетами пользуюсь. )
+2
Мой мозг перестает варить как только гифка останавливается.
0
Красивый цвет. =)
раскрыть ветку 1
0
Ага, тоже люблю этот цвет. Он еще и наглядно позволяет показать модель. В каком-то уроке лет семь - восемь назад вычитал.
0
это шедевр
-4
Десять плюсов, пожалуйста
-9
линии соединяющие палки кривые
а мы видим прямые,с прямыми линиями такая фигура невозможна
раскрыть ветку 1
+4
ну на тебе с прямыми
Иллюстрация к комментарию
Иллюстрация к комментарию
-51
Насколько я знаю, специально оговаривается, что все палки - прямые.
раскрыть ветку 3
+46
Вы читать умеете? Или только картинки смотреть?
Иллюстрация к комментарию
-6
Не надоедает?
раскрыть ветку 1
+8
Да ладно, не заметил человек, что стебусь, вот и подумал, что я правила нарушил )
ещё комментарии
ещё комментарии
Похожие посты
52

В жизни каждого 3D моделлера была бочка

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

Утверждение в заголовке спорное, может быть... Но бочки преследуют компьютерные игры: найти их можно очень часто. Где-то это просто элемент окружения, где-то ну как минимум за неё можно спрятаться (в надежде, что она неразрушаемая). Бочки мы лутаем в надежде пополнить инвентарь ништяками - появляется функциональность бочки. Ломаем их. Если лень открыть. Или в пылу битвы... Бывает вполне себе необычное назначение бочек в играх. Сходу припомню Ведьмака 3, где на островах Скеллиге к бочкам привязывали контрабанду и кидали в море (океан?), а несчастному Геральту приходилось плавать в надежде найти что-нибудь ценное. Признавайтесь, кто прошёлся по всем вопросикам у "скандинавов"? Не просто проплыл мимо, а вытащил все, убегая от сирен или расстреливая их из арбалета? Ну, ваши вкусы весьма специфичны, но у всех у нас свои тараканы.

В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост


Бочки бывают взрывающиеся. Их обычно аккуратно расставляют по локации, да и вообще всяческая охрана, бандиты и прочие любят тусить возле них... Бочки бывают радиоактивные. Стилизованные (WarCraft и не только). Деревянные. Метал. Сай-фай. Да много их! А какие бочки запомнились вам?

Вот и пришла мысль сделать бочонок. Иногда предмет выбираешь случайно... Допустим, попадается на глаза фотка и предмет кажется интересным. Бывает, вдохновляешься чем-то на ArtStation и хочется сделать что-то подобное. Иногда использую Pinterest для поиска идей. В данном случае, я очевидно особо долго не думал, простите. Просто хотелось потекстурить дерево, пока преимущественно в маленьком опыте текстуринга преобладал метал. Но всё же я постарался найти и сделать не особо типичную бочку. Наткнулся на нужные фотки по всяким запросам: old wood barrel, antique barrel и т.п. И вышел на аукцион Ebay. И потратил там все деньги.

В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост

Шучу. Там кстати много антиквариата. Уже приводила меня туда дорога ранее... В итоге собрал такую вот доску рефов. Достаточно скромную, на самом деле. Что-то для основных вещей, что-то для деталей. По сути, примерно взял общую форму с одной бочки, а металлическую ручку с другой. Сама бочка, увы, заливается ни ромом, ни вином, ни имперским стаутом, а всего лишь водой. По размеру небольшая, иначе бы вряд ли её можно было бы поднять кому-то, кроме Кирилла Сарычева или Цыпленкова. А ну и Гора Клиган еще, да, мощный исландец, 501 кг в тяге всё-таки поднял.

В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост

Рефы собраны, берем, моделим, разворачиваем, хайполим, бейкаем... И получаем в результате это!

В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост

Бочка скукожилась?... Вода сжалась настолько, что это уже какое-то новое агрегатное состояние? Скажите, не попал в реф? Держите!

В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост

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

1. Сначала какая-то грубая модель, чтобы прикинуть форму: драфт, бейзмеш, блокинг - как хотите.

2, 3. Потом додеталил. Что изменилось? Доски отдельной геометрией с толщиной.  Немного по разному торчат для более интересного силуета. Металлическую ручку добавил. Затем включаю сабдивижен (TurboSmooth в максе по группам сглаживания) для уплотнения сетки и выгружаю в Zbrush. Отхайполил. Про хайполи будет отдельно после картинки.

4. Сделал ретопо на основе ранних стадий. И да, не ругайтесь за полигонаж модели, по сути это просто моделька под рендер для себя. Оптимизированное лоуполи для игр делать тоже приходилось. Просто сделал кругло под крупные планы, не переживая за то, есть ли у меня в запасе треугольники. Развертка (сложно удержаться не сделать 2к-4к, но в реальной жизни так бывает редко для такого), бейк...

В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост

Поговорим о хайполи. Ниже результат. Я не особо им доволен. Вышло не особо реалистично, с перебором рельефа, потерял форму досок (слишком кривые и округлые края местами), и до конца её растерял на лоуполи... И вообще, смысла скульптить было не особо много, но хотелось попробовать побрашить, ведь опыт Браша у меня недостаток. По-хорошему, достоточно было сделать фасок и где-то легкого повреждения, а все остальное  вытянуть на текстуре.

В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост

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

В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост

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

Покажу текстуру  с разверткой. В левом верхнем углу - 2 доски с днища бочки, отрезал, чтобы больше свободного места в квадрате занять.

В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост

Как, грубо говоря, ложились слои при текстурировании. Отдельно стоит отметить цветную текстуру, где цветные доски. Это специальная текстурная карта (id map), в помощью которой легче редактировать отдельные доски.

Что ж, дальше предлагаю просто посмотреть рендеры. Делал их в Marmoset Toolbag. Прекрасно работает с PBR. Нет, конечно, наворотов, но удобно. Быстро видишь результат манипуляций.



По источникам света вроде классически: заполняющий (HDRI карта, светит со всех сторон), направленный (но не из-того угла, откуда смотрит камера) и контровой свет (дли подсветки силуета). Где-то могут быть точечные мелкие источники чисто для бличков. Ну и в целом, чтобы самому нравилось, могу долго мучить рендер в плане ракурса, света, настройки камеры.
В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост
В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост
В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост

Далее, несколько экспериментальных кадров. Какая-то композиция, вряд ли особо удачно по композиционным правилам, но по мне вышло любопытно. А одна бочка-то голая! Отдалась! На металлолом...

В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост

Просто побаловался с фоном, блики, контраст!

В жизни каждого 3D моделлера была бочка Бочка, 3D, Модели, Zbrush, Substance painter, 3DS max, Текстуры, Рендер, Видео, Длиннопост

И вращение модельки напоследок.

Спасибо за уделенное время! Можно поддержать на АртСтанции, буду благодарен. Делитесь своими бочками!

Показать полностью 13 2
46

Проект и его воплощение

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

С созданием моделей связано не только моё хобби, но и основная работа. Занимаюсь 3D проектированием зданий и сооружений (конструированием, если быть точным). Сегодня подвезли фотки с монтажной площадки, и я создал парочку вот таких сравнений.

Проект и его воплощение 3D, Модели, Реальность
Проект и его воплощение 3D, Модели, Реальность
119

ТОЗ МЦ-9, модель

ТОЗ МЦ-9, модель Оружие, Модели, 3D, Тоз, СССР, Autodesk Maya, Длиннопост
ТОЗ МЦ-9, модель Оружие, Модели, 3D, Тоз, СССР, Autodesk Maya, Длиннопост
ТОЗ МЦ-9, модель Оружие, Модели, 3D, Тоз, СССР, Autodesk Maya, Длиннопост
ТОЗ МЦ-9, модель Оружие, Модели, 3D, Тоз, СССР, Autodesk Maya, Длиннопост
ТОЗ МЦ-9, модель Оружие, Модели, 3D, Тоз, СССР, Autodesk Maya, Длиннопост
ТОЗ МЦ-9, модель Оружие, Модели, 3D, Тоз, СССР, Autodesk Maya, Длиннопост
ТОЗ МЦ-9, модель Оружие, Модели, 3D, Тоз, СССР, Autodesk Maya, Длиннопост

Относительно редкое советское ружье - ТОЗ МЦ-9. Моделил с реального экземпляра
Буду рад услышать критику


Софт: 3ds max, Maya, Substance Painter, Photoshop, Marmoset Toolbag 3


На ArtStation можно покрутить:
https://www.artstation.com/artwork/4Ykb1

Показать полностью 5
52

3D-модель Магнитофон ВЕСНА [Free]

3D-модель Магнитофон ВЕСНА [Free] Халява, 3D, Модели, Free, Model, Blender

Модель советского магнитофона, низкополигональная.


Diffuse = 2048x2048

Normal map = 2048x2048

AO = 2048x2048
Rough = 2048x2048
Metalness = 2048x2048
(На скетче все текстуры продублированы в 4к разрешении, но с сжатием)

Tris - 1.7k Vert - 1.2k Poly - 952


Скетч
Гумроад

105

Чудесные модели динозавров

Как насчет заценить по-настоящему высокий уровень создания моделей от Якоба Баардо?

Посмотрите на это семейство тираннозавров, паразауролофа и аллозавра, созданных для игры The Isle.

Чудесные модели динозавров Модели, Динозавры, Компьютерные игры, 3D, Длиннопост

^ Семейное фото тираннозавров.

Чудесные модели динозавров Модели, Динозавры, Компьютерные игры, 3D, Длиннопост

^ Модель паразауролофа.

Чудесные модели динозавров Модели, Динозавры, Компьютерные игры, 3D, Длиннопост

^ Аллозавр.

Чудесные модели динозавров Модели, Динозавры, Компьютерные игры, 3D, Длиннопост

^ Взгляд на аллозавра с другой стороны.

Чудесные модели динозавров Модели, Динозавры, Компьютерные игры, 3D, Длиннопост
Чудесные модели динозавров Модели, Динозавры, Компьютерные игры, 3D, Длиннопост

^ Взрослый тираннозавр.

Чудесные модели динозавров Модели, Динозавры, Компьютерные игры, 3D, Длиннопост
Чудесные модели динозавров Модели, Динозавры, Компьютерные игры, 3D, Длиннопост

^ Тираннозавр-подросток.

Чудесные модели динозавров Модели, Динозавры, Компьютерные игры, 3D, Длиннопост
Чудесные модели динозавров Модели, Динозавры, Компьютерные игры, 3D, Длиннопост

^ Юный тирекс.

Как по мне, так этот парень знает свое дело, детализация отличная, а сами динозавры весьма анатомично сделаны. Вы даже можете "покрутить" эти модели на Artstation, чтобы рассмотреть их как следует со всех сторон.


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

Чудесные модели динозавров Модели, Динозавры, Компьютерные игры, 3D, Длиннопост

Стая карнотавров следит за двумя самками альбертозавра у кромки леса. Самцы альбертозавра имеют более яркую раскраску морды. Модель взрослого карнотавра на скрине сделана известным русским 3D-художником Владом Константиновым, который создает модели для музеев, образовательных передач и фильмов. На днях модель карнотавра заменена на модель от Якоба Баардо, которая более "рогата".

Чудесные модели динозавров Модели, Динозавры, Компьютерные игры, 3D, Длиннопост

Самцы альбертозавра на болоте.

Показать полностью 10
129

Немецкий средний танк Т-V "Пантера"

Недавно завершил сборку и окраску модели от "Звезды"

Представляю Вашему вниманию модель танка Т-5 "Пантера" (PzKpfw V «Panther»)

Первый опыт в сборке и окраске. Вот результат:

Немецкий средний танк Т-V "Пантера" Моделизм, Танки, Модели, Пантера, Рукожоп, Картинки, Стендовый моделизм, Пятничный тег моё, Длиннопост

Красил кистью краской "Звезда". "Пачкал" смесью пепла и масла

Немецкий средний танк Т-V "Пантера" Моделизм, Танки, Модели, Пантера, Рукожоп, Картинки, Стендовый моделизм, Пятничный тег моё, Длиннопост

в варианте ч\б похоже выглядит симпатичнее

Немецкий средний танк Т-V "Пантера" Моделизм, Танки, Модели, Пантера, Рукожоп, Картинки, Стендовый моделизм, Пятничный тег моё, Длиннопост

Тут фото на фоне фотографии с монитора, придал немного "оживлённости"

Немецкий средний танк Т-V "Пантера" Моделизм, Танки, Модели, Пантера, Рукожоп, Картинки, Стендовый моделизм, Пятничный тег моё, Длиннопост

Спасибо за внимание! Гитлер капут!

ЗЫ: фоткал на MEIZU M3

upd: масштаб 1:35

Показать полностью 3
174

Рисуем в 3d на c++ поверхность, заданную формулой

Всем привет, меня зовут TaHk и по ночам я программирую на c++.

Недавно я столкнулся с задачей (не столько про c++, сколько математической), решение которой показалось мне красивым, и я хочу им поделиться.

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

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


Итак. Задача -- нарисовать в 3d поверхность, которая задана не набором полигонов, а формулой.

Алгоритм был выбран следующий:

0. Исходные данные.

*Координаты нулевой точки поверхности (точка в глобальной системе координат, являющаяся центром координат для формулы, которой задана поверхность);

*Вектор нормали поверхности в нулевой точке (показывает, как наклонена поверхность относительно глобальных координат);

*Размеры поверхности по x, y и z (чтобы она просчитывалась не по бесконечность во все стороны, а в рамках определенного объема);

*Координаты "глаза";

*Вектор направления взгляда;

*Вектор, показывающий, где у "глаза" верх;

1. Формируем лучи из каждого пикселя экрана и проверяем на пересечение с поверхностью.

2. Если луч не пересекается с поверхностью -- окрашиваем пиксель в черный.

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


Давайте разбираться с каждой задачей в отдельности.

1. Лучи из каждого пикселя экрана.

Ну, тут все просто. Чтобы задать луч -- нужна точка и вектор. Точка у нас есть -- это координаты "глаза". И направление взгляда есть. Соответственно, луч для координат [0,0] у нас уже есть. Что же делать с остальными координатами? Ответ на этот вопрос даст (или нет) эта картинка:

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

Для начала, нам нужны единичные векторы dx и dy, перпендикулярные друг другу и вектору взгляда, чтобы построить на них плоскую систему координат, которая будет для нас экраном. Вектор dy у нас уже есть («Вектор, показывающий, где у "глаза" верх» в исходных данных). Что же на счет dx? А тут приходит на помощь векторная алгебра, из которой мы помним (или нет), что результатом векторного произведения двух векторов является вектор, перпендикулярный векторам-множителям, с нормой равной площади параллелограмма, построенного на этих векторах. Соответственно, если исходные векторы перпендикулярны друг другу и оба с длиной равной единице – длина результата тоже будет равен единице. А это прекрасно, ведь нам нужен именно единичный вектор.

Таким образом,

dX[0] = tv[1]*dY[2] - tv[2]*dY[1];
dX[1] = tv[2]*dY[0] - tv[0]*dY[2];
dX[2] = tv[0]*dY[1] - tv[1]*dY[0];

где tv — вектор направления взгляда, а dY вектор, показывающий где у взгляда верх.

Дальше, было бы неплохо определиться с длиной векторов dx и dy, определив таким образом размер экрана (по сути, это управление углом обзора). Мне оптимальным показался вариант, когда у экрана размер равен единице

dX[0] /= max_x;
dX[1] /= max_x;
dX[2] /= max_x;
dY[0] /= max_x;
dY[1] /= max_x;
dY[2] /= max_x;

Где max_x – разрешение экрана по x. Да, dy тоже делится на max_x, чтобы длина вектора dx была равна вектору dy, так как иначе изображение будет растянуто по одной из осей.

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

Итак, у нас есть:

dX, dY – векторы, определяющие плоскость экрана.

dZ – вектор направления взгляда.

for (int y = 0; y <= max_y; ++y) {
for (int x = 0; x <= max_x; ++x) {
tv[0] = dZ[0]+x*dX[0]+y*dY[0];
tv[1] = dZ[1]+x*dX[1]+y*dY[1];
tv[2] = dZ[2]+x*dX[2]+y*dY[2];
// tv – вектор, показывающий направление луча из точки [x,y] экрана
// ...
};
};

В рамках этого цикла мы и будем работать дальше.


2. Пересечение луча с поверхностью.

Обычно лучший способ найти в пространстве точку пересечения луча с поверхностью, которая задана формулой – это решить систему уравнений, состоящую из уравнения плоскости и уравнения луча. Но если в уравнение плоскости проникает тригонометрия – решений становится бесконечное множество (буквально бесконечное, вида x = 0 ± 2πn, где n∈R ), и что делать программно с этой бесконечностью – не ясно. Поэтому мы будем искать точку пересечения итеративно:

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

1. Определяем параллелепипед, ограничивающий нашу поверхность (мы помним, что по условиям ограничили ее в размерах).

2. Ищем точки пересечения луча и параллелепипеда. Получаем 2 точки – «вход» и «выход» в пределы параллелепипеда.

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

4. В локальных x и у находим по формуле поверхности координату z. Если найденная координата z больше, чем у точки «входа», фиксируем, что мы «под» поверхностью. Иначе – фиксируем, что мы «над» поверхностью.

5. От точки «входа» до «выхода» проверяем аналогичным образом все точки на луче с заданным шагом. Как только на следующем шаге состояние отличается от того, что было на предыдущем – значит, нашли точку пересечения.

6. Если до точки «выхода» состояние не менялось – значит пересечения не было.


Теперь по пунктам.

Существует простой и понятный алгоритм быстрого поиска пересечения прямоугольника с лучом на плоскости. Для его понимания нужно ввести пару терминов:

Точка входа – точка пересечения луча с прямой, в случае если нормаль этой прямой направлена навстречу лучу.

Точка выхода – точка пересечения луча с прямой, в случае если нормаль этой прямой направлена навстречу лучу.

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

Алгоритм такой:

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

К чему это я? А вот к чему. Этот подход отлично работает и в пространстве, если заменить 4 прямые на 6 плоскостей.

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

Как мы помним, поверхность задана точкой и нормалью и ограничена в размерах по x, y и z. Причем эти x y и z – в локальных координатах. То есть наш параллелепипед, ограничивающий поверхность, должен уметь вращаться вместе с поверхностью.

Поэтому для начала определим эти плоскости с учетом поворота параллелепипеда с поверхностью. Для этого нам понадобятся 3 вектора:

ddX[3] = {0,0,0}; // единичный вектор, который направлен вдоль оси X нашей поверхности
ddY[3] = {0,0,0}; // единичный вектор, который направлен вдоль оси Y нашей поверхности
ddZ[3] = {0,0,0}; // единичный вектор, который направлен вдоль оси Z нашей поверхности

с ddZ все понятно – это нормаль к поверхности.

С ddX и ddY сложнее. Одной только точкой и нормалью можно задать в пространстве только бесконечную поверхность. А тут нам нужно зафиксировать поворот этой плоскости вокруг оси z. Это можно сделать разными способами – я беру еще одну точку на плоскости и фиксирую ее координаты в глобальной системе координат. Допустим, это точка point2, а нулевая точка поверхности — point. Тогда

ddX[0] = point2[0] - point[0];
ddX[1] = point2[1] - point[1];
ddX[2] = point2[2] - point[2];
len = sqrt(ddX[0]*ddX[0]+ddX[1]*ddX[1]+ddX[2] *ddX[2]) ;
ddX[0]/=len;
ddX[1]/=len;
ddX[2]/=len;

Как мы видим, я не забыл, что нам нужен именно единичный вектор (с длиной равной единице), поэтому я посчитал длину вектора от точки point к точке point2 и разделил каждую координату на длину. Эта процедура называется нормализация вектора – приведение его к единичной длине с сохранением направления.

Ну и ddY по старой схеме (как в пункте 1, где мы экран рисовали) определяем как векторное произведение ddX на ddZ:

ddY[0] = ddX[1]*ddZ[2] - ddX[2]*ddZ[1];
ddY[1] = ddX[2]*ddZ[0] - ddX[0]*ddZ[2];
ddY[2] = ddX[0]*ddZ[1] - ddX[1]*ddZ[0];

Таким образом, мы можем задать все 6 плоскостей. Например, плоскость, ограничивающая параллелепипед «снизу» определяется так:

spoint[0] = point[0] - z * ddZ[0];
spoint[1] = point[1] - z * ddZ[1];
spoint[2] = point[2] - z * ddZ[2];
n[0] = -ddZ[0];
n[1] = -ddZ[1];
n[2] = -ddZ[2];

где point — нулевая точка нашей поверхности, а z - половина высоты параллелепипеда.

Остальные – по аналогии, меняем только - на + и буквы координат.


Дальше нужно в общем виде понимать, как мы будем искать точки пересечения луча и плоскости. Допустим, плоскость задана точкой point[3] и нормалью n[3]. Луч задан точкой tp[3] и вектором tv[3]. Еще одна картинка в стиле «я у мамы paint master»:

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

Несложно догадаться, что если векторы n и tv имеют единичную длину, то расстояние от точки tp до точки пересечения с плоскостью будет равно -h/p. Шучу, сложно догадаться. Но при желании вы можете это проверить. Даже так – если вы сейчас в школе проходите векторную алгебру – вы должны это проверить и выложить в комментариях доказательство. Иначе вам поставят двойку. Или что там сейчас ставят в школах…

Как же найти эти h и p? Тут на помощь снова приходят определения из векторной алгебры. Скалярное произведение векторов численно равно длине проекции одного из этих векторов на другой. Как определить скалярное произведение? А примерно так:

float MulVecSc(float *Vec1, float *Vec2){
return Vec1[0]*Vec2[0] + Vec1[1]*Vec2[1] + Vec1[2]*Vec2[2];
};

Как мы видим из рисунка, h – это проекция на нормаль вектора от точки tp до точки point, принадлежащей плоскости, а p – это проекция на нормаль вектора tv.

vp[0] = point[0] - tp[0];
vp[1] = point[1] - tp[1];
vp[2] = point[2] - tp[2];
p = MulVecSc(n,tv);
h = MulVecSc(n,vp);
t = - h/p;

Знак p покажет нам, с какой стороны плоскости мы находимся (а значит покажет, нашли мы точку «входа» или «выхода»).


Резюмируем. В пространстве точки пересечения луча с параллелепипедом находятся так:

float ddY[3] = {point2[0],point2[1],point2[2]};
float ddX[3] = {0,0,0};
float ddZ[3] = {n[0],n[1],n[2]};
tmMulVec(n,ddY,ddX);
// 6 плоскостей. Ищем самый поздний "вход" и самый ранний "выход"
// Плоскость 1
spoint[0] = point[0] + x * ddX[0];
spoint[1] = point[1] + x * ddX[1];
spoint[2] = point[2] + x * ddX[2];
vp[0] = tp[0]-spoint[0];
vp[1] = tp[1]-spoint[1];
vp[2] = tp[2]-spoint[2];
n[0] = ddX[0];
n[1] = ddX[1];
n[2] = ddX[2];
p = tmMulVecSc(lv_n,tv);
t = - tmMulVecSc(lv_n,lv_vp)/p;
if(p>0.0f){ // выход
if(t<t_out)
t_out = t;
}else{ // вход
if(t>t_in)
t_in = t;
};
// Плоскость 2
spoint[0] = point[0] - x * ddX[0];
spoint[1] = point[1] - x * ddX[1];
spoint[2] = point[2] - x * ddX[2];
vp[0] = tp[0]-spoint[0];
vp[1] = tp[1]-spoint[1];
vp[2] = tp[2]-spoint[2];
n[0] = -ddX[0];
n[1] = -ddX[1];
n[2] = -ddX[2];
p = tmMulVecSc(lv_n,tv);
t = - tmMulVecSc(lv_n,lv_vp)/p;
if(p>0.0f){ // выход
if(t<t_out)
t_out = t;
}else{ // вход
if(t>t_in)
t_in = t;
};
// Плоскость 3
// ...
// Плоскость 4
// …
// Плоскость 5
// …
// Плоскость 6
// ...
if(t_in<t_out&&t_out>0){
// есть пересечение
};
Так. Теперь мы знаем, что в промежутке от t_in до t_out мы внутри параллелепипеда.
Дальше, как и планировали, будем проверять каждую точку с неким шагом h на то, находится она выше или ниже поверхности в локальных координатах.
Что такое локальные координаты?
Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

Это система координат, образованная теми самыми ddX, ddY, ddZ которые мы определили выше. Как очевидно из рисунка (на этот раз действительно очевидно), если у нас есть точка p, то вектор, ведущий от нулевой точки нашей поверхности до точки p будет определяться векторной суммой x*ddX+y*ddY+z*ddZ, где x y и z локальные координаты этой точки. Что ж, в таком случае, зная глобальные координаты точки p мы можем получить локальные таким образом:

vtp[0] = p[0]-point[0];
vtp[1] = p[1]-point[1];
vtp[2] = p[2]-point[2];
x = MulVecSc(ddX,vtp);
y = MulVecSc(ddY,vtp);
z = MulVecSc(ddZ,vtp);

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

F = F_xy; // тут у нас определение значения функции, описывающей плоскость. Его мы рассмотрим позже, в 3й части.
if(z<F){ // определяем, находимся мы в точке входа «над» или «под» поверхностью
in = true;
}else{
in = false;
};

Дальше – просто делаем это в цикле, перемещая точку p:

for(t = t_in+h;t<=t_out;t+=h){
pt[0] = tp[0] + tv[0]*t;
pt[1] = tp[1] + tv[1]*t;
pt[2] = tp[2] + tv[2]*t;
vtp[0] = point[0]-pt[0];
vtp[1] = point[1]-pt[1];
vtp[2] = point[2]-pt[2];
x = -tmMulVecSc(ddX,vtp);
y = -tmMulVecSc(ddY,vtp);
z = -tmMulVecSc(ddZ,vtp);
F = F_xy;
if(z<F){ // сейчас внутри
if(!in){ // были снаружи
break;
};// были снаружи
}else{ // сейчас снаружи
if(in){ //были внутри
break;
};//были внутри
}; // внутри/снаружи
}; // for t_in ... t_out
if(t>=t_out){
break; // никакого пересечения не было
};
// на данный момент t – это расстояние от точки tp до точки пересечения
// фактически точка на расстоянии t уже после пересечения с плоскостью, поэтому
// в качестве точки пересечения берем t-h
t-=h
collision_pt[0] = tp[0] + tv[0]*t;
collision_pt[1] = tp[1] + tv[1]*t;
collision_pt[2] = tp[2] + tv[2]*t;

Вот мы и нашли, где луч пересек поверхность. Запихнув это решение в цикл, который мы получили в первой части, мы получим картинку, на которой будут видны очертания поверхности. Но на 3d картинку это не будет похоже – чтобы одна точка поверхности отличалась от другой (что создаст объем) нужно определить освещенность.


3. Определение освещенности точки.

В рамках этой задачи мы не будем заморачиваться с источниками света – будем считать, что у нас один источник и он расположен непосредственно за «глазом». В таком случае расчет освещенности сводится к простому определению нормали к поверхности. Чем меньше значение проекции – тем темнее точка, так как свет падает под большим углом. Поскольку векторы у нас единичные, значение проекции будет изменяться в диапазоне [0..1], что позволяет просто домножать значение цвета на проекцию и получать нужную картинку.

Итак, вернемся к «простому определению нормали».

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

Пора наконец определиться с тем, какую поверхность мы рисуем. В коде ранее была конструкция F = F_x; Тут F_x это макрос, в который я подставляю формулу, которую хочу рисовать. Разумеется, в последствии в код можно будет подставить любую формулу, но для примера нужно взять что-то конкретное. Я выбрал такое:

#define F_xy cos((x*x+y*y)/20.0)/(1+(x*x+y*y)/100.0)

Чтобы понимать, что мы хотим увидеть в программе, построим этот график в каком-нибудь инструменте, который это уже умеет:

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

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

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

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

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

(графики касательных смещены для наглядности)

Функция Y=x^2. Её производная Y'=2x. Соответственно, в точке X=0.5 коэффициент угла наклона равен единице, а в точке 2 – четырем. Из графика видно, что коэффициент угла наклона с обратным знаком показывает угол наклона линии, перпендикулярной касательной. Эта же логика работает и для более сложных графиков. Так же она работает и в пространстве.

Поэтому запишем уравнение поверхности в виде cos((x*x+y*y)/20.0)/(1+(x*x+y*y)/100.0) - z = 0 и возьмем производные по трем координатам:

F'x = ((sin((x*x+y*y)/20.0)*x/10.0)*(1+(x*x+y*y)/100.0)-(x/50.0)*cos((x*x+y*y)/20.0))/((1+(x*x+y*y)/100.0)*(1+(x*x+y*y)/100.0))

F'y = ((sin((x*x+y*y)/20.0)*y/10.0)*(1+(x*x+y*y)/100.0)-(y/50.0)*cos((x*x+y*y)/20.0))/((1+(x*x+y*y)/100.0)*(1+(x*x+y*y)/100.0))

F'z = -1

Вернемся к коду. Теперь зная точку пересечения и ее локальные координаты – мы можем найти нормаль. Она будет определяться как N[3] = {-F'x,-F'y,-F'z}. Но нужно помнить, что это ее значения в локальных координатах. Чтобы перевести в глобальные – нужно каждый компонент умножить на значение вектора той оси, которой он соответствует:

#define F_x ((sin((x*x+y*y)/20.0)*x/10.0)*(1+(x*x+y*y)/100.0)-(x/50.0)*cos((x*x+y*y)/20.0))/((1+(x*x+y*y)/100.0)*(1+(x*x+y*y)/100.0))
#define F_y ((sin((x*x+y*y)/20.0)*y/10.0)*(1+(x*x+y*y)/100.0)-(y/50.0)*cos((x*x+y*y)/20.0))/((1+(x*x+y*y)/100.0)*(1+(x*x+y*y)/100.0))
#define F_z 1.0
float Fx = F_x;
float Fy = F_y;
float Fz = F_z;
collision_normal[0] = ddX[0]*Fx+ddY[0]*Fy+ddZ[0]*Fz;
collision_normal[1] = ddX[1]*Fx+ddY[1]*Fy+ddZ[1]*Fz;
collision_normal[2] = ddX[2]*Fx+ddY[2]*Fy+ddZ[2]*Fz;

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

Shade = 255.0f * MulVecSc(collision_normal,tv);
if(Shade < 0)
Shade = -Shade;
r = Shade * rgb[0];
g = Shade * rgb[1];
b = Shade * rgb[2];

Оценим результат:

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

Сменим формулы:

#define F_xy 0.3*(sin(x)*cos(y/2.0)+cos(x/2.5)*sin(y/1.5))
#define F_x -0.3*(cos(x)*cos(y/2.0)-sin(x/2.5)*sin(y/1.5))
#define F_y -0.3*(-sin(x)*sin(y/2.0)+cos(x/2.5)*cos(y/1.5))
Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

Ок.

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост

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

Рисуем в 3d на c++ поверхность, заданную формулой C++, Программирование, 3D, Визуализация, Рендер, Геометрия, Алгебра, Вектор, Длиннопост
Показать полностью 15
829

Космический корабль из Lego. 9.5 кило удовольствия...

Кораблик получился не маленький. Аж 6500 элементов (приблизительно). Хотел разобрать, но в результате выгодно продал через инет...
Космический корабль из Lego. 9.5 кило удовольствия... Кораблик получился не маленький. Аж 6500 элементов (приблизительно).  Хотел разобрать, но в результате выгодно продал через инет...
Показать полностью 1
Похожие посты закончились. Возможно, вас заинтересуют другие посты по тегам: