c# - Unity3d中的圆锥截头体
问题描述
我正在帮助我的朋友制作他的研究项目,为此我们需要一个 3d 平截头体,并且能够在运行时设置上圆形表面和底部圆形表面的直径,您能否建议如何完成?我正在考虑获取边缘/顶点数组,它们与顶部和底部的中心连接,并更改它们的坐标,也许有更简单的方法可以做到这一点?
解决方案
要创建具有动态大小的圆锥截头体,您可以使用http://wiki.unity3d.com/index.php/ProceduralPrimitives#C.23_-_Cone中的脚本
由于您稍后开始创建网格,因此您确切知道哪些顶点是顶部和底部平面的顶点,因此您可以在之后轻松地动态更改它们。
有点像例如
public class DynamicConicalFrustum : MonoBehaviour
{
[SerializeField] private MeshFilter meshFilter;
[SerializeField] private MeshCollider meshCollider;
[Header("Settings")]
[SerializeField] private float _height = 1f;
[SerializeField] private float _bottomRadius = .25f;
[SerializeField] private float _topRadius = .05f;
[SerializeField] private int nbSides = 18;
private Mesh mesh;
const float _2pi = Mathf.PI * 2f;
private Vector3[] vertices;
private void Awake()
{
if (!meshFilter && !TryGetComponent<MeshFilter>(out meshFilter))
{
meshFilter = gameObject.AddComponent<MeshFilter>();
}
if(!GetComponent<MeshRenderer>())
{
var mr = gameObject.AddComponent<MeshRenderer>();
mr.material = new Material(Shader.Find("Standard"));
}
if (!meshCollider)
meshCollider = GetComponent<MeshCollider>();
mesh = meshFilter.mesh;
if (!mesh)
{
mesh = new Mesh();
}
meshFilter.mesh = mesh;
if (meshCollider)
meshCollider.sharedMesh = mesh;
RecreateFrustum(_height,_bottomRadius,_topRadius);
}
#if UNITY_EDITOR
private void OnValidate()
{
if (Application.isPlaying)
{
Awake();
}
}
#endif
public void RecreateFrustum(float height, float bottomRadius, float topRadius)
{
mesh.Clear();
int nbVerticesCap = nbSides + 1;
#region Vertices
// bottom + top + sides
vertices = new Vector3[nbVerticesCap + nbVerticesCap + nbSides * 2 + 2];
// Bottom cap
vertices[0] = new Vector3(0f, 0f, 0f);
for(var idx = 1; idx <= nbSides; idx++)
{
float rad = (float)(idx ) / nbSides * _2pi;
vertices[idx ] = new Vector3(Mathf.Cos(rad) * bottomRadius, 0f, Mathf.Sin(rad) * bottomRadius);
}
// Top cap
vertices[nbSides + 1] = new Vector3(0f, height, 0f);
for(var idx = nbSides + 2; idx <= nbSides * 2 + 1; idx++)
{
float rad = (float)(idx - nbSides - 1) / nbSides * _2pi;
vertices[idx] = new Vector3(Mathf.Cos(rad) * topRadius, height, Mathf.Sin(rad) * topRadius);
}
// Sides
int v = 0;
for(var idx = nbSides * 2 + 2; idx <= vertices.Length - 4; idx+=2)
{
float rad = (float)v / nbSides * _2pi;
vertices[idx] = new Vector3(Mathf.Cos(rad) * topRadius, height, Mathf.Sin(rad) * topRadius);
vertices[idx + 1] = new Vector3(Mathf.Cos(rad) * bottomRadius, 0, Mathf.Sin(rad) * bottomRadius);
v++;
}
vertices[vertices.Length - 2] = vertices[nbSides * 2 + 2];
vertices[vertices.Length - 1] = vertices[nbSides * 2 + 3];
#endregion
#region Triangles
int nbTriangles = nbSides + nbSides + nbSides * 2;
int[] triangles = new int[nbTriangles * 3 + 3];
// Bottom cap
int tri = 0;
int i = 0;
while (tri < nbSides - 1)
{
triangles[i] = 0;
triangles[i + 1] = tri + 1;
triangles[i + 2] = tri + 2;
tri++;
i += 3;
}
triangles[i] = 0;
triangles[i + 1] = tri + 1;
triangles[i + 2] = 1;
tri++;
i += 3;
// Top cap
//tri++;
while (tri < nbSides * 2)
{
triangles[i] = tri + 2;
triangles[i + 1] = tri + 1;
triangles[i + 2] = nbVerticesCap;
tri++;
i += 3;
}
triangles[i] = nbVerticesCap + 1;
triangles[i + 1] = tri + 1;
triangles[i + 2] = nbVerticesCap;
tri++;
i += 3;
tri++;
// Sides
while (tri <= nbTriangles)
{
triangles[i] = tri + 2;
triangles[i + 1] = tri + 1;
triangles[i + 2] = tri + 0;
tri++;
i += 3;
triangles[i] = tri + 1;
triangles[i + 1] = tri + 2;
triangles[i + 2] = tri + 0;
tri++;
i += 3;
}
#endregion
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
mesh.RecalculateTangents();
mesh.Optimize();
}
}
当然,目前还没有真正优化,但我希望你能从那里继续前进;)例如,该方法为侧面创建额外的顶点..人们可以重新使用顶部和底部的顶点,因为它们无论如何都匹配位置。此外,您当然也可以在高度和半径变化时更新相应的顶点,您不需要每次都重新创建整个网格,因为三角形保持不变,只有顶点改变位置。
推荐阅读
- sequelize.js - Sequelize:SQL Server 2014:从字符串转换日期和/或时间时转换失败
- asp.net-core - 如何在 .net core web api 中使用 ToListAsync()
- regex - 正则表达式捕获和非捕获组
- python - Google Colab 中的错误:SystemError:此解释器版本:“3.7.10”与 ViZDoom 编译时使用的解释器版本不匹配:3.7.11
- r - 如何用一个自由变量解决这个受约束的线性规划 (LP) 问题?
- javascript - 如何在组件 vue 中使用 file.js
- email - 我应该通过什么方法发送带有气流的电子邮件?
- html - 搜索栏宽度不适应窗口大小
- javascript - 图像不会加载到 javascript 画布中
- python - 在函数中设置条件以继续