У кого-нибудь есть алгоритм для создания сферы процедурно с la
количеством линий широты, lo
количеством линий долготы и радиусом r
? Мне нужно, чтобы он работал с Unity, поэтому необходимо определить позиции вершин, а затем треугольники, определенные с помощью индексов ( подробнее ).
РЕДАКТИРОВАТЬ
Мне удалось заставить код работать в единстве. Но я думаю, что мог сделать что-то не так. Когда я поднимаю detailLevel
, Все, что он делает, это добавляет больше вершин и многоугольников, не перемещая их. Я что-то забыл?
РЕДАКТИРОВАТЬ 2
Я попытался масштабировать сетку вдоль ее нормалей. Это то, что я получил. Я думаю, что что-то упустил. Я должен масштабировать только определенные нормы?
unity
procedural-generation
3d-meshes
Даниэль Пендергаст
источник
источник
vertices[i] = normalize(vertices[i])
. Кстати, это также дает вам ваши новые, правильные нормы, так что вы должны сделать этоnormals[i] = vertices[i]
потом.Ответы:
Чтобы получить что-то вроде этого:
Создайте икосаэдр (20-стороннее правильное тело) и разделите грани, чтобы получить сферу (см. Код ниже).
Идея в основном:
Разделите каждое лицо на четыре лица одинакового размера. Каждый раз, когда вы делаете это, он в четыре раза увеличивает количество граней в модели.
i0
,i1
иi2
являются вершинами исходного треугольника. (На самом деле, индексы в буфер вершин, но это уже другая тема).m01
середина ребра(i0,i1)
, m12 - середина ребра(i1,12)
иm02
, очевидно, середина ребра(i0,i2)
.Всякий раз, когда вы разделяете лицо, убедитесь, что вы не создаете дублирующиеся вершины. Каждая средняя точка будет совместно использоваться одной другой исходной гранью (поскольку ребра совместно используются гранями). Приведенный ниже код объясняет это, поддерживая созданный словарь именованных средних точек и возвращая индекс ранее созданной средней точки, когда она доступна, вместо создания новой.
Повторяйте, пока не достигнете нужного количества граней для вашего куба.
Когда вы закончите, нормализуйте все вершины, чтобы сгладить поверхность. Если вы этого не сделаете, вы просто получите икосаэдр с высоким разрешением вместо сферы.
Вуаля! Вы сделали Преобразуйте результирующие векторные и индексные буферы в а
VertexBuffer
иIndexBuffer
и рисуйте с помощьюDevice.DrawIndexedPrimitives()
.Вот что вы использовали бы в своем классе "Сфера" для создания модели (типы данных XNA и C #, но это должно быть довольно ясно):
И
GeometryProvider
классисточник
int
массив? И что делает.Select(i => i + vertices.Count)
?.Select(i => i + vertices.Count)
не работает для меня вообще. Это только функция XNA?Рассмотрим параметрическое определение сферы:
где theta и phi - два увеличивающихся угла, которые мы будем называть
var t
и,var u
а Rx, Ry и Rz - независимые радиусы (радиусы) во всех трех декартовых направлениях, которые в случае сферы будут определены как один радиусvar rad
.Давайте теперь рассмотрим тот факт, что
...
символ указывает на итерацию, которая намекает на использование цикла. Концепцияstacks
иrows
«сколько раз вы будете повторять». Поскольку каждая итерация добавляет значение t или u, чем больше итераций, тем меньше значение, следовательно, тем точнее кривизна сферы.«Сферы рисование» предусловия функции является иметь следующие данные параметров:
int latitudes, int longitudes, float radius
. Условия отправки (выходные данные) должны возвращать или применять вычисленные вершины. В зависимости от того, как вы намереваетесь использовать это, функция может возвращать массивvector3
(трехмерных векторов) или, если вы используете какой-то простой OpenGL, до версии 2.0, вы можете напрямую применить вершины к контексту.NB Применение вершины в openGL вызывает следующую функцию
glVertex3f(x, y, z)
. В случае, когда мы будем хранить вершины, мы добавим новыйvector3(x, y, z)
для удобства хранения.Кроме того, способ, которым вы запрашивали работу системы широты и долготы, требовал корректировки определения сферы (в основном переключая z и y), но это просто показывает, что определение очень податливое, и что вы можете свободно переключаться вокруг Параметры x, y и z для изменения направления, в котором нарисована сфера (где широта и долгота).
Теперь давайте посмотрим, как мы собираемся делать широты и долготы. Широты представлены переменной
u
, они повторяются от 0 до 2π радиан (360 градусов). Поэтому мы можем кодировать его итерацию следующим образом:Теперь долготы представлены переменной
t
и повторяются от 0 до π (180 градусов). поэтому следующий код выглядит аналогично предыдущему:(Обратите внимание , что петли Inclusive из там терминального состояния, потому что интервал для параметрического интегрирования от 0 до 2л Inclusive . Вы получите частичную сферу , если ваши условия не включены.)
Теперь, следуя простому определению сферы, мы можем получить определение переменной следующим образом (предположим
float rad = radius;
):Еще одно важное предупреждение! В большинстве случаев вы будете использовать какую-то форму OpenGL, и даже если это не так, вам все равно может понадобиться это сделать. Для трехмерного объекта необходимо определить несколько вершин. Обычно это достигается путем предоставления следующей вершины, которая вычислима.
То, как на рисунке выше разные координаты,
x+∂
иy+∂
мы можем легко сгенерировать три другие вершины для любого желаемого использования. Другие вершины (предположимfloat rad = radius;
):Наконец, вот рабочая полноценная функция, которая будет возвращать все вершины сферы, а вторая показывает работающую реализацию кода OpenGL (это синтаксис в стиле C, а не JavaScript, это должно работать со всеми языками в стиле C, в том числе C # при использовании Unity).
Код OpenGL:
PS Возможно, вы заметили это утверждение
rad = radius;
. Это позволяет изменять радиус в петле в зависимости от местоположения или угла. Это означает, что вы можете применить шум к сфере, чтобы придать ей шероховатость, чтобы она выглядела более естественно, если желаемый эффект похож на планету. Напримерfloat rad = radius * noise[x][y][z];
Клод-Генри.
источник
rad
. Теперь вы делаете одну ногу треугольника и подразумеваете, что гипотенуза этого треугольника тожеrad
. Это эффективно дает вам радиусrad * sqrt(2)
.Некоторое время назад я создал нечто подобное, чтобы создать сферу из кубов, для развлечения и науки. Это не так уж сложно. По сути, вы берете функцию, которая создает круг вершин, а затем шагаете по шагам высоты, которые вы хотите, создавая круги на каждой высоте с радиусом, необходимым для создания сферы. Здесь я изменил код, чтобы не быть для кубов:
Теперь этот код будет просто создавать точки для широты. Однако вы можете почти использовать один и тот же код для создания линий долготы. За исключением того, что вам нужно вращаться между каждой итерацией и делать полный круг на каждой
degreeStep
.Извините, это не полный ответ или не относится к Unity, но, надеюсь, это поможет вам начать.
источник
Не могли бы вы просто начать с простой формы, может быть поле с г расстояние от центра до угла. Чтобы сделать более детальную сферу, разделите все многоугольники и затем переместите вершины на расстояние r от центра, чтобы вектор прошел их текущее положение.
Продолжайте повторять, пока не станет достаточно сферическим для ваших вкусов.
источник
Вам действительно нужна трехмерная геометрия или просто форма?
Вы можете создать «поддельную» сферу, используя один квад. Просто нарисуйте круг и закрасьте его правильно. Это имеет то преимущество, что у него будет именно то разрешение, которое требуется независимо от расстояния до камеры или разрешения.
Здесь есть учебник .
источник
Вот некоторый код для любого числа равноотстоящих вершин сферы, он, как апельсиновая корка, обматывает линию точек вокруг сферы по спирали. потом, как вы присоединитесь к вершинам, зависит от вас. вы можете использовать соседние точки в цикле как 2 каждого треугольника, а затем найти, что третья будет пропорциональной крутизной вокруг сферы выше или ниже ... вы также можете делать треугольники петлей и ближайшим соседом на ней, кто-то делает знаете лучший способ?
};
источник
Хотя Дэвид абсолютно прав в своем ответе, я хочу предложить другую точку зрения.
Для моего задания по генерации процедурного контента я посмотрел (помимо прочего) на икосаэдр по сравнению с более традиционными подразделенными сферами. Посмотрите на эти процедурно сгенерированные сферы:
Оба выглядят как совершенно правильные сферы, верно? Что ж, давайте посмотрим на их каркасы:
Вау, что там произошло? Каркасная версия второй сферы настолько плотная , что выглядит текстурированной! Я открою вам секрет: вторая версия - это икосаэдр. Это почти идеальная сфера, но по высокой цене.
Сфера 1 использует 31 подразделение по оси x и 31 подразделение по оси z, в общей сложности 3844 грани.
Сфера 2 использует 5 рекурсивных подразделений, в общей сложности 109 220 лиц.
Но ладно, это не совсем справедливо. Давайте значительно снизим качество:
Сфера 1 использует 5 подразделов на оси x и 5 подразделов на оси z, всего 100 граней.
Сфера 2 использует 0 рекурсивных подразделений, в общей сложности 100 граней.
Они используют одинаковое количество лиц, но, на мой взгляд, сфера слева выглядит лучше. Это выглядит менее комковатым и намного более круглым. Давайте посмотрим, сколько лиц мы генерируем с помощью обоих методов.
Икосаэдр:
Подразделенная сфера:
Как вы можете видеть, икосаэдр увеличивается в гранях с экспоненциальной скоростью, до третьей степени! Это потому, что для каждого треугольника мы должны разделить их на три новых треугольника.
Правда в том, что вам не нужна точность, которую вам даст икосаэдр. Потому что они оба скрывают гораздо более сложную проблему: текстурирование 2D-плоскости на 3D-сфере. Вот как выглядит верх:
В левом верхнем углу вы можете увидеть используемую текстуру. По совпадению, это также генерируется процедурно. (Эй, это был курс по процессуальному поколению, верно?)
Это выглядит ужасно, верно? Ну, это так же хорошо, как и собирается. Я получил высшие оценки за наложение текстур, потому что большинство людей даже не понимают это правильно.
Поэтому, пожалуйста, рассмотрите возможность использования косинуса и синуса для создания сферы. Он генерирует намного меньше граней для того же количества деталей.
источник
N
деталей даст вамN*N
новые треугольники, которые являются квадратичными, точно так же, как вы делаете с УФ-сферой.Приведенный ниже скрипт создаст икосаэдр с n полигонами ... основание 12. Он также разделит полигоны на отдельные сетки и вычислит общее количество вершин-дубликатов и полигонов.
Я не мог найти ничего подобного, поэтому я создал это. Просто прикрепите скрипт к GameObject и установите подразделения в редакторе. Работы по модификации шума следующие.
источник