Saturday, June 20, 2015

Subvoxel Terrain

Range of subvoxels I currently have implemented
In my first pass at subvoxel terrain, I'm trying to shoehorn a random Perlin Noise field into a bunch of subvoxels. Instead of a single integer height value, I could use of the subvoxels pictured at right.

For now I'm sticking to just eleven possibilities: the solid voxel (duh), the half-slab, and the nine sloped options at the bottom-left of the picture. In other words, I can now support elevations at the corners -- that is, four elevation values go into deciding what to draw at each voxel.

There's some tricks here. What if the highest elevation is in a different voxel? Before I get into that, let me describe how I'm thinking about the problem.

First I pick a lowest integer voxel value; one that's at or below the lowest corner. This value I call "0", duh. Then the corners are numbered according to how many half-voxels they are above that voxel. The lowest corner could actually be a 1, or even a 2 -- the latter case if the lowest corner is 0.75 units above the floor.

The set of options I have to work with are things like 0011 or 0222 or 2202, etc. There's three ways to consider the numbers: as they are, with the northwest corner first; rotated, such that the lowest corner is first; or as a generic set of corner values. There's 15 possibilities in that set, btw, which I'll leave as an exercise for the reader.

15 possibilities -- if each corner is 0, 1, or 2. But what if I have a voxel where my corner values want to be 0, 1, 2, and 3? Or 1, 3, 5, and 9? That I'm just punting for now, actually. I've got some shapes that I could rotate such that I could handle a combination (clockwise) like 0044, and I'm planning on adding a couple shapes that would handle 0033 or 1144 or 1133. Maybe I need to add something for 1333? And I could do a two-voxel stack that would handle 0242.

I think options like 0244 is just right out; that would require a radically different way of handling voxels. Converting corner elevations to subvoxels is a bit of a "hack" -- taking what I have in the engine, and trying to find a simple way to generate undulating terrain with something other than plain stairsteps.

OK, so what DO we have? Let's take 0000, 1111, and 2222 first. In this cases, I have no voxel, a half-slab, and a solid voxel. Simple enough.

Next comes combinations of two height-values. The nine angled shapes in the front-left of the image represent the (clockwise) combinations 2211, 1211, 2221; 1100, 0100, 1110; and 2220, 0200, plus 2200. Note that I haven't implemented 2121, 1010, or 2020. With rotation, these shapes can handle all of the possibilities of two numbers (again, minus the 2121 1010 and 2020 cases).

There's also the problem of voxels like 1133. What do I do with that? If I'm not going to do two voxels (and I don't have the shapes for that yet), do I force that to 1122, or 2233 (and raise the surface voxel up one unit)? For now, I've got some simple logic that decides; I don't know that there's a one-size solution, so I went with "close enough" and we'll see where that gets me.

subvoxel terrain test world
So that's what I do. Simple pattern-matching. Here's what it looks like now, and it makes plain -- I need to fix subvoxel lighting! Guess what I work on next? :)

Saturday, June 6, 2015

Voxel-Based Lighting

Smooth voxel-based lighting
So, like, how do you light a voxel world, anyway?

I'm using Unity. However, my terrain is procedurally generated at run time. The data can be saved and loaded, but it's not like I'm building a Quake level here. My Unity scene is empty. Stark. Bare. I can't use all those fancy Unity tools for lighting. No lightmaps, no light samples, no baked radiosity, nothing.

And it's a sandbox voxel world. Voxels come and go, so I can't do anything fancy that requires precomputation. Whenever some user walks up and deletes a voxel, I've got to redo lighting. And if you've played Minecraft much, you know that you've got to kinda dump torches every 10 meters. All over the place. A distant view of your castle will have hundreds of light sources.

From playing the game, one can guess what Minecraft does. You might be wrong. At some point, lighting for a voxel was calculated by shooting out rays from each voxel into the sky, and the number of those rays that made it determined the light value for that voxel. This only works outdoors, though; what happens when the sun sets? What do torches do?

So the next guess has two parts: (1) Anything directly exposed to sunlight gets lit at full brightness (during the day). (2) Everything else seems to be lit by light values in a voxel slowly dropping from voxel to voxel. A voxel "in the shade" (ie not directly exposed to sunlight) but that is next to such a voxel will be lit just one tick darker. And so that's what I did.

The next trick is to figure out how to light each quad in the world. (With all my subvoxels, I've actually got to worry about WAY more planes, but that's a different story. Let's pretend we're doing strict cube-only worlds for now.) Lighting is there to see stuff, obviously, but we've got two main goals with the light algorithm: to model light occlusion, and to model light radiance.

The first means that something not facing a light source should be darker than something facing it. Further, if a quad faces a light source but is occluded by an intervening object, then it should be darker. In a simple game engine, we could model the sun using a shadow map, perhaps rendered in screenspace, to indicate which parts of the world are exposed to a light. But, again: 100+ lights! This is madness. We need a solution.

The second term -- radiance -- means that, even if a quad isn't exposed to the sun, it will pick up light bounced off of other surfaces. Ideally, the surface should colorize the reflected light. This gets tricky with sunlight, however, since the sun itself isn't in the direction of sunlight. Sunlight comes from the whole sky, bouncing through the atmosphere, although most brightly in a straight line. That bounced light is what makes outdoor shadows soft-edged and light. We kinda want an HDR solution here; a way of providing tons of resolution to the "how much light is here?" equation, as well as handling the fact that the human eye will adapt to the total amount of light in the environment.

But I get ahead of myself here.

So let's go back to the "simple" MineCraft-style solution. Any voxel directly exposed to sunlight gets the maximum light value. Any voxel with a torch in it gets the maximum light value. Other light-generating objects (jack'o'lanterns, ovens, glowstone) get the same treatment, although their light values are lower. Next, every other voxel gets assigned a light value that is one less than the most brightly-lit neighbor.

I'd love to colorize this light value. I'd love to directionalize it, so that we're actually modelling radiance; that would mean assigning 6 light values to a given voxel, with each value being not just a 4-bit value but an actual color. Maybe a full 32 bits. And maybe rather than the 6 cardinal directions, we could model 18 directions (the 6 + the 12 diagonal directions along plane lines) or 26 directions (ie to all neighboring 26 voxels in a 3x3x3 cube around our source). Do we have processor power for that? Hurm. Dunno. There are real-time lighting solutions for complex-geometry games that compute light in six directions, eg using a clipmap, that can model complex interactions.

But... well do we really need that much detail?

Ok, so let's go back. Let's just get something working. We got a light value at a voxel. How do we light quads?

The goal here, really, is to provide consistency. Take a 2x2 chunk of grass voxels, sitting in a plane under the sun. The intersection at the middle of the four top quads of these voxels should be seamless. Or not; that's a choice here. Minecraft Classic only lit quads by whether they were facing the sun or not. It was a simple directional one-light system with an ambient factor. You could tell which way a poly was facing by the lighting on its quads. At some point, MC introduced smooth lighting, and that's what I'm talking about here. Smooth lighting looks sooo much better. So that's our goal. (When did MC add good support for both sunlight and moonlight, and torches, and the rest? I don't know. I'm not too interested in the history here.)

So the solution I've used is to come up with a clear definition for the lighting at any given vertex based upon neighboring voxel light values and the facing of the tri. (Remember, I'm dealing with subvoxels that have many faces not in any of the 3 axis planes.) In the simple case, at a corner such as our 2x2 chunk of grass voxels, lighting at the corner is the average of the light value of the four voxels directly above the grass. No matter which voxel you look at, that voxel's quad will have the same light value at each corner.

This gives us partial occlusion for free. If one of the four voxels above a vertex is solid, then that vertex will only be 75% lit. Two voxels, 50% lit. Three voxels, 75% lit. And we let the graphics card smoothly interpolate lighting across the quad.

Take a look at the image. The red area seems odd; why the bright contrast? Well that's cuz the bright bit faces out into the sunlight, while the dark bits are directly under the tree. (Sidewise light propagation is turned off in this image.) Inside the blue circle, you can see that corners get progressively darker.

There's algorithmic hoops to jump through to get this working fast, but do you really want to know about hashsets? I'll skip those details for now.

Friday, June 5, 2015

Top 3 Keys to a Successful Kickstarter

SteamShards, the (current) name of the project to which all this terrain generation is going into, will be up soon on Kickstarter. Here's a preview to it.

I haven't posted much here lately because ... well I've been busy on lighting, and then writing all the code to handle the various subvoxel shapes (863 at last count) and proper lighting for them. I think I'm going to write a post on voxel lighting, actually.

There's tons of information out there on Kickstarter. I haven't launched yet, but I've got some comments on the campaign-creation process:

Video is top, I think. From everything else I can tell, having a video has the single biggest effect on sales.

It's weird to calculate that, though. I think the greatest multiplier might be being able to spell, and/or not looking like a tool. So, like, #0 is not looking like a fail project. I've seen kickstarters that basically said "I want to eventually be good enough to be a game dev," kind of a "fund my life" sort of goal with no reward. Those failed. Many failed projects were "I'm going to remake this obscure game from the 90s, and I need $100,000 to do it, and btw I'm still in high school." All sorts of things wrong with that: the tiny market, the outsized goal, usually bad grammar and art, but mostly very little evidence to suggest that the creator would be able to finish the project.

So #1, really, is "don't suck." Avoid bad mistakes. Have a video, include screenshots, have a key reward that people actually want. Spellcheck. And, if English isn't your native language but you're trying to sell to an English-speaking market, try to get a native speaker to review your page. If English is your native language but you're currently in 9th grade and failing at spelling... then you're not ready for Kickstarter yet. Hmm. I don't just want to complain though. If you are currently 23 and you have a great idea but suck really bad at spelling and grammar... then find a friend or partner to help. Put an ad in Craigslist for a copy-editor for $100. Ask a mate, spouse, girlfriend, mentor, whatever.

#2 is "be believable". You've got to convince people that you can finish the project and deliver the rewards. $25 or $40, sure, I could buy that project. But if I don't think the rewards will come, then I've got to weight that $40 against the chance I actually get the reward. If the project doesn't meet its funding goal, then OK, no cash lost. I'm fine with that. There's two parts to being believable: first, actually BE capable of finishing the project, and second, communicating that to people. Many of the failed projects I've looked at (and I've scrutinized a couple hundred projects) fail because the creator doesn't look like they know what they're doing. High school kids that want to make the "biggest" zombie game ever, someone that wants to make an awesome RPG (one of the most technically different game genres out there) but is currently only an artist, a team of one that wants to build the next MMORPG, stuff like that. It's possible for one person to make a game by themselves, but that usually means simple art, simple design, and/or simple tech. Middleware like Unity makes building a game much easier, but it doesn't provide any game design.

I've seen those projects, though. Unity is great! Someone buys a bunch of assets and scripts from the Unity Asset Store, throws them together, makes a build, and somehow gets the project onto Steam. It's buggy as hell and doesn't do much, but the assets look great. Those devs lived off of backers for a couple years, but now their reputation is ruined and they've got to switch to driving a taxi or working at dad's dry cleaners. Meanwhile the backers have gotten more sophisticated, more cynical; they'll look more closely at who they're willing to back.

To me, that means the gold rush is over. You'll no longer find placer deposits.

#3 is having a hook. That obscure game from the 90s is not a hook. "It's like Game X, but it has Feature Y!" That's your hook. Some hooks are more compelling than others. "That obscure game from the 90s, but MODERNIZED!" Well, um, ok, what does that mean? I don't even know what game your talking about. That's not a hook. "That popular game from the 80s, but MODERNIZED!" Well hey, here's a hook: that popular game from the 80s.

I think for SteamShards (that's my project, btw), I've got two hooks: steampunk, and subvoxels. Minecraft has procedural terrain, voxels, exploration, adventure, "world gates" (kinda; although there's only 3 worlds). I've also got Minions, Cities, and Invasions, though, but they're not really my hook. I'd like to think that the City complex -- cities, bad guys invading your cities, you having to defend your cities, and minions to help you do that -- are a good hook, but ... it's also complex gameplay. I don't have that working; I can't show that off. I'd love to talk about it, but that's a future hook. I'm not sure how to categorize that.

OK, so that's my Top 3 Keys to Success. I think I'm currently failing at #1 -- I need more graphics and a video for my project. I will definitely have those before I launch.