Генерация случайных точек на любой трехмерной поверхности

Мне было интересно, как вы, математически говоря, могли бы генерировать x точек в случайных положениях на трехмерной поверхности, зная количество треугольников, составляющих поверхность (их размеры, положения, нормали и т. Д.)? За сколько шагов вы бы продолжили?

Я пытаюсь создать "рассеиватель" в Maya (с Python и API), но я даже не знаю, с чего начать с точки зрения концепции. Должен ли я сначала создать точки, а затем проверить, принадлежат ли они поверхности? Должен ли я создавать точки непосредственно на поверхности (и как, в этом случае)?

Изменить: я хочу достичь этого без использования 2D-проекции или UV, насколько это возможно.

4 ответа

Решение

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

def sample_areas(triangles, samples):
  # compute and sum triangle areas
  totalA = 0.0
  areas = []
  for t in triangles:
    a = t.area()
    areas.append(a)
    totalA += a

  # compute and sort random numbers from [0,1)
  rands = sorted([random.random() for x in range(samples)])

  # sample based on area
  area_limit = 0.0
  rand_index = 0
  rand_value = rands[rand_index]
  for i in range(len(areas)):
    area_limit += areas[i]
    while rand_value * totalA < area_limit:
      # sample randomly over current triangle
     triangles[i].add_random_sample()

      # advance to next sorted random number
      rand_index += 1;
      if rand_index >= samples:
        return
      rand_value = rands[rand_index]

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

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

Мой уродливый мел сценарий:

//Select poly and target object
{
$sel = `ls -sl -fl`; select $sel[0];
polyTriangulate -ch 0;
$poly_s = `polyListComponentConversion -toFace`;$poly_s = `ls -fl $poly_s`;//poly flat list
int $numPoly[] = `polyEvaluate -fc`;//max random from number of poly
int $Rand = rand($numPoly[0]);//random number
$vtx_s =`polyListComponentConversion -tv $poly_s[$Rand]`;$vtx_s=`ls- fl $vtx_s`;//3 vertex from random poly flat list
undo; //for polyTriangulate

vector $A = `pointPosition $vtx_s[0]`;
vector $B = `pointPosition $vtx_s[1]`;
vector $C = `pointPosition $vtx_s[2]`;
vector $AB = $B-$A; $AB = $AB/mag($AB); //direction vector and normalize
vector $AC = $A-$C; $AC = $AC/mag($AC); //direction vector and normalize
$R_AB = mag($B-$A) - rand(mag($B-$A)); vector $AB = $A + ($R_AB * $AB);//new position
$R_AC = mag($A-$C) - rand(mag($A-$C)); vector $AC = $C + ($R_AC * $AC);//new position
vector $ABC = $AB-$AC; $ABC = $ABC/mag($ABC); //direction vector and normalize
$R_ABC = mag($AB-$AC) - rand(mag($AB-$AC)); //random
vector $ABC = $AC + ($R_ABC * $ABC);
float $newP2[] = {$ABC.x,$ABC.y,$ABC.z};//back to float

move $newP2[0] $newP2[1] $newP2[2] $sel[1];
select -add $sel[1];
}

PS УФ метод лучше

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

Хакетический способ сделать это - создать UV-карту для вашего 3d-объекта, а затем разбросать точки случайным образом в двух измерениях (отбрасывая точки, которые не попали внутрь действительной UV-оболочки). Как только ваши УФ-оболочки заполнены настолько, насколько вы хотите, вы можете преобразовать свои УФ-точки в барицентрические координаты, чтобы преобразовать эти 2-d точки обратно в 3-d точки: фактически вы говорите: "Я 30%, вершина A, 30". % вершины B и 40% вершины C, поэтому моя позиция (.3A + .3B + .4C)

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

Переход к 2D приведет к появлению некоторых артефактов, потому что вы, вероятно, не сможете придумать УФ-карту, которая бы не была растянутой и не имела швов, поэтому из-за этого вы получите изменения в плотности рассеяния. Однако для многих приложений это будет хорошо, поскольку алгоритм действительно прост, а результаты легко настраиваются вручную.

Я не использовал этот, но похоже, что он основан на этом общем подходе: http://www.shanemarks.co.za/uncategorized/uv-scatter-script/

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

Вот псевдокод, который может быть хорошей отправной точкой:

  1. Пусть N = нет вершин трехмерного лица, с которым вы работаете.
  2. Просто сгенерируйте N случайных чисел, вычислите их сумму, разделите каждое на сумму. Теперь у вас есть N случайных чисел, сумма которых равна = 1,0.
  3. Используя приведенные выше случайные числа, возьмите линейную комбинацию трехмерных вершин 3D-грани, которая вас интересует. Это должно дать вам случайную 3D-точку на грани.
  4. Повторяйте, пока не получите достаточно нет. случайных точек на трехмерном лице.
Другие вопросы по тегам