- Home /
Plotting stars on dynamic sphere texture
I have a sphere with the winding reversed so that I can texture the inside, and wish it act as star-dome. Using data from a star catalog I want to dynamically texture the sphere by plotting the stars on it for a given day/time.
I have created a basic 4-color striped texture using a script and it makes the sphere look like a beach ball. But I am struggling with more accurate creation of texture, what size should I make it relative to the size of my sphere, and how can I plot using spherical coordinates on this texture?
This is a very broad topic, a sphere's surface cannot be represented on a plane without distortion :
Answer by DMGregory · May 06, 2014 at 02:56 PM
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) 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 - 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[i] = 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.
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;
colorBuffer[(int)face][index] = color;
}
If I understand you correctly, you suggest placing quads as stars and then using that Pro function to take images and create a texture for a cubemap?
I think this would cause performance issues for a mobile device, and I am also using Unity free. Hence why I was asking about plotting the celestial sphere coords onto a texture. Thanks for the insight though
Thank you for your in-depth solution and help regarding this issue, especially co$$anonymous$$g back for a non-pro solution. $$anonymous$$y problem may have been simplified but your info is helpful nonetheless!
Your answer
Follow this Question
Related Questions
The name 'Joystick' does not denote a valid type ('not found') 2 Answers
Centering a texture on Sphere on X axis 0 Answers
GUITexture is lagging my object 0 Answers
Modifying Terrain Splat Texture at Runtime 2 Answers
First Person Controller Detect Texture 2 Answers