If you’re texturing the whole celestial sphere, then does it need to be dynamic? Unless you’re going to the detail of simulating relative parallax of stars, you can probably get away with a static texture (maybe derived from a sky panorama [like these][1]) and rotate the celestial sphere over time. Items that move noticeably, like planets, can be rendered as quads on top, rather than baked-into the texture. This will likely give much better performance than generating the texture at runtime.
If you do need to plot, I’d advise using a cubemap instead of spherical coordinates. There are some (Pro) functions to [generate a cubemap using a camera][2] - you could position quads where you want each star, or use a particle system with manually-positioned particles to draw a lot of them. Then let Unity’s rendering pipeline handle actually creating the texture out of it.
Update:
For Unity Free, I’d still recommend a cubemap over other spherical projections. Using an equirectangular (lat/long) projection, for instance, wastes a lot of resolution at the poles, and will make your stars smeared at the equator but aliased at the poles. A cubemap has much more uniform resolution, which can lead to less waste and more consistent appearance of your stars. For example, a 512-pixel-wide cubemap gives you as much equatorial resolution as a 2048 equirectangular, but uses 25% less texture memory.
You can initialize a cubemap like this:
cubemap = new Cubemap(cubemapSize, TextureFormat.RGB24, false);
Color[][] colorBuffer = new Color[6][];
for(int i = 0; i < 6; i++)
{
colorBuffer _= new Color[cubemapSize * cubemapSize];_
-
}*
-
foreach(var star in starCollection)*
-
{*
-
PlotCubemapPixel(star.direction, star.color, colorBuffer);*
-
}*
-
cubemap.SetPixels(colorBuffer[(int)CubemapFace.PositiveX], CubemapFace.PositiveX);*
-
cubemap.SetPixels(colorBuffer[(int)CubemapFace.NegativeX], CubemapFace.NegativeX);*
-
cubemap.SetPixels(colorBuffer[(int)CubemapFace.PositiveY], CubemapFace.PositiveY);*
-
cubemap.SetPixels(colorBuffer[(int)CubemapFace.NegativeY], CubemapFace.NegativeY);*
-
cubemap.SetPixels(colorBuffer[(int)CubemapFace.PositiveZ], CubemapFace.PositiveZ);*
-
cubemap.SetPixels(colorBuffer[(int)CubemapFace.NegativeZ], CubemapFace.NegativeZ);*
-
cubemap.Apply();*
-
RenderSettings.skybox.SetTexture("_Tex", cubemap);*
If you want, you can initialize a face of your cubemap color buffer at a time with a background texture (say, the milky way) before plotting your stars on top, [following the example here][3].
Stars can be placed using a pixel-plotting function like:
- void PlotCubemapPixel(Vector3 direction, Color color, Color colorBuffer)*
- {*
-
CubemapFace face;*
-
Vector3 absDirection = new Vector3(Mathf.Abs(direction.x), Mathf.Abs(direction.y), Mathf.Abs(direction.z));*
-
Vector2 position = Vector2.zero;*
-
if(absDirection.x > absDirection.y && absDirection.x > absDirection.z)*
-
{*
-
face = direction.x > 0 ? CubemapFace.PositiveX : CubemapFace.NegativeX;*
-
position.x = -direction.z/direction.x;*
-
position.y = direction.y/absDirection.x;*
-
}*
-
else if(absDirection.y > absDirection.z)*
-
{*
-
face = direction.y > 0 ? CubemapFace.PositiveY : CubemapFace.NegativeY;*
-
position.x = direction.x/absDirection.y;*
-
position.y = -direction.z/direction.y;*
-
}*
-
else*
-
{*
-
face = direction.z > 0 ? CubemapFace.PositiveZ : CubemapFace.NegativeZ;*
-
position.x = direction.x/direction.z;*
-
position.y = direction.y/absDirection.z;*
-
}*
_ position = 0.5f * (position + Vector2.one);_
_ int pX = Mathf.Clamp(Mathf.FloorToInt(cubemapSize * position.x), 0, cubemapSize - 1);_
_ int pY = Mathf.Clamp(Mathf.FloorToInt(cubemapSize * (1f - position.y)), 0, cubemapSize - 1);_
_ int index = pX + cubemapSize * pY;_