A texture jackpot

•July 20, 2009 • 5 Comments

This update is sort of like two-in-one because I fixed two problems in the past few days:

  1. The texture is now made up of a series of smaller textures rather than flat pixel values.
  2. The texture generation algorithm now blends the different layers into each other.

I think the results speak for themselves:

globe-textured-beautiful.png

Next up: boring old optimizations and efficiency fixes. This globe took a full four minutes to generate, about 3.5 of which were eaten up by my super-slow heightmap generation algorithm. That’s the first target, and I think I can dramatically improve its speed.

My problem is that right now I read and write one pixel per calculation, which is horribly inefficient, as any techie can tell you that disk reads and writes are some of the slowest operations out there; it’s orders of magnitude faster to write a 1-gigabyte file than to write 1,000 1-megabtye files.

With this in mind, I think I’ll do the reads upfront, load the written values into an array and then apply the final pixel values all at once when the calculations are finished, rather than one at a time. This approach will be tricky, as I’ll have to figure a fast method of converting from 2D (a plane) to 1D (an array) because my heightmap algorithm right now works by calculating 2D distance, which sort of doesn’t work if you happen to be working with fewer than two dimensions. Ultimately, though, it’s the only way, as performance is pretty horrific right now due to this bottleneck.

Oh, and I’d also like to increase the resolution of the textures, but the efficiency fixes come first unless I’d like to wait until I’m an old man for a high-res globe to complete.

DAS TEXTURE IST HIER

•July 17, 2009 • 1 Comment

Days of slaving over my algorithms has finally paid off! I have successfully managed to generate a texture from a heightmap and apply it to my random globe. As usual, this is a rough attempt and the visual quality isn’t where I’d like it to be yet, but there are a squillion tweaks that I can do now that I’ve finally cleared the hurdle of randomly generating a texture pixel-by-pixel to begin with.

3-globes-textured.png

This graphic is similar to the last one, only with the addition of the texture. At the top is the finished globe; beneath it is the texture that has been applied to it; and beneath that is the extrapolated heightmap that was used to generate the texture.

More Updates will follow shortly. The approach I think I’ll try next is documented here (scroll to the bottom for the ultimate goal), and I think it won’t be long at all until my globes are looking as nice as the terrains there!

An idea…

•July 14, 2009 • 2 Comments

I’ve found no less than a treasure trove of resources on how to create terrains and textures from heightmaps, but this hasn’t helped me, because I’m bypassing the heightmap entirely by creating the terrain myself rather than creating a heightmap and generating the terrain from it.

But I’ve been really banging my head against the wall about this texture issue. And then it hit me (the wall, maybe!): if I can super-easily generate a texture from a heightmap, how hard would it be to create a heightmap from a terrain? If I could just do that, then I could make a terrain from it with no problem.

It intrigued me. The biggest problem I was running into was that there weren’t enough vertices to paint one pixel per vertex; I would up with unpainted black areas. I had contemplated drawing circles or even fancy radial gradients, but I had NO IDEA how I would get the colors to mix properly given how colors are stored in Unity.

But it would actually be very easy do draw circles or gradients if I didn’t have to worry about complicated color mixing. And I wouldn’t have to worry about complicated color mixing if there were only one color. And there’s only one color in a heightmap…

Everything seemed to be pushing me in the direction of generating a heightmap from my terrain mesh. Which is funny, since heightmaps are almost always used to generate meshes themselves, not the reverse! Still, it had some promise.

Having decided to do it, I had to figure out how to draw radial gradients pixel-by-pixel. Summoning up all my high school math knowledge, I actually managed to do it! Basically, I had each pixel calculate its distance from the center and dampen its color value accordingly: a pixel right in between the center and the edge would be 50% as bright as the center pixel; one 90% to the edge would be 10% as bright as the center one and so on. Then I just had these pixels add their color values to the color values of the pixels they were about to replace. In other words, a bright pixel that gets a bright pixel painted on top of it becomes twice as bright.

Here are three random globes and the heightmaps they generated. I stuck the heightmaps themselves onto the globes in lieu of textures because I couldn’t stand those beastly squares any more.

3-globes-heightmaps.png

The next step is basically to loop through the heightmap and determine for each pixel what color to apply to the pixel in that same spot on the texture. It seems easy, but I’m still working on it. And there’s an obvious performance hit to adding this intermediate heightmap generation step, but I think it’s worth it if it gets me farther to my goal. And once I reach it, maybe I’ll figure out how to create the texture without a heightmap.

It’s time for another one of those “good news/bad news” posts

•July 11, 2009 • 2 Comments

The good news: I finally got an algorithm to generate a UV map for my deformed sphere!

The bad news: So far, the end result is hideous. Like, really hideous. Are you sure you want to see it? No, really, it’s really bad. Well, don’t say I didn’t warn you.

Globe-texure-hideous-.png

My god, it’s covered in squares! Before you projectile-vomit with laughter, let me explain the reason for this visual travesty.

You see, I managed to generate a UV map by looking at each vertex and calculating what that vertex’s UV coordinate should be. My globe has 10,242 vertices, so its UV map will have 10,242 UV coordinates. Great! So now I want to apply a texture to it, right? So my current method is to look at each vertex and determine what color to apply to the pixel on the texture that corresponds to that vertex (which I look up by asking for the vertex’s UV coordinate). So this means that I’ll end up with 10,242 colored pixels, one for each vertex.

Therefore, there had better beat exactly 10,242 or fewer pixels available in my texture, or else there will be gaps in between the colored pixels. In a 64×64 texture, there are 4096 pixels available, which is fine. In a 128×128 texture, there are 16,384 pixels to fill. Oops, I only have 10,242 pixels worth of color! What are those poor unfilled leftover 6,142 pixels going to do? As you can see, if I go above a 64×64 texture, I’ll wind up with uncolored gaps:

Globe-tex-comparison.png

This bites the big one, since a 64 bit texture is so small that it isn’t even worth considering. What I really need is a 4096-bit texture so that you can zoom in really close and see the details. Only, right now there aren’t any details. If I tried to color the pixels of a 4096-bit texture, I could only fill a measly 10,242 of the 16,777,216 pixels, giving me a big black texture speckled with tiny colored dots at regular intervals.

So I cheated. I used a large texture, but instead of painting one pixel worth of color for each vertex, I had it paint a big square of color instead. Look ma, no more gaps! Yeah, yeah, I know, ma would flay my skin off with a cheese grater if she saw this crime against programming, but it’s all I could come up with late at night. In case you’re interested, here’s what the actual texture for the large globe at the top looks like:

SavedScreen.png

(there are still some gaps toward the poles, but they don’t really matter since the texture sort of folds in on itself around those regions)

It would be really cool if I could use circles rather than squares to make it look more organic, but I’m still wrapping my mind around the Midpoint circle algorithm. I’m also looking into blurring together the colors, which is something that Photoshop makes it seem much easier than it apparently really is to do. Still, progress is progress!

The UV problem

•July 9, 2009 • 2 Comments

So I’m having UV problems with my sphere. The general question is: “how do you get a 2D image to wrap onto a 3D model?” Here’s a quick explanation of just what UV mapping is and how it works for that indisputably tiny minority who is interested but doesn’t already know.

a UV map is a 2D representation of the surface of a 3D model. Imagine you have a pair of pants. Well, those pants are three-dimensional, and therefore you can’t see all of the outside surfaces of the pants all at once. If you wanted to apply a pattern those pants, you would have to turn them around so you could see the non-visible parts. But imagine you live in a dismal world where you aren’t allowed to rotate your pants. Now imagine that some cruel, haughty taskmaster hands you a piece of butcher paper with zebra stripes on it and informs you that your job is to somehow wrap the paper around the pants without being able to look at the pants from multiple angles, with the ultimate goal of producing a pair of zebra-striped pants.

So, what you do is you undo the stitches on those pants. This leaves you with a bunch of pieces of fabric that you could lay down flat on a table, and then you would be able to see all the pants at once, just not in their assembled (3D) form. Now you can simply lay the butcher paper on top of the flat pants pieces and glue them into place. When you re-stitch the pieces, the butcher paper stays on the pieces, giving you your zebra pants.

This is what UV mapping does. You unwrap your 3D image into 2D pieces and then lay them out so a 2D texture can be painted on them. Ordinarily, this is a process you complete manually in your 3D program. It’s more of an art than a science, and there are many stunningly clever techniques to pack UVs into a square plane that I don’t know yet, but I can do it. However, I can’t pre-generate a UV map for my globe because It’s not a globe anymore when it’s finished being altered by the planetary evolution algorithm! So if I make a UV map that’s accurate for a sphere, it’s not accurate for a deformed sphere. There are seams and ugly black lines and all that jazz.

That’s problem #1. Problem #2 is getting a mapping between vertices and UV coordinates. I need a way to ask a particular vertex on my planet mesh, “hey, what UV coordinate are you at?” I need to do this so I can dynamically generate my texture by looking at each vertex’s elevation and determining what color to assign the texture on the part that corresponds to that vertex. So even if I could pre-generate the UV map with 100% fidelity, It would only solve half the problem because I would still need a way to figure out which UV coordinate a particular vertex corresponded to.

All this is pushing me in the direction of having to generate the UV map in code as soon as the base planet mesh is suitably deformed. If I did it vertex by vertex, I would automatically know which UV coordinate a vertex represented, and I could create a UV map appropriate for the final mesh.

Unfortunately, this is really hard. I’ll probably be bashing my head against it for a while, but I think I’ll get it eventually.

Tweaks

•July 8, 2009 • Leave a Comment

I’m having a lot of trouble getting the globe to accept textures rather than vertex coloring. It’s all about a complicated interaction between the globe’s vertices and its UV coordinates, but I don’t feel like writing about it right now. Maybe I will in a few days if I haven’t gotten it sorted out by then.

So I made some tweaks to my vertex-colored globe in the meantime. These are changes that’ll be used in the eventual textured globe, so it wasn’t wasted effort, and it won’t be hard to port the code. The biggest change is in the geometry algorithm for the land masses. Previously, any elevation was accompanied by a corresponding depression on the opposite side of the globe; this means that there was guaranteed to be an ocean opposite a continent. In a few test globes, literally half of the world would be a continent and the other half would be water!

I also applied different colors to the ocean based on their depth, just like for the land. Previously, the ocean was another mesh that was 100% opaque blue. Obviously that would obscure the new colors, so I made the water mesh about 10% transparent. I think it looks pretty nifty:

Globe-ocean-contour.png

Success!

•July 7, 2009 • Leave a Comment

Well, sort of. The good news is that I figured out how to make a procedural shader that changes color based on elevation. The bad news is that so far it looks hideous! Here, let me show you:

Globe-vert-colors.png

I know, it’s awful, right? Still, it illustrates what I’m trying to accomplish, which is dynamically tying color values to elevation. The reason that this is so garish is that I’m using vertex coloring rather than texturing. Essentially, each vertex has been given a color based on that vertex’s distance from the center of the sphere — the farther from the center, the more mountain-like the color should represent. This means that the image’s resolution is tied to the vertex density. In the interest of performance, the globe mesh only has about 10,000 polygons, so you can pretty clearly see where the vertices are located at by looking at the borders of the colors. My implementation also doesn’t take into account lighting and shading. Oops.

Needless to say, there are a whole host of changes I’d like to make. Blending the colors into each other, using image maps instead of colors, generating lightmaps and shadows, etc etc etc. No doubt I’ll have to switch to texturing, which invites a bundle of complications such as generating UVs, interpolating between vertex and UV coordinates, and creating tileable images, but I may have to. In fact, it’s almost certain that I’ll have to, so I might as well.

 
Follow

Get every new post delivered to your Inbox.