【发布时间】:2020-06-07 00:11:33
【问题描述】:
我有一个包含近 120,000 颗星星的数据集和一个包含 215 颗星星的测试数据集(取自主数据集),我正在编写一个程序来读取数据集并在 3D 地球模型周围绘制星星。
- 读取数据集并将信息存储在多个列表中(在单例脚本中)
- 然后模拟脚本读取列表(销毁单例以提高程序效率):
void listStars()
{
int i = 0;
while (i < (StarDataBank.Instance.NumOfStars))
{
int primaryID = int.Parse(StarDataBank.Instance.StarIDID[i]);
string properName = StarDataBank.Instance.StarName[i];
string HIPID = StarDataBank.Instance.StarIDHIP[i];
string HDID = StarDataBank.Instance.StarIDHD[i];
string HRID = StarDataBank.Instance.StarIDHR[i];
string GLID = StarDataBank.Instance.StarIDGL[i];
string BFID = StarDataBank.Instance.StarIDBF[i];
decimal rightAscension = Convert.ToDecimal(StarDataBank.Instance.StarRA[i]);
decimal declination = Convert.ToDecimal(StarDataBank.Instance.StarDec[i]);
decimal Mag;
decimal CI;
float scale = 0;
int r = 0;
int g = 0;
int b = 0;
Decimal.TryParse((StarDataBank.Instance.StarMag[i]), out Mag);
Decimal.TryParse((StarDataBank.Instance.StarCI[i]), out CI);
if (PlayerPrefs.GetInt("dynamicSize") == 1)
{
if (Mag < -1)
{
scale = 77.5f;
}
else
{
if (Mag > -1 && Mag <= 5)
{
scale = 52.5f;
}
else
{
if (Mag > 5 && Mag <= 10)
{
scale = 32.5f;
}
else
{
if (Mag > 10 && Mag <= 15)
{
scale = 17.5f;
}
else
{
if (Mag > 15 && Mag <= 20)
{
scale = 7.5f;
}
else
{
if (Mag > 20 && Mag <= 25)
{
scale = 2.5f;
}
}
}
}
}
}
}
else
{
scale = 20;
}
StartCoroutine(placeStars(primaryID, properName, HIPID, HDID, HRID, GLID, BFID, rightAscension, declination, Mag, CI, scale));
i++;
}
DestroyImmediate(StarDataBank.Instance.gameObject);
}
- 每颗星都是用这种方法绘制的:
IEnumerator placeStars(int primaryID, string properName, string HIPID, string HDID, string HRID, string GLID, string BFID, decimal rightAscension, decimal declination, decimal magnitude, decimal colourIndex, float scale)
{
var thisStar = (GameObject)Instantiate(prefabStar, transform.position + getVectors(Convert.ToDecimal(rightAscension), Convert.ToDecimal(declination)), Quaternion.identity);
thisStar.name = (primaryID).ToString();
thisStar.transform.parent = StarObject.transform;
thisStar.transform.localScale = new Vector3(scale, scale, scale);
thisStar.AddComponent<Star>().newStar(primaryID, properName, HIPID, HDID, HRID, GLID, BFID, rightAscension, declination, magnitude, colourIndex);
yield return null;
}
使用只有 215 颗星的较小测试数据集,我能够将 Star 类附加到每个实例化的星。
但是对于拥有约 120k 星的大型完整数据集,Unity 编辑器只会在按下播放按钮后挂起。当我注释掉这一行时:thisStar.AddComponent<Star>().newStar(...); 程序按预期工作,每个星星都绘制在场景中,唯一的问题是 Star 类没有附加到每个新实例化的星星上。
这意味着 AddComponent 函数不能很好地与我的代码配合使用,尤其是在使用大型数据集时。
有没有更有效的方法将 Star 类附加到每个实例化的 Star GameObject?
另外,在我用完单例后销毁它有什么不同吗?我使用 IEnumerator 实例化有什么不同吗?
编辑:这是 Star 类:
public class Star : MonoBehaviour
{
Simulation simulationInstance;
public int primaryID; // primary key NEEDS TO BE SET
public string properName; // some stars have names NEEDS TO BE SET
public string HIPID; // ID of star from Hipparcos catalogue NEEDS TO BE SET
public string HDID; // ID of star from Henry Draper catalogue NEEDS TO BE SET
public string HRID; // ID of star from Harvard Revised catalogue NEEDS TO BE SET
public string GLID; // ID of star from Gliese catalogue NEEDS TO BE SET
public string BFID; // ID of star from BayerFlamsteed catalogue NEEDS TO BE SET
public decimal rightAscension; // right ascension of star NEEDS TO BE SET
public decimal declination; // declination of star NEEDS TO BE SET
public decimal magnitude; // magnitude of the star NEEDS TO BE SET
public decimal colourIndex; // colour index of the star NEEDS TO BE SET
public int scale; // size of the sphere that will represent the star AUTOMATICALLY SET
public int red; // red colour (0-255) AUTOMATICALLY SET
public int green; // green colour (0-255) AUTOMATICALLY SET
public int blue; // blue colour (0-255) AUTOMATICALLY SET
public double x; // AUTOMATICALLY SET
public double y; // AUTOMATICALLY SET
public double z; // AUTOMATICALLY SET
void Start()
{
simulationInstance = FindObjectOfType<Simulation>();
}
public void newStar(int primaryID, string properName, string HIPID, string HDID, string HRID, string GLID, string BFID, decimal rightAscension, decimal declination, decimal magnitude, decimal colourIndex)
{
this.primaryID = primaryID;
this.properName = properName;
this.HIPID = HIPID;
this.HDID = HDID;
this.HRID = HRID;
this.GLID = GLID;
this.BFID = BFID;
this.rightAscension = rightAscension;
this.declination = declination;
this.magnitude = magnitude;
this.colourIndex = colourIndex;
}
public void tellStarInfoPanel()
{
simulationInstance.starInfoPanelManager(primaryID, properName, HIPID, HDID, HRID, GLID, BFID, rightAscension, declination, magnitude, colourIndex);
}
}
编辑:我将 listStars() 设为协程,将 placeStars() 设为普通方法
public void placeStars(int primaryID, string properName, string HIPID, string HDID, string HRID, string GLID, string BFID, decimal rightAscension, decimal declination, decimal magnitude, decimal colourIndex, float scale)
{
var thisStar = (GameObject)Instantiate(prefabStar, transform.position + getVectors(Convert.ToDecimal(rightAscension), Convert.ToDecimal(declination)), Quaternion.identity);
thisStar.name = (primaryID).ToString();
thisStar.transform.parent = StarObject.transform;
thisStar.transform.localScale = new Vector3(scale, scale, scale);
thisStar.GetComponent<Star>().newStar(primaryID, properName, HIPID, HDID, HRID, GLID, BFID, rightAscension, declination, magnitude, colourIndex);
starsRendered++;
}
【问题讨论】:
-
在这里使用协程没有任何附加价值,因为其中的所有代码都会同时运行,然后它会停顿一帧并继续前进。所以你可以使用普通的 void 方法。如果您的程序趋于变慢,也许您可以考虑只加载相关的星星,例如可见的星星或接近的星星。随着时间的推移,您可以使用协同程序来创建它们,因此不是在一次运行中创建它们,而是创建前 200 个,然后 yield return,下一个 200,依此类推。这将需要几秒钟,但您可以同时使用该应用程序。
-
所以我会首先运行并创建 200 个在一定半径内的星星,那些未创建的星星放在一个集合中。然后接下来的 200 以此类推,直到初始为空。完成后,使用相同的方法,但使用 far 集合。您的方法看起来像 IEnumerator CreateStars(IEnumerable
initial, IEnumerable nextBatch, float radius); initial 是要运行的集合, nextBatch 是放置远项目的集合。每次,nextBatch 都成为初始值。运行这个直到 initial 为空。 -
FindObjectOfType<>()也很重,消除它。这看起来像是 ECS 的完美用例,我会按照 Andrew 的建议进行研究。
标签: c# class unity3d instantiation large-data