在任何三维表面上生成随机点

时间:2016-03-04 15:48:53

标签: python math 3d maya maya-api

我想知道,从数学上讲,你如何在3D表面上的随机位置生成x点,知道构成表面的三角形多边形的数量(它们的尺寸,位置,法线等)?你会进行多少步骤?

我正在尝试在Maya中创建一个“散射器”(使用Python和API),但我甚至不知道在概念方面从哪里开始。我应该首先生成点,然后检查它们是否属于曲面?我应该直接在曲面上创建点(以及在这种情况下如何)?

编辑:我希望尽可能不使用2D投影或UV来实现这一目标。

4 个答案:

答案 0 :(得分:2)

If the constraint is that all of the output points be on the surface, you want a consistent method of addressing the surface itself rather than worrying about the 3d > surface conversion for your points.

The hacktastic way to do that would be to create a UV map for your 3d object, and then scatter points randomly in 2 dimensions (throwing away points which happened not to land inside a valid UV shell). Once your UV shells are filled up as much as you'd like, you can convert your UV points to barycentric coordinates to convert those 2-d points back to 3-d points: effectively you say "i am 30% vertex A, 30 % vertex B, and 40% vertex C, so my position is (.3A + .3B + .4C)

Besides simplicity, another advantage of using is UV map is that it would allow you to customize the density and relative importance of different parts of the mesh: a larger UV face will get a lot of scattered points, and a smaller one fewer -- even if that doesn't match the physical size or the faces.

Going to 2D will introduce some artifacts because you probably will not be able to come up with a UV map that is both stretch-free and seam-free, so you'll get variations in the density of your scatter because of that. However for many applications this will be fine, since the algorithm is really simple and the results easy to hand tune.

I have not used this one but this looks like it's based on this general approach: http://www.shanemarks.co.za/uncategorized/uv-scatter-script/

If you need a more mathematically rigorous method, you'd need a fancier method of mesh parameterization : a way to turn your 3-d collection of triangles into a consistent space. There is a lot of interesting work in that field but it would be hard to pick a particular path without knowing the application.

答案 1 :(得分:2)

您应计算每个三角形的面积,并将其用作权重来确定每个随机点的目标。作为批处理操作,这可能是最简单的方法:

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]

请注意,脊状或皱纹区域可能看起来具有较高的点密度,这仅仅是因为它们在较小的空间中具有更多的表面积。

答案 2 :(得分:2)

  1. 从随机三角形中挑选2条随机边。
  2. 在边缘创建2个随机点。
  3. 在它们之间创建新的随机点。
  4. 我丑陋的梅尔剧本:

    //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 UV方法更好

答案 3 :(得分:1)

这是伪代码,可能是一个很好的起点:

  1. 设N =您正在使用的3D面的顶点。
  2. 只需生成N个随机数,计算它们的总和,将每个数除以总和。现在你有N个随机数,其总和= 1.0。
  3. 使用上面的随机数,拍摄您感兴趣的3D脸部的linear combination个3D顶点。这应该会在脸上给你一个随机的3D点。
  4. 重复直到你得到足够的号码。 3D脸上的随机点数。