给定 Unity 和 C# 中的网格(它本身是通过合并更简单的基础网格实时创建的),我们如何在运行时* 将它变成一个平滑的,几乎就像包裹在布中一样的网格版本?不是完全凸出的版本,而是更圆润、柔化锋利边缘、弥合深缝隙等。当“平滑角度”法线设置应用于导入的对象时,表面看起来也很理想。谢谢!
草图前后
*网格设置是由人制作的,其细节事先未知。虽然它的所有基本形状部分(在我们合并它们之前)都是已知的。如果这有助于解决方案,基础部分也可能保持未合并状态,如果有一个运行时解决方案可以快速应用包装混搭,即使基础部分随着时间的推移改变它们的变换,但静态一次性转换,那将是非常棒的也会很棒。
(一些相关的关键字可能是:行进立方体算法和元球、骨骼上方的皮肤、网格过滤器转换、平滑着色器、软化、顶点分割。)
最佳答案
有很多方法可以获得类似的东西,所以你可以选择你喜欢的一种:
行军方块
这个算法很容易使用,但结果总是继承了它的块状“风格”。如果这是您想要的外观,请使用它。如果您需要更平滑和/或像素完美的东西,请寻找其他方法。
射线行进和有符号距离函数
这是一个非常有趣的技术,可以给你很多控制。您可以使用简单的立方体/圆柱体等来表示您的基础部件。方程并用简单的数学将它们混合在一起。
在这里你可以看到一些例子:
http://iquilezles.org/www/articles/distfunctions/distfunctions.htm
这里最好的事情是设置非常简单,您甚至不需要合并基础部分,您只需将数据推送到渲染器。更糟糕的是,渲染部分可能会变得难以计算。
旧学校网格修改
在这里,您有最多的选择,但也最复杂。您从自己没有太多数据的基础部分开始,因此您可能应该使用 CSG 联合操作将它们连接到一个网格中。
有了这个网格,你可以为你的基元计算邻居数据:
等等。
使用此类数据,您可以执行以下操作:
等等...
确实有很多细节可能对你有用,你只需要测试一些看看哪个给出了首选的结果
.
我会从一件简单的事情开始:
使用这种方式,您也有两个不同的阶段:计算和渲染,因此使用动画可能会变得太慢,但仅渲染网格会比使用 Ray Marching 方法更快。
希望这可以帮助。
编辑:
不幸的是,我从来没有这样的需求,所以我没有任何示例代码,但是这里有一些伪代码可以帮助您:
你有你的网格:
Mesh mesh;
顶点邻居数组:
对于任何顶点索引
N
, triNeighbors[N]
将存储由边连接的其他顶点的索引List<HashSet<int>> triNeighbors = new List<HashSet<int>>();
int[] meshTriangles = mesh.triangles;
// iterate vert indices per triangle and store neighbors
for( int i = 0; i < meshTriangles.Length; i += 3 ) {
// three indices making a triangle
int v0 = meshTriangles[i];
int v1 = meshTriangles[i+1];
int v2 = meshTriangles[i+2];
int maxV = Mathf.Max( Mathf.Max( v0, v1 ), v2 );
while( triNeighbors.Count <= maxV )
triNeighbors.Add( new HashSet<int>() );
triNeighbors[v0].Add( v1 );
triNeighbors[v0].Add( v2 );
triNeighbors[v1].Add( v0 );
triNeighbors[v1].Add( v2 );
triNeighbors[v2].Add( v0 );
triNeighbors[v2].Add( v1 );
}
现在,对于任何单个顶点,索引为
N
您可以计算其新的平均位置,例如:int counter = 0;
int N = 0;
Vector3 sum = Vector3.zero;
if( triNeighbors.Count > N && triNeighbors[N] != null )
{
foreach( int V in triNeighbors[N] ) {
sum += mesh.vertices[ V ];
counter++;
}
sum /= counter;
}
这段代码可能有一些错误,我刚刚补上了,但你应该明白这一点。
关于unity3d - 在 Unity 中平滑动态生成的网格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50273477/