我有一个用于根据角度动态生成圆环段的代码(我基本上是从ProceduralPrimitives那里获取的,并做了一些更改以使用输入角度而不是创建完整的圆环):
public class DynamicTorusSegment : MonoBehaviour
{
[Range(0, 360)] public float CurrentAngle;
[SerializeField] private int _maxSegments = 20;
[SerializeField] private float _radius1 = 1f;
[SerializeField] private float _radius2 = 0.3f;
[SerializeField] private int _nbSides = 5;
// For checking if the Angle was changed since the last frame
private float _lastAngle;
private const float TwoPi = Mathf.PI * 2f;
// Update is called once per frame
private void Update()
{
if (Mathf.Approximately(CurrentAngle, _lastAngle)) return;
_lastAngle = CurrentAngle;
GenerateTorus(CurrentAngle);
}
private void GenerateTorus(float angle)
{
var meshFilter = GetComponent<MeshFilter>();
var mesh = meshFilter.mesh;
mesh.Clear();
var segmentsCount = (int)(_maxSegments * angle / 360);
if (!Mathf.Approximately(angle, 0))
{
segmentsCount = Mathf.Clamp(segmentsCount, 2, _maxSegments);
}
#region Vertices
var vertices = new Vector3[(segmentsCount + 1) * (_nbSides + 1)];
for (var segment = 0; segment < segmentsCount; segment++)
{
var currentSegment = segment == segmentsCount ? 0 : segment;
var t1 = (float)currentSegment / segmentsCount * TwoPi / 360 * angle;
var r1 = new Vector3(Mathf.Cos(t1) * _radius1, 0f, Mathf.Sin(t1) * _radius1);
for (var side = 0; side <= _nbSides; side++)
{
var currentSide = side == _nbSides ? 0 : side;
var t2 = (float)currentSide / _nbSides * TwoPi;
var r2 = Quaternion.AngleAxis(-t1 * Mathf.Rad2Deg, Vector3.up) * new Vector3(Mathf.Sin(t2) * _radius2, Mathf.Cos(t2) * _radius2);
vertices[side + segment * (_nbSides + 1)] = r1 + r2;
}
}
#endregion
#region Normales
var normals = new Vector3[vertices.Length];
for (var segment = 0; segment < segmentsCount; segment++)
{
var currentSegment = segment == segmentsCount ? 0 : segment;
var t1 = (float)currentSegment / segmentsCount * TwoPi / 360 * angle;
var r1 = new Vector3(Mathf.Cos(t1) * _radius1, 0f, Mathf.Sin(t1) * _radius1);
for (var side = 0; side <= _nbSides; side++)
{
normals[side + segment * (_nbSides + 1)] = (vertices[side + segment * (_nbSides + 1)] - r1).normalized;
}
}
#endregion
#region UVs
var uvs = new Vector2[vertices.Length];
for (var segment = 0; segment < segmentsCount; segment++)
{
for (var side = 0; side <= _nbSides; side++)
{
uvs[side + segment * (_nbSides + 1)] = new Vector2((float)segment / segmentsCount, (float)side / _nbSides);
}
}
#endregion
#region Triangles
var faceCount = vertices.Length;
var triangleCount = faceCount * 2;
var indexesCount = triangleCount * 3;
var triangles = new int[indexesCount];
var i = 0;
for (var segment = 0; segment < segmentsCount - 1; segment++)
{
for (var side = 0; side <= _nbSides - 1; side++)
{
var current = side + segment * (_nbSides + 1);
var next = side + (segment < (segmentsCount) ? (segment + 1) * (_nbSides + 1) : 0);
if (i >= triangles.Length - 6) continue;
triangles[i++] = current;
triangles[i++] = next;
triangles[i++] = next + 1;
triangles[i++] = current;
triangles[i++] = next + 1;
triangles[i++] = current + 1;
}
}
#endregion
mesh.vertices = vertices;
mesh.normals = normals;
mesh.uv = uvs;
mesh.triangles = triangles;
mesh.RecalculateBounds();
}
}
这基本上可以正常工作,并根据CurrentAngle
但是您可能已经注意到我的代码/数学出了点问题。
主要问题是:圆环在360°上不完整。
但是当我进一步测试它时,我注意到实际上已经在例如90°也不正确:
因此,为了获得闭合的圆环,我必须使用378°至379°之间的某个角度。因此似乎总有缺少19°的偏移..但这是从哪里来的呢? (它似乎也适用于小角度,所以我也有一个angle < 19°
的分段)
有人在这里看到我在做什么错吗?
更新
19°
的数目实际上似乎取决于(360° / _maxSegments ) = 18,5°
(在我的示例中,_maxSegments
是20),实际上取决于_maxSegments
的值而变小或变大。 / p>
答案 0 :(得分:3)
从原始代码中提取两行:
Vector3[] vertices = new Vector3[(nbRadSeg+1) * (nbSides+1)];
for( int seg = 0; seg <= nbRadSeg; seg++ )
^^
...以及您自己的代码中的相应行:
var vertices = new Vector3[(segmentsCount + 1) * (_nbSides + 1)];
for (var segment = 0; segment < segmentsCount; segment++)
^
请注意,第二个循环条件是<
,而不是应为的<=
。这意味着您将跳过最后一段。
在您的示例中,由于线段的角度跨度为〜18.5°,因此您观察到的〜19°系统差异不是巧合。
请注意,法线,UV和三角形生成循环也会发生相同的问题。