Sphere Rendering: Flat Planets
emildziewanowski.com
emildziewanowski.com
If you want something conformal that has less scale variation and wastes fewer corner pixels than a pair of stereographically projected hemispheres and is still not too conceptually tricky, you can use a pair of slightly overlapping Mercator projections, at right angles to each-other, covering the sphere like the two pieces of leather covering a baseball. Each one can have a rectangular texture. There are some NOAA papers suggesting this approach for the grids for solving differential equations needed in weather simulation of the Earth.
The most pixel-efficient projection I know starts by breaking the sphere into an octahedron, then taking each octant to be covered in a grid of hexagonal pixels, using "spherical area coordinates" in each octant to determine the grid. Each octant can then be represented in an ordinary square-pixel image by a half square ("45–45–90 right triangle"), so the result is something like this <https://observablehq.com/@jrus/sac-quincuncial> with a hexagon grid like <https://observablehq.com/@jrus/sphere-resample> (scroll a few examples down from the top of the page). But figuring out the details about how to sample the texture when you need to cross edge boundaries, etc., makes using this quite a bit more fiddly than the 2 stereographic projection version. And there will be some seam artifacts.
It's more math, though, and usually not worth it unless you're already planning to subdivide the surface further for some other reason.
The problem is the sphere is divided into quads which are represented by two triangles, which each have equal area in UV space, but one of the triangles is smaller than the other in 3D space (the one with its horizontal edge closer to the pole). Despite this difference, the UVs are interpolated linearly across the triangle, which means half of the texture is shrunk and half is stretched. At the pole this becomes extreme because one of the triangles actually has zero area in 3D space, so only half of the texture is actually rendered, which causes obvious seams between the triangles.
The right solution is to calculate the UV coordinates per pixel in the pixel shader, instead of per vertex with linear interpretation. If done properly the poles will be seamless.
[1]: https://en.wikipedia.org/wiki/Texture_mapping#Rasterisation_...
As an example a sphere with a “true north” pole that is rendered with one rendering pole at “true north” and another at 0',0’. When the user is looking at the sphere sidelong the former is used and if the user looks at it from closer to the “true north” pole, the equatorial render is used.
I wrote a kind of cool music visualizer for SoundJam perhaps 25 years ago I called "Eclipse". Input data was an array of levels (probably integers) across some range of audible frequencies — a left and right channel.
Think of the eclipsed sun with corona ejections — that was what I was going for. The music data was the "ejections". The frequency of the data determined where around the disc of the sun it would appear.
Over time the ejecta moved away from the sun and soon disappeared as they "cooled" to black — the initial color of the ejecta being white for the strongest signals — yellow, orange, red, brown when weaker. (Think of the black body curve.)
I had to keep a circular buffer of the sound data values (an array of arrays) large enough to represent how much time the ejecta would "live" before disappearing to black.
In any event, the whole display of the "eclipse", ejecta, was just a displacement map. I had pre-calculated a bitmap where the value for each "pixel" was an offset into the buffer of sound level values. "pixels" close to the surface of the sun would have offsets to the new data coming in, pixels further out would have offsets into the tail of the buffer that was about to expire. With the circular, radial aspect of the ejecta, there was some math involved in generating the displacement values in order to map from essentially a radial space to a cartesian one.
With that established as described, the main loop simply pulled in new sound values, over-wrote the oldest values in the circular buffer with the new and then iterated row and column-wise over the displacement map, grabbing the corresponding sound data value, mapped it to a color in a fixed palette and pushed that color into display buffer.
Although not as "flashy" as other visualizers, there was I thought a calm beauty to it. And it very much represented the music data (you know, as opposed to later visualizers where, even when presented with silence, they seemed to be unable to settle down).
> the gas giant’s surface texture will be generated in realtime using a pixel shader and a render-to-texture approach
It's fascinating to watch someone descend into a rabbithole, starting with an impractical, unbounded approach, finding ways to invite performance bottlenecks, and carrying on, and on and on, meandering towards... did OP eventually get this working?
I guess this is a difference between a project with real-life constraints, and a hobby. Let's use a pre-rendered, animated texture for the gas giant, and move on to the rest of the project - come back to cosplay Slartibartfast once everything is up and running.
It seems like a magnificent waste of resources to rotate and project a million vertices for the triangles of this thing when a sphere is a circle, the algorithm for drawing a circle is simple, and you only need to walk horizontally and then drop down a line and keep going until you've drawn every line.
I remember doing stuff like this in the late 80s to precompute magnifying lenses, like the one in Second Reality.
https://computergraphics.stackexchange.com/questions/5090/fa...
This is a great series of blog posts about how GPU based rendering is structured (long but excellent if you're interested):
https://fgiesen.wordpress.com/2011/07/09/a-trip-through-the-...
Part 6 is about rasterisation.
www.shadertoy.com would like a word.
What aspect of shadertoy disagrees with what I wrote?
Rasterisation is one specific step of the rendering process (+). GPUs rasterise triangles. If you're writing a software renderer you can include algorithms to directly rasterise other shapes such as circles, which is what started this whole thread. But if you're rendering with a GPU and relying on its built in rasterisation then triangles is where you start, even if circles is what you ultimately want.
(+) It's also possible to render without the rasterisation step at all - for example, a pure ray tracing based renderer doesn't have an explicit rasterisation step as it's normally thought of in graphics terms.
public void DrawSphere(int centerX, int centerY, int radius, double angle)
{
for (int y = -radius; y <= radius; y++)
{
for (int x = -radius; x <= radius; x++)
{
if (x * x + y * y <= radius * radius)
{
double z = Math.Sqrt(radius * radius - x * x - y * y);
double xRot = x * Math.Cos(angle) - z * Math.Sin(angle);
double zRot = x * Math.Sin(angle) + z * Math.Cos(angle);
double u = 0.5 + (Math.Atan2(zRot, xRot) / (2 * Math.PI));
double v = 0.5 - (Math.Asin(y / (double)radius) / Math.PI);
int textureX = (int)(u * _textureWidth) % _textureWidth;
int textureY = (int)(v * _textureHeight) % _textureHeight;
Rgba32 color = _texture[textureX, textureY];
SetPixel(centerX + x, centerY + y, color);
}
}
}
}Triplanar mapping may have worked as well. It would have fixed the seam and also the polar region. Given the simple texture patterns in the examples it may have worked well.
> I’m taking a similar approach in my project. The skybox I’m working on will feature an animated moon and a gas giant, adding some extra visual flair. Both planets will spin, and in addition, the gas giant will feature moving atmospheric currents. Normally, these motions are too subtle to be seen, but I’ll accelerate them for greater visual impact.
Sounds like they're attempting to create background imagery for a video game or movie or something. Maybe they're fine adjusting the colors just like they adjusted the wind speeds. But they should know that they're trading off accuracy.
My machine slowed down tremendously, with a YouTube video in another tab pausing entirely until I managed to close the tab. I tried again with Task Manager open and saw a process named "System Interrupts" with 75% of the CPU before I choked off the tab again.
Really, it also shouldn't be able to choke the browser.
Effects like swirl etc are easy, and you can use a range of parameters for the noise input: polar angle, azimut, time, 3d coordinates, ... Configuration could be easy by adding things like hue etc