Back in 1988 I wrote FOFT, at the start of the game I did a little sequence where you started out viewing a galaxy from a long way away. The galaxy rotated in 3D. After a short while the camera zoomed into a single solar system, then through the solar system to a single planet.
Of course in those days my "galaxy" only had 256 stars, and no dust but it still took a lot of work to get all the bits to work real time.
I want to do the same sequence again, but I now want it to look great.
My target platform is OpenGLES 1.0, so no shaders, and a very basic form of GLES, so no point sprites or render to texture.I also need it to run on mobile devices, so ram is limited.
With these limitations, I am struggling to come up with a design for the code.
I am thinking of storing my galaxy as a sparse 2D array with each element containing dust density, star density, and thickness.
However rendering that structure real time is going to be tough.
For the distant view I could run a marching cubes algo and texture each poly from an atlas, but that won't work when the camera is inside the structure.
With shaders I would probably look at a ray marching algo, but I don't think I can get that real time without them.
Any ideas guys?
I would probably try regular ol' billboard particles first, before trying to take a volume rendering approach.
I think you're pretty much on the right path. Transitioning from distant billboards to 3D objects when up close can be tricky, but it can be done. It's all about cross fading at the right time, which just means you have to keep experimenting until you find the sweet spot. I would basically implement my own software mipmapper and treat level "0" as the moment when I should start the transition. It helps to throw some dust in there or pass through a nebula when you really need to pull off some smoke and mirror magic.
Another alternative would be to use deep zoom. It's more FMV then actual programming effort on your part, but it's easy to setup and allows for more flexibility than a basic video. Since you mention this is a sequence and probably won't need to do much more than present it, it's an option I thought I would throw out there. You can see an example of it here, or if you have Silverlight installed you can check out the world telescope website.
While I want it to be good looking for the front end, I'm thinking I need a cut down version for the navigation display.
So pre-rendering is not really what I want to do.
Bill boarding always looks a little strange to me when you have a lot of movement, it's fine for linear zoom, but once you add rotation... iffy.
My thoughts at the moment are heading towards a voxel solution. Each voxel will be subdivided as they get closer to the camera, At large distances each voxel would be rendered as a billboard sprite with the dust and star density used to select which sprite to draw. At closer distance several sprites. One for the dust and one for each star.
I am worried about the speed though, I think to get the speed I will have to use too large a scale when all the galaxy is displayed. I suppose the only way to find out is to try.
Before I do that I will have a play with some ray-casting techniques. They are easier to implement
Still not sure though. I feel like I'm missing a trick. I have that kind of itch in the back of my head I get when an idea is trying to fight it's way through the day to day rubbish stacked in my head.
Okay I've raycast a 256 by 128 image in software
Doesn't look too bad, I could possibly work with it but I would need to do a lot of tweaking
Needs a lot of tidying up, but I'm not sure it's worth it. The code is very slow. 300-400 mS at a guess
Need to think about it, any ideas?
the code basically does ....
for (int y=0; y<STARVIEW_HEIGHT; y++)
for (int x=0; x<STARVIEW_WIDTH; x++)
float fx = tanHalfFovX * (float)(2*x - STARVIEW_WIDTH)/(float)STARVIEW_WIDTH;
float fy = tanHalfFovY * (float)(2*y - STARVIEW_HEIGHT)/(float)STARVIEW_HEIGHT;
CVec3 d = front - lup * fy - left * fx;
if( castRay( eye, d, t , u) )
starview[pos++] = terrainColor( d, t , u );
starview[pos++] = 0xff0000ff;
Looks puffy, but otherwise neat
Raycasting should be fast if the problem set is simple enough, but even faster would be to reduce your problem to a simple 2D scanline algorithm with mathematical formulas (spiral, spherical falloff) and cached perlin noise texture to dictate the denser regions. Even then, if you're planing on rendering a dozen unique rotating galaxies then you're pushing the limits. If your target hardware is limited to GLES 1.0, I'm going to guess the CPU is probably not that good either. I would say this would be more interesting approach if the end result is to render high quality galaxies, but I'm not so sure for real-time gaming.
Have you considered something more like how Spore does it?
Using a simple particle simulator and billboards, you can pull off a decent looking galaxy. They used a rather large radial distance in their game, but it would be trivial to reduce that and get a more tight look. Best of all, it would be hardware accelerated and you can throw in some animation effects such as simulating pulsars, animating star luminosity, create nebulous regions (randomly placed billboards; I know you luv billboards so much!), and transitioning would be simpler (IMO) when you're already dealing with 3D objects.
My galaxy is defined by a 128 by 128 array. Each cell has a byte for star density, a separate array has dust and colour information.
At the moment I ray cast the star density table to find the intersection point, then extract colour information from the other table.
Using this approach I can move the camera to anywhere, which is what I want, but it looks crap and is slow.
I guess I can try the particle system idea, though it's going to be a lot of work since I don't have point sprites.
I'm just thinking aloud here...
My galaxy is densely packed, over 75% of the 128 by 128 cells are occupied. That's some 12288 cells, I think that's going to be too much for a particle approach.
I could easily split it down into some kind of bsp tree, but it's how to render the cells when they are at the low level of detail setting that I'm struggling with.
If I just create an atlas of 2d sprites and work out which to draw based on view direction..... maybe
How about this,
I use the dust density map to generate 16 textures in each view direction.
Create slices along the x, y, and z axes.
then I draw the 48 textures with additive blending enabled and depth buffer disabled.
but I'll need to do something about edge artifacts........ how about using the dot product between the camera and the surface normal as the alpha value for the blit.
That sounds worth a try. I used something kinda like that for ground fog in one of our games and it was moderately successful. Would be interesting to see if it works better for your case.
I'm guessing you might want 1 - (1 - dot product)\\^n for some power n as the alpha value. Then by adjusting n you can get some control over how quickly the slices fade out when they get toward edge-on.
just done x and y planes at the moment, but looking promising.
Runs real time, still a lot of artifacts, but since the source is only 128 by 128 I don't expect anything else.
Damn I wish I could use shaders
Kind of looks like whip cream
I compressed the volume in the y plane and it looks a hell of a lot better.
I am just adding another term, it occurred to me that the dust clouds are only visible from a long way away. As you get closer the dust density is so low it disappears.
This term also serves as a switch for adding individual stars.
It's not as good as I hoped, but it runs in real time and I don't think I am going to be able to come up with anything better given the limitations.
When I get this extra term in I'll try and grab a video so we can pull it apart and come up with something better.
well I added third plane of textures, turned on additive blending, played with alpha values, looks crap.
especially when zoomed
I really want to avoid having a multi-stage display, 2d long range, 3d short range
Played with star density table and getting better, but some nasty artifacts showing up
Mmmm, upgraded from whip cream to a Danish sweet roll
Looks like you're getting closer to perfecting your solution. It's hard to tell from just the one photo, but the artifacts seem weird given that you disabled depth testing and are using additive blending. Maybe the texture's you're producing are not smoothed out? Using a radial gradient to fade out the texture before it reaches the borders might do the trick.
Damn... why do people talk about food when you are hungry?