So I'm now actually at the stage that I can set destinations for squads. For now, they'll go by "public transport" - the end goal here is that they will fly to the city nearest to the target site, and then drive the rest of the way. Yeah, I'm anal like that.
But, for now we'll settle with them taking the airliner direct to the site. I could cheat here and use the movement trail you can see here:
... as, effectively, a progress bar; indeed, it shouldn't really be possible to alter your squad's destination while they are in flight, not until you get your own air fleet. That would mean I could escape having to figure out how to reposition the squad as it flies through the sky, but I really want to add a neat airliner icon onto the movement trail, so that's my next job.
This is going to get increasingly complex, as I now have to build something similar to the QuadRenderer to draw multiple movement "trails", and also the icons for individual conveyances (which I'll refer to as "Conveyances", since that's my top-level moving-quad-icon class, or "blips" for simplicity). This is problematic since every blip will move pretty much every frame! So I don't really know how much benefit there is to precompiling a vertex buffer for every conveyance.
Showing posts with label 3d. Show all posts
Showing posts with label 3d. Show all posts
Monday, 22 February 2010
HS: mouse picking simplicity
One of the nicest things about XNA in comparison to Java3D is the flexibility afforded when drawing and picking, since you have complete control of the pipeline. For picking, this means that you can implement a lot of low-level smarts that make your job easier.
Whereas in Java3D, a pick ray would pick everything in the scene, even stuff that was occluded or facing the wrong way, with XNA you can implement specific pick tests for each of your objects and pick in whatever order you like. So for now, I run a pick on my Scene, which calls a pick on the Planet, which only calls a pick on the list of Sites (the cities and zones and so on). Later I am sure I'll have to adjust this to encompass the planet too (for adding new bases, and arbitrary waypoints for aircraft).
My picking architecture is to pass a MouseMode and a PickMode through to each object so it can decide whether it can be picked at all, and what the relevant pick action is. Cities can only be picked with the "hover"£ PickMode, which returns their label to be displayed, unless the city has a base in it, in which case they also accept "right click" PickModes, with the pick action being a context menu to display. The MouseMode part is used for things like squad deployment. As you can see here:
By clicking the green button on the Team window, I set my MouseMode to a "squad select destination" mouse mode. This overrides the regular picking behaviour, and it itself knows that squads can currently only have their destination set to a Site, no matter what else is available for picking.
Whereas in Java3D, a pick ray would pick everything in the scene, even stuff that was occluded or facing the wrong way, with XNA you can implement specific pick tests for each of your objects and pick in whatever order you like. So for now, I run a pick on my Scene, which calls a pick on the Planet, which only calls a pick on the list of Sites (the cities and zones and so on). Later I am sure I'll have to adjust this to encompass the planet too (for adding new bases, and arbitrary waypoints for aircraft).
My picking architecture is to pass a MouseMode and a PickMode through to each object so it can decide whether it can be picked at all, and what the relevant pick action is. Cities can only be picked with the "hover"£ PickMode, which returns their label to be displayed, unless the city has a base in it, in which case they also accept "right click" PickModes, with the pick action being a context menu to display. The MouseMode part is used for things like squad deployment. As you can see here:
By clicking the green button on the Team window, I set my MouseMode to a "squad select destination" mouse mode. This overrides the regular picking behaviour, and it itself knows that squads can currently only have their destination set to a Site, no matter what else is available for picking.
Wednesday, 17 February 2010
HS: QuadRenderer
Well, a lot has happened since my last update. I added a set of cities into the game and was rendering them individually until I realized that in order to have them have different textures on them, I would need to set an Effect parameter, and constantly doing fx.Begin() and fx.End() was of course a ridiculous performance hit.
So most of yesterday was spent building a QuadRenderer class to manage the individually textured cities. The QuadRenderer maintains a dictionary of vertexbuffers and indexbuffers by texture, which has to be recompiled if the list of cities / sites changes - I plan to use this also for managing bases, crash sites and really any world elements that don't actually move.
One thing that I learned yesterday was that storing the GraphicsManager.GraphicsDevice in a shortcut variable is a really bad idea - it caused a lot of "NullReferenceException" problems until I removed the reference and just went the long way around.
The other challenge was figuring out where to put the QuadRenderer in my architecture, since ideally there would be a complete split between model and view, but as individual cities are added and removed from the model, they need to to work directly with the QuadRenderer. Since my GameManager is a singleton, I have added a QuadRenderer there, but I am not entirely happy with this solution and can see the GameManager class getting filled up with all sorts of optimization rubbish like this.
Here's a picture of the QuadRenderer in action:
So most of yesterday was spent building a QuadRenderer class to manage the individually textured cities. The QuadRenderer maintains a dictionary of vertexbuffers and indexbuffers by texture, which has to be recompiled if the list of cities / sites changes - I plan to use this also for managing bases, crash sites and really any world elements that don't actually move.
One thing that I learned yesterday was that storing the GraphicsManager.GraphicsDevice in a shortcut variable is a really bad idea - it caused a lot of "NullReferenceException" problems until I removed the reference and just went the long way around.
The other challenge was figuring out where to put the QuadRenderer in my architecture, since ideally there would be a complete split between model and view, but as individual cities are added and removed from the model, they need to to work directly with the QuadRenderer. Since my GameManager is a singleton, I have added a QuadRenderer there, but I am not entirely happy with this solution and can see the GameManager class getting filled up with all sorts of optimization rubbish like this.
Here's a picture of the QuadRenderer in action:
Saturday, 13 February 2010
HS: hires Earth texturing, and bump maps revisited
I've been investigating the thoroughly awesome NASA Blue Marble images, particularly these monthly ones, which I plan to incorporate once I can figure out how to cleanly load 24 separate 4096x4096 textures without running out of graphics card memory. Even the 2km-to-pixel ones are far, far too hires to load all in one go.
So, I've kinda cheated with getting a 8192x4096 Earth texture by splitting it into two and then using the pixel shader to double the y value of the texture coordinates, and use two separate texture samplers, one for each 4196-wide image. It would probably have been much cleaner to create two hemispherical Earths with different textures! Perhaps I will do that another time, if it'll allow me to increase resolution even further. Alternatively, I'm going to have to come up with some sort of mental Level-of-Detail texturing algorithm which, since you can scroll around the earth pretty quickly, would be quite complex. Here's a screenie of where I'm at right now:
You probably couldn't have noticed, but the bump mapping I was so pleased with the other day isn't working properly - obviously, now I think about it, one needs to rotate the texture normal to bring it into the same coordinate space as the vertex normal. There are a few tutorials out there on doing just that, this one appears to be pretty informative.
Next up: variable-rate clock, which will include actually programming a fair number of Neoforce buttons, which'll be interesting. Unlike Java3d, XNA doesn't appear to have a bunch of interpolator classes all hardwired into the system clock, so hopefully this will be quite an easy job.
So, I've kinda cheated with getting a 8192x4096 Earth texture by splitting it into two and then using the pixel shader to double the y value of the texture coordinates, and use two separate texture samplers, one for each 4196-wide image. It would probably have been much cleaner to create two hemispherical Earths with different textures! Perhaps I will do that another time, if it'll allow me to increase resolution even further. Alternatively, I'm going to have to come up with some sort of mental Level-of-Detail texturing algorithm which, since you can scroll around the earth pretty quickly, would be quite complex. Here's a screenie of where I'm at right now:
You probably couldn't have noticed, but the bump mapping I was so pleased with the other day isn't working properly - obviously, now I think about it, one needs to rotate the texture normal to bring it into the same coordinate space as the vertex normal. There are a few tutorials out there on doing just that, this one appears to be pretty informative.
Next up: variable-rate clock, which will include actually programming a fair number of Neoforce buttons, which'll be interesting. Unlike Java3d, XNA doesn't appear to have a bunch of interpolator classes all hardwired into the system clock, so hopefully this will be quite an easy job.
HS: mouse camera
There are lots of tutorials around on how to create an FPS-style camera in XNA. However, no easy to find ones on how to create a click-and-drag mouse camera similar to the Java3d OrbitBehavior class.
Digression: if there's one thing to be said of Java3d it is its suite of sensible helper classes to get you up and running faster, even if you can't do much once you're there. Here's hoping JavaFX finally integrates shaders into Java3d.
My problem is comparatively simple: I want a camera I can click and drag to rotate a camera view around a sphere. In Quake, I'd store the X and Y angles of the rotation and call makevectors() on them to turn the angles into a vector. Not so in XNA, I spent quite a while fiddling around with different ways to solve the problem. Eventually, the easiest way was to only calculate the rotation about the poles using this code I found on a forum somewhere:
And then to magick up the vertical position with a little bit of maths, thus:
... where xpos is the output from using the above function. My camera recalculate position just needs to set the camera position, then it figures out the new view matrix using CreateLookAt.
Digression: if there's one thing to be said of Java3d it is its suite of sensible helper classes to get you up and running faster, even if you can't do much once you're there. Here's hoping JavaFX finally integrates shaders into Java3d.
My problem is comparatively simple: I want a camera I can click and drag to rotate a camera view around a sphere. In Quake, I'd store the X and Y angles of the rotation and call makevectors() on them to turn the angles into a vector. Not so in XNA, I spent quite a while fiddling around with different ways to solve the problem. Eventually, the easiest way was to only calculate the rotation about the poles using this code I found on a forum somewhere:
static Vector3 RotateAroundPoint( Vector3 point,
Vector3 originPoint,
Vector3 rotationAxis,
float radiansToRotate)
{
Vector3 diffVect = point - originPoint;
Vector3 rotatedVect = Vector3.Transform(diffVect, Matrix.CreateFromAxisAngle(rotationAxis, radiansToRotate));
rotatedVect += originPoint;
return rotatedVect;
}
And then to magick up the vertical position with a little bit of maths, thus:
pos.X = xpos.X * (float) Math.Cos(ang.Y);
pos.Z = xpos.Z * (float) Math.Cos(ang.Y);
pos.Y = (float)Math.Sin(ang.Y);... where xpos is the output from using the above function. My camera recalculate position just needs to set the camera position, then it figures out the new view matrix using CreateLookAt.
Thursday, 11 February 2010
HS: normal maps and spheres
So, I've been experimenting with lights and so forth. I had a normal map lying around for the Earth, so I've gone ahead and banged a moving light source in:
Looking a little nicer now isn't it? I've jacked up the sphere quality a bit, too. There was a bit of a struggle getting the normal map integrating with everything else: one has to combine the flat normal map composed of mostly blue (indicating a vector of approx {0.5, 0.5, 1} with the normal as interpolated from the nearby vertices. This is in the pixel shader, of course. Here's mine:
In order to compose the flat normal vector with the interpolated vector, I figured the sensible thing to do would be to subtract the perpendicular vector from the value from the normal map, then add that to the normal coming from the vertex shader. In order to give the bumps a little more oomph I multiplied the difference vector up by 16.
Looking a little nicer now isn't it? I've jacked up the sphere quality a bit, too. There was a bit of a struggle getting the normal map integrating with everything else: one has to combine the flat normal map composed of mostly blue (indicating a vector of approx {0.5, 0.5, 1} with the normal as interpolated from the nearby vertices. This is in the pixel shader, of course. Here's mine:
pf_col PS_LitTextured(vp_pos_tex PSIn)
{
pf_col Output = (pf_col)0;
float3 baseNorms;
baseNorms.xyz = tex2D(NormalsSampler, PSIn.TexCoords).rgb;
baseNorms.r -= 0.5;
baseNorms.g -= 0.5;
baseNorms.b -= 1;
baseNorms = (baseNorms * 16) + PSIn.Normal;
float diffuseLightingFactor = DotProduct(xLightPos, PSIn.Position3D, baseNorms);
diffuseLightingFactor = saturate(diffuseLightingFactor);
diffuseLightingFactor *= xLightPower;
float4 baseColor = tex2D(TextureSampler, PSIn.TexCoords);
Output.Color = baseColor*(diffuseLightingFactor + xAmbient);
return Output;
}In order to compose the flat normal vector with the interpolated vector, I figured the sensible thing to do would be to subtract the perpendicular vector from the value from the normal map, then add that to the normal coming from the vertex shader. In order to give the bumps a little more oomph I multiplied the difference vector up by 16.
HS: trouble with spheres
Having got my mode switching working and Neoforce mostly behaving itself (though I have noticed that it's perhaps stealing keyboard events, something worth investigating), I turned to the task of getting myself a spherical Earth model displaying itself.
My first instinct was to use a prefabbed sphere mesh, one of which I found here. However, I couldn't figure out how to load the vertices out of the model, knowing that I have certain rather advanced plans for my Earth. So, I turned to this code to procedurally generate a sphere for my Earth.
I had to adjust the code to use my homegrown vertex declaration that includes texture coordinates, and discovered in the process how to draw a sphere with texture coordinates that go all the way from 0 to 1 in both axes. There were two parts to this:
1. Adding an extra column of vertices that overlap x=0 with x=1 for texture coordinates (essentially, generating the first vertex in every row twice, once for 0 and once for 1).
2. Removing the triangle fans at the top and bottom of the sphere and replacing them with strips. This is because otherwise you have to set the texcoord of the poles to {0.5,1}, which leads to texture twisting in the triangle fans. Instead, I generated an additional vertex at each pole for each column, these overlapping vertices having gradually increasing x coordinates for the texture.
So, here's my Earth! You can also see some axis lines I'm drawing on, and a Neoforce button on there for testing purposes:
Eventually, as well as lighting it, I plan to calculate surface normals based on a NASA bump map, potentially multitexture it with a nighttime texture, and of course add all the game components such as cities, bases and UFOs.
Two things to do next: allow proper click-drag modification of the camera view, and add a variable-rate clock. Perhaps I will try getting a default light source in first, though.
My first instinct was to use a prefabbed sphere mesh, one of which I found here. However, I couldn't figure out how to load the vertices out of the model, knowing that I have certain rather advanced plans for my Earth. So, I turned to this code to procedurally generate a sphere for my Earth.
I had to adjust the code to use my homegrown vertex declaration that includes texture coordinates, and discovered in the process how to draw a sphere with texture coordinates that go all the way from 0 to 1 in both axes. There were two parts to this:
1. Adding an extra column of vertices that overlap x=0 with x=1 for texture coordinates (essentially, generating the first vertex in every row twice, once for 0 and once for 1).
2. Removing the triangle fans at the top and bottom of the sphere and replacing them with strips. This is because otherwise you have to set the texcoord of the poles to {0.5,1}, which leads to texture twisting in the triangle fans. Instead, I generated an additional vertex at each pole for each column, these overlapping vertices having gradually increasing x coordinates for the texture.
So, here's my Earth! You can also see some axis lines I'm drawing on, and a Neoforce button on there for testing purposes:
Eventually, as well as lighting it, I plan to calculate surface normals based on a NASA bump map, potentially multitexture it with a nighttime texture, and of course add all the game components such as cities, bases and UFOs.
Two things to do next: allow proper click-drag modification of the camera view, and add a variable-rate clock. Perhaps I will try getting a default light source in first, though.
Subscribe to:
Posts (Atom)