Sunday, March 18, 2007
The trouble is that as tightly packed as the game's galaxy is (and its about as tightly packed as I can make it) it still contains a lot more nothing than something. There's really just no way that a standard RTS sort of camera will do. I'm working on the presumption that the most convenient way to move around will be by a goto sort of interface.
I've been putting together a sort of toggle that will let the camera pop up to a view of the entire galaxy and I figure that from there, a mouse click could take the camera down into a closer resolution from there. Will just have to see how it goes.
Monday, March 5, 2007
But I thought I'd take a few minutes to talk about a type of astrographic object that is just the other side of implementation - Barycenters.
A glance at wikipedia's invaluable articles on orbital mechanics reveals that within any orbital system, the objects involved all orbit not the primary (star, or planet) but the "barycenter" of the system. That is to say (in the manner of the Greeks), the center of gravity. In fact, in our own solar system, this point lies approximately along the line between the Sun and Jupiter and lies a few thousand miles outside the sun's surface.
Back last summer, I spent a lot of time grappling with this and came up with some pretty decent code for them. At that time, I was using a database of the actual stars with 50LY of earth as my universe - I had a much more austere, serious aesthetic in mind then. And real space is chock full of binary, trinary systems. And one system within that volume contains 6. yikes.
I didn't have the data describing their actual orbits (in many cases even the astronomers don't know precisely how they move around each other) and so this had to be randomly generated. In the process, whole regions of system space are rendered unteneble for planetary orbits. Code can get a little gruesome, but its not that bad.
But what about Luminosity? At that time, I was doing genuine Luminosity calculations, to derive a range of exothermic temperatures on the planets. And this, combined with the planet's gravity, determines a the minimum molecular weight of gasses that can be retained to comprise an atmosphere (i.e. the molecules would have too much mass/not enough energy to escape into space but enough energy not to fall as snow/ice and stay that way forever). Its a simple enough calc for a single star - run the numbers, get an atmosphereic density and assign a planet type. But what if there are two stars big/close enough together to both influence planets?
This is the problem with a "realistic" sim game. Where do you draw the line? This is not something that can be ignored because you could easily have a Red Dwarf orbiting a hot white main-sequence star at the distance of, like Mars. Given the rules of teneble orbits, a planet could be orbiting that red dwarf out to 0.5AU (Mars is 1.5 AU. For planets orbiting the stars in a binary system, orbits must be less than 1/3rd or greater than 3 times the separation of the primaries). The Red Dwarf would produce barely any warmth on a planet that far away but the planet would on average, be just 1.5AU from the White star and at that distance, there's more than enough warmth from that star to make the planet earthlike.
(Forget the fact that over its "year", the planet would be oscillating between 1AU and 2AU from its principle source of heat producing a whole separate seasonal cycle.)
And it was as I waded into that issue, that I realized why people don't do "realistic" space sims. ^_^
And I started scaling back my design, leading to the hugely simple, comic-book like design I'm working on today. And the thing is, its just better in every way imaginable. There's more stuff to look at on the screen, many other aspects of the design are hugely simplified (maybe I'll post about my stuggles with a warp-drive model sometime) and the list goes on and on. I'm not writing Celestia here.
Still, I did get the orbital mechanics working. And animated it looked reall cool, like a weird mobile. All sorts of suprising configurations would pop out, particularly in the 4-star systems. These I did by barycentering the stars into two barycenters and the balancing those on a another barycenter. This process could go on forever, supporting systems of arbitary complexity but I'm not smart enough to figure out how. Four was enough for me.
Sometimes, BarycenterA would be HUGE and so both of BarycenterB's stars would end up inside the separation space between AA and AB. Or various oddities like that. The interesting part is that it can be really hard, without schematic/diagnostic graphics, to tell just from watching which star is orbiting what. If the system had one big star and 3 small stars, no matter how the barycenters ended up getting randomized, it looked like all three smalls were orbiting the big one - which just sat at the center and wobbled around a little bit. Then throw the planets and the moons into that and it was totally neat.
But useless for a game - you had to have the clock running at like 100 years/second to actually see them move. So it languishes in an archive folder someplace.
I might bring them back, in a greatly simplified form to allow me to create a solar system that has two stars. These would be small stars in a very tight mutual orbit and the planets would all orbit the pair. This would be an anomalous system - zero or one such system would occur in each instance of the game.
Actual binary+ systems I have no use for in this design. My systems are already so close together, there simply isn't room to move them around each other.
Sunday, March 4, 2007
This grid is used for the locating of buildings and resource deposits and could also form the basis of a pathfinding graph (like for an A*) if I ever need one.
These geodesic spheres are then scaled so that the edge length on all of them are the same and this determines the final radius of each planet size within the galactic coordinate system.
For rendering, I take each basis grid and subdivide it a bunch more times. So a large planet's model ends up with about 10,000 vertices.
Here's a planet rendered in wireframe, to illustrate the vertex density.
I maintain a single instance of each of these models in a vertex buffer of Position/Texture, where the texture coordinates contains pre-calculated Longitude and Latitude. I don't really have any use for this but I could do latitudinally-based terrain alterations. Longitude will be used for dayside/nightside calcs. I'm doing these with a dot product in the pixel shader right now but I can drop that computation and use longitude compared to the star's position and the planet's current axial theta instead.
Then there's a second huge vertex buffer that contains the Perlin samples for every vertex of every planet in the galaxy. It ends up about 10MB for a Large Galaxy using a 2D texture coord and takes about 8 seconds to generate. This is a rather greedy use of video memory. If it turns out to be a problem, I have all the hooks in place to create and discard planet sample buffers as the camera moves around the galaxy. Each planet takes 0.1-ish seconds to sample and there are no more than a half-dozen terrestrials in any system so that's just a couple frames of delay.
The other approach would be to maintain a big buffer but only big enough for the fattest system. I keep all the vertex data in system memory as well already, so I can rebuild my buffers during device resets. So I could page just the chunks for the system currently containing the camera. I guess that would work a lot better - just a lock/unlock instead of going back to the perlin.
So when it comes time to render a planet, I set the basis model as Stream and the sample buffer as Stream, with the appropriate offset and out comes the planet.
As of this writing, I do the displacements of the vertices inside the shader, working off the raw noise sample from the perlin. The coefficient is Noise^3 and samples range from -1.5ish to +1.5ish, which results in those nice steep mountains. But I think I'm going to move that calc back into a pre-processing stage during generation. No sense doing Noise^3 thousands of times per frame. And this will also allow me to centralize terrain displacement logic. I need that so I can displace building models and similar.
The other advantage to this is that it will allow me to implement some special handling for certain locations on the planetary surface: specifically mineral deposits. During processing, I can determine the locations of these resources and use the adjacencies on the high-density rendering models to flatten out the "hex" containing the resource. Or flag them to not get rendered at all. Then I can patch in a small model of ingots or crystals or what-have-you. It should look a lot better than decal textures.
There are a lot of unresolved issues with the renderings of planets. They need some sort of atmosphere to help them pop off the background.
This early planetary renderer is doing colors by vertex using an extremely simple lerp. I'm going to replace that with an altitude-based texture lookup. I'll pass the elevation through to the pixel shader and then it can do a 1D tex into the sample swatch. I'm hoping this will result in a smoother blending between terrain types.
Coastlines are a different problem because a pixel is either in or out of the water. The fuzzy dark coastlines you see in the current renderings are what you get when you lerp between Green and Blue. The texture lookup for color should smooth these out, getting rid of the dark band and hiding the hexagonal nature of the underlying structure quite a bit. But I'm a little worried about heavy artifacting right at 0 elevation. I'm betting it would look really static-y right along the coast as the planet and camera move.
What I'm considering is displacing the sea floor vertices down quite abruptly (right now they don't get displaced at all) from sea level. I'll color them based on their depth from a pale blue to a deep blue. And then, right at sea level, render a second, smooth sphere in blue with a 0.5 alpha. The hope is that the intersection of the ocean sphere and the land sphere will produce a nice-looking coastline. But who knows. Will just have to try it.
This ocean sphere could get a specular treatment that might look nice and if I got real ambitious, I could put an ocean waves effect on it.
Both ring and planet are rendered from a 512x256 noise texture I keep around for all sorts of uses. Each planet gets a "TerrainSeed" during generation and that value is used to select a column from the noise. The texture v runs from 0 at the north pole to 1 at the south pole. Then its a straight 2D texture lookup in the shader.
All the specs in the background are stars and and planets in other solar systems. I wasn't doing any sort of culling when I took this image and so the smaller planets also show. I've since added a simple distance cull on non-gas giant planets. Its a rather stark scene - I need to come up with a livlier deepspace background as a skybox of some sort.
Saturday, March 3, 2007
I've taken Kayfess's advice and started up a blog for my hobby programming project. This in spite of his obviously dubious judgement in other matters over which we shall pass in silence.
The project is a RTS/Empire Builder set in outer space and developed in C# and the XNA frameworks. I've been teaching myself 3D graphics programming for a couple years now, and I think I'm finally ready to undertake a playable game. I started this iteration back in early January and have been making pretty good progress.
The game universe is randomly generated and a Large Galaxy contains about 32 systems with somewhere around 150 to 200 objects of all sorts (stars, planets, etc). Unlike earlier attempts, I'm making no attempt at a realistic scale because it turns out that real outer-space has waaaay too much nothing in it. So a large galaxy will typically end up about 20,000 units across where the unit is the radius of the smallest-sized planet.
I'm going to support 4 players in a game using what I think is a fairly typical Lockstep syncronization model, where user input is propogated between instances.
Here's a screenshot
I took this one a couple days ago. That wedge-shaped thing is a ship and the little white box on the planet is the Depot for a colony the ship just established. It was all done with actual game inputs and this represents about how far along I am now.
The picture gives a good impression of the sort of scale I'm going for. That pale blue thing back there is a gas giant, with one of its moons in front of it and there's another planet near the star. Renderings are all pretty rudimentary right now - I'm just bringing these things up to functionality right now.
The next phase of development will culminate in the placement of a second building. This is going to require quite a bit of work in the Input and GUI regions of the code because I need some sort of menu from which to select types of buildings to construct. I'll also need to develop some sort of rendering for the resource deposits (ore and stuff like that) on a planet so that the user can place buildings properly.