制作一个顶点等距的球体

Posted

技术标签:

【中文标题】制作一个顶点等距的球体【英文标题】:Make a sphere with equidistant vertices 【发布时间】:2014-09-20 16:09:27 【问题描述】:

为了检查碰撞,我正在尝试制作一个球形的射线爆发,但是根据每条射线撞击的内容或位置会发生特定的交互。因此,为什么我使用光线而不是更简单的东西,例如OverlapSphere

我正在寻找如何制作球体的原因是因为我可以对光线使用相同的数学运算,让它们到达球体所在位置的顶点。但是我能找到的每一种制作球体的方法都是让线条更靠近两极,这是有道理的,因为它很容易做到。但正如你可以想象的那样,它对我当前的项目并没有那么有用。

TL;DR: 如何制作具有等距顶点的球体?如果它不是 完美 等距的很好,它只需要非常接近。如果发生这种情况,如果您能给出差异有多大以及在哪里(如果适用),那就太好了。

补充说明: 我看过this 和this,但数学问题方式超出了我的想象,所以我一直在寻找的东西可能一直盯着我看.

【问题讨论】:

使它们完全等距可能很困难。但是,如果您只需要相当接近的东西,我在这里回答中的一些方法可能对您有用:***.com/questions/24137198/opengl-es-2-0-sphere. 为什么,以善良的名义,当它完全内置在 Unity 中时,你会这样做吗? 明确一点,您想要实现的目标的解决方案内置于 Unity 中。并且如果出于某种原因您想要 "均匀间隔的顶点" ...这也是 Unity 内置的!呵呵! 您的解决方案看起来不错。不幸的是,当我研究这个时,你提到的功能并不存在。这可以追溯到 4.6,当时没有 icosphere 或对所需版本的 PhysX 的支持。无论如何,感谢您的意见。 【参考方案1】:

您可以使用 icosphere。由于顶点分布在等边三角形上,因此您的顶点保证是等距的。

要构造 icosphere,首先制作一个二十面体,然后将面递归地拆分为较小的三角形,如 article 中所述。

【讨论】:

(请注意,那里的著名文章中有几个著名的错误。)仅供参考,您绝对不必这样做,因为它完全内置于 Unity。 这听起来和我要找的完全一样。你会看看这个问题吗? ***.com/questions/46777626/…【参考方案2】:

您是否知道 Unity 提供给您的球体实际上是设计的

牢记这个确切的目标?

也就是说,Unity 内置球体的全部存在理由是,这些点是相当平滑的空间......大致等距,正如你所说的那样。

要在 Unity 中调出这样的球体,只需执行以下操作:

如您所知,您可以立即访问顶点

Mesh mesh = GetComponent<MeshFilter>().mesh;
Vector3[] vv = mesh.vertices;
int kVerts=vv.Length
for (int i=0; i<kVerts; ++i)
  Debug.Log ... vv[i] 

请注意,您可以通过(例如)检查它们与您的“城市”(或其他任何东西)的距离或仅检查(例如)z 值来查看它们在“球体的哪个部分”他们在半球......等等。


此外...

请注意。关于您想要这样做的总体原因:

但是会根据每条光线的照射对象或位置发生特定的交互

请注意,使用 PhysX 做到这一点再简单不过了。 (Unity 中完全内置的游戏物理特性。)事实上,我从来没有在没有根据“碰撞位置”做“特定”事情的情况下看到碰撞!

例如,您可以获取与http://docs.unity3d.com/ScriptReference/RaycastHit-point.html 联系的点

值得注意的是,在休闲编程中写出接近 PhysX 性能的东西是绝对不可想象的。

我希望这会让事情变得更容易!

【讨论】:

【参考方案3】:
    将球体切成 N 圈 计算它的周长 将其除以创建切片的相同角度 这会给你顶点的数量 还有圆内的角步 投射光线

这就是我在 C++ + OpenGL 中的编码方式:

// draw unit sphere points (r=1 center=(0,0,0)) ... your rays directions
int ia,na,ib,nb;
double x,y,z,r;
double a,b,da,db;
na=16;                                  // number of slices
da=M_PI/double(na-1);                   // latitude angle step
for (a=-0.5*M_PI,ia=0;ia<na;ia++,a+=da) // slice sphere to circles in xy planes
    
    r=cos(a);                           // radius of actual circle in xy plane
    z=sin(a);                           // height of actual circle in xy plane
    nb=ceil(2.0*M_PI*r/da);
    db=2.0*M_PI/double(nb);             // longitude angle step
    if ((ia==0)||(ia==na-1))  nb=1; db=0.0;   // handle edge cases
    for (b=0.0,ib=0;ib<nb;ib++,b+=db)   // cut circle to vertexes
        
        x=r*cos(b);                     // compute x,y of vertex
        y=r*sin(b);
        // this just draw the ray direction (x,y,z) as line in OpenGL
        // so you can ignore this
        // instead add the ray cast of yours
        double w=1.2;
        glBegin(GL_LINES);
        glColor3f(1.0,1.0,1.0); glVertex3d(x,y,z);
        glColor3f(0.0,0.0,0.0); glVertex3d(w*x,w*y,w*z);
        glEnd();
        
    

看起来是这样的:

R,G,B 线是球坐标系轴 X,Y,Z 白色线条是您的顶点(白色)+ 方向(灰色)

[备注]

不要忘记包含 math.h 并用你的替换 OpenGL 的东西

【讨论】:

再重复一遍——Spektre,这是针对 Unity3D 的。执行此操作的工具绝对内置于 Unity3D,看来 OP 只是没有意识到这一点。顺便说一句,Unity 绝对与 c++ 或 OpenGL 编程无关。 (同样,无论如何,您“单击一个按钮”并获得 OP 想要的内容。) @Spektre 你知道如何将结果顶点连接成三角形吗?我正在尝试连续第二天,到目前为止,我得到了一个不包括极点的方法:```for(var i = 0; i = count - 21 如果你想要更好看的网格,那么你需要将极点作为顶点,这仅适用于特定数量的点......更容易网格化球体是使用像 this 这样的细分但是而是从二十面体开始。还有更狂野的方法,比如this和this 谢谢,我也试试,我也有点设法连接点,看看:i.imgur.com/kMRCCSA.mp4【参考方案4】:

如果您想要 4、6、8、12 或 20 个顶点,那么您可以拥有与 Platonic solid 完全等距的顶点,它们都适合一个球体。这些的实际坐标应该很容易获得。对于其他数量的顶点,您可以使用其他多面体并缩放顶点,使它们位于球体上。如果您需要很多积分,那么geodesic dome 可能是一个很好的基础。 C60 bucky-ball 可能是一个很好的基础,有 60 分。对于其中的大多数,您应该能够找到可以从中提取坐标的 3D 模型。

【讨论】:

再重复一遍——Salix,这是针对 Unity3D 的。执行此操作的工具绝对内置于 Unity3D,看来 OP 只是没有意识到这一点。【参考方案5】:

我认为控制球体上的点最简单的方法是使用spherical coordinates。然后,您可以使用两个角度(rho 和 phi)和半径来控制球体周围点的位置。

在旋转球体周围均匀填充点的示例代码(为了好玩):

var time = 1; // Increment this variable every frame to see the rotation
var count = 1000;
for (int i = 0; i < count; i++)

    var rho = time + i; 
    var phi = 2 * Math.PI * i / count;
    var x = (float)(radius * Math.Sin(phi) * Math.Cos(rho));
    var z = (float)(radius * Math.Sin(phi) * Math.Sin(rho));
    var y = (float)(radius * Math.Cos(phi));
    Draw(x, y, z); // your drawing code for rendering the point

【讨论】:

这会像一个围绕球体的弯曲环一样绘制,对吧? 不,它实际上应该绘制整个球体。弯曲循环会将rho 设置为固定值。例如,如果您使用rho = i % 2,您将只绘制 2 个循环,等等。【参考方案6】:

正如一些答案已经建议的那样,使用基于二十面体的解决方案。这个来源很容易找到(我自己写了好几次),但我发现优秀的 Primitives Pro 插件在许多其他情况下非常方便,并且总是使用它们的球体而不是内置 Unity one。

Link to Primitives Pro component

Primitives Pro options

【讨论】:

以上是关于制作一个顶点等距的球体的主要内容,如果未能解决你的问题,请参考以下文章

将顶点保存到纹理并传递给着色器

绘制球体OpenGL C++

如何纹理球体的不规则平面?

threejs学习day3:几何形状

坏顶点数据的常见陷阱/原因?

blender中顶点吸附对齐的几点操作细节