Back to work
Hey again, and sorry for the long absence! There was nothing special about it, I’m alive and well - just had a few busy months at my job, shipping some projects and consequently working lots of overtime with little free time for the fun stuff like this game. But that’s dealt with for now, and I’m back to fiddling with this project.
First let’s get the boring stuff out of the way. I moved to Unity 5, yay. Nothing too interesting about that, especially since I’m using Jove (so we already had PBR, neat lights, neat shadows and other shiny goodies for a long time).
Now to something interesting. Environments: how do they work?
As I got back some free time, I started working on a new environment, and as the work progressed on the lovely stairs, railings and pipes, I started questioning the content creation process and scene structure I have adopted a year ago. Lets consider the following environment (as usual, all images are clickable and link to the original sizes).
Before, I would jump ahead and export the whole floor of that structure as a single mesh. But there are some problems with that.
Occlusion culling has nothing to work with. No matter how you spin your head around, the engine will be forced to submit entire enormous mesh to the GPU every frame, even if all you’re looking at is a tiny section of an outermost railing of an outermost platform. Not very nice for performance, especially when dozens of floors like those can be in a frame at once.
Art updates are pain in the ass. Want to change the design of 1m catwalk segment used across 23 environments? Pray you have them all in one file with all instancing links intact and if you somehow actually do, have fun reexporting 23 enormous meshes from scratch.
Lightmapping is horrifying. Good luck getting decent texel density on that chunk when it contains hundreds of square meters and thousands of isolated elements which have to be padded. And speaking of which, you’ll have to recalculate the lighting after you made that tiny change to one catwalk section because duh, all lightmapping UVs assumed a different layout now.
Primarily I’m worried about art changes being pain in the ass, of course. Because let’s be clear here: this is shovelware where I make my fun doing environment art and pretend to touch some code once a year, so any art-related inconveniences really bum me out.
If only I had a way to export individual modular pieces I use in the 3d pacakage, assemble levels from them, and have every environment automatically updated to the newest versions of those pieces every time I export a new version of them. That will solve lightmaps being stretched over enormous objects and occlusion culling being forced to work with enormous chunks. Except wait a minute, that’s already a thing in Unity, and it’s called prefabs.
Nice, now I can change the shape of some railing or a platform and have every instance of them already placed in the scenes perfectly updated. Except in contrast with SketchUp, where you have godlike alignment, movement and rotation tools allowing you to set up perfectly snapped scenes like one depicted above literally in minutes, in Unity you have nothing but few dinky gizmos and a grid. Have fun assembling that scene with hundreds of off-grid attachments and various chained rotations in the Unity Editor.
Okay, that’s not very fun, and fun is of essence here - otherwise what’s the point of working on a game, right? So, if I want to enjoy the niceties of prefab use, I need to do one of the following:
Figure out a way to save scenes from SketchUp: should definitely be possible by writing a SketchUp plugin with will serialize positions/rotations/scales/ids of components into a file and a Unity tool which will use that file to instantiate stuff in the scene. Except I’m too lazy to learn Ruby and SketchUP API to write something like that.
Figure out a way to replicate the tools I use in SketchUp in Unity. Sounds harder, but hey, I can probably avoid learning something new that way, so let’s definitely choose that.
Replicating whole toolset and inferencing system from SketchUp sounds like a year-long project, of course, so first I thought about actual intent of my actions there and the tools I used most frequently to accomplish my goals. What was my intention? To snap stuff together, of course.
And it just so happens that there exists a perfect inspiration for a system to snap stuff together. It’s the craft editor in Kerbal Space Program.
You have parts, parts are objects with nodes, nodes snap together, dragging object rotation and position into a very specific place. How about implementing something like that for level editing? Define attachment nodes once per object type, save the object to prefab, reuse the nodes forever for automatic perfect attachments. Once you drop more complex and irrelevant parts of KSP editor attachment system, like pointer-attached hovering pieces or surface attachment, the spec for your system ends up pretty simple. And so I implemented something like that:
The attachment is performed after four simple clicks. First click selects the attached object (one which will be moved into place), available nodes on that object light up; second click selects the node which will be used for attachment; third click selects the parent object, available nodes on that object light up; and finally, fourth click selects the parent node used for attachment. Works nicely. Except the instant nature of attachment is pretty disorienting - you can’t exactly wrap your head about the movement and rotation of objects, and frequently make mistakes because of that, misjudging the sides that have to be attached and such. I’m still unwilling to implement KSP-like pointer-attached pieces hovering around, so let’s try another route: animating every change.
Implementing simple in-editor tweening system every change is submitted to instantly makes things more readable and satisfying. But we’re only starting, of course. For once, those standard spheres look boring, we should outdo KSP by using something nicer.
As an added bonus, those peeled spheres visualize the rotations of the nodes, which is very useful for checking whether they are configured correctly. Let’s also implement attachment node types, so that it’s impossible to attach together pieces that should not go together, like a 3m pipe cross section and a ladder, and add neat labels on top of every node showing you their types:
Okay, some basic use cases covered. Except it’s still impossible to assemble the environment from SketchUp screenshots in the beginning of the post. Why? Because of those pesky chained attachments using diagonal pieces, which make it impossible to close the loops without case-specific unique segments of weird lengths like 1.279133m. How do we solve that?
By implementing stretchy pieces, of course. The concept is pretty simple - those are supporting segments that have no turns, only have nodes on borders on one axis, and stretch themselves on that axis to meet the selected parent object. If the arrival position of the endpoint node matches the node of a parent object, the attachment is performed straight away - if not, then you have to do some alignment on another axis using another stretchy piece. Works quite easily once you get the hang of using them. Let’s also implement a way to quickly swap the attachment point:
We also have a problem with pieces like stairs. One-sided platforms can be flipped around to accomodate any direction, but pieces like wall-mounted stair segments will always go up or down relative to a wall. So let’s solve that too.
Yes, fancy lights and neat arrow models are mandatory, I don’t want those scrub tier default gizmos offered by the editor. :^) Now, what about pieces like pipes which should have an option to rotate around the attachment point to allow spaghetti-like mess from the first screenshots? Let’s implement that too.
Let’s also add a way to quickly clone the selected piece (nope, standard duplication isn’t suitable, as we want to reliably modify the state of our custom component every time we do duplication like that):
Okay, I also did that because I wanted a nice animation on pasting. Don’t judge.
So, with that covered, what do I have left? Evidently I do have some stuff left to implement, because the post is missing some in-Unity screenshots of that fancy environment from the beginning. Let’s see:
First of all, I need a way to group multiple modular objects into prefabs. For example, to create a floor out of 20 pieces or a neat reusable tangle of pipes out of 15 pipe pieces. It just so happens that Unity has absolutely no support for nested prefabs, so if I would save anything like that into a prefab, I would lose prefabs linked to individual pieces and would lose a way to reliably update them. Anyway, long story short, I’m almost done with that - I’ve implemented a simple imitation of nested prefabs that works fine enough for the specific case of saving and instantiating a group of modular objects. It can be saved into a prefab but it keeps the child modular objects as prefabs too, which is neat.
Some additions left with that, but overall it works. I hope it will be easy to adapt the resulting chunks to work with the procedural level system I have outlined in the previous posts.
Another problem I have to tackle is recursive operations. It’s not an immediately obvious thing, but I’d like to be able to do stuff like rotation or detachment of pieces in the middle of a long connection chains, which every subsequent attachment being rotated or shifted in sync with their neighbours. This is hard to implement, but should be possible, and will make it easier for me to iterate through multiple designs quickly.
That’s it for this post, I guess. Future is looking bright.