It’s now 1999, and I have an odd job. Our product is a multi-user social environment. In four years, Second Life will show up and make a more successful version of this idea, but for right now we’re doing pretty good. Sometimes clients come along and ask us to build custom environments for them. A lot of these projects land on my desk.
I’m technically an “artist” in the sense that a lot of my job involves creating models and textures. But I’m more an engineer in terms of inclination and skill set. I don’t have a solid grip on aesthetics and I really envy my fellow artists who can nail a particular architectural style like “Gothic”, “modern”, “whimsical”, or whatever. I don’t have the flair for that sort of work. When I need to make something, I have a very literalist, brute-force approach to designing stuff. If someone sends me sketches or reference photos for what they want, I’m likely to just build exactly what I’m shown, while the real artists on the team are able to get the “vibe” the client is going for.
In any case, I see myself as a bridge between artists and engineers. I make tools to help automate some of the drudgery work of the art pipeline and sometimes I come up with solutions to time-consuming problems.
At one point a client comes along. They want something that looks like an indoor corridor shooter. The problem is that our software is not designed to render BSP based levels like that, and our tools aren’t designed for making those sorts of spaces. Imagine trying to build an Unreal Tournament level with the Fallout 4 building interface, using stuff like one-meter rectangular panels, and you have a sense at just how maddening and fussy the job was going to be.
We don’t really have good tools for building something like this. The 3D modeling program we use is called truSpace. It’s basically tolerable for making small-scale models. It’s okay for making stuff you might put IN an environment, but it’s terrible for making the environments themselves. It’s fiddly and buggy and the interface is inscrutable. The most egregious shortcoming is that the program can't do boolean operationsCombining two shapes together. For example, use a smaller cube to carve out a hollow area inside of a larger cube. to save its life. Some of my friends at work have a saying we use: “Truespace is a 3D program that is bad at math.” Subtract 3d object A from B, and you have 33% chance it will work, a 33% chance it will do something that makes no sense, and a 33% chance it will crash.
My solution is to build the level using a modern level editor. I build the level using the awesome Unreal Edit, which comes free with every copy of UnrealI wonder now if I was violating some sort of license agreement? At the time it never even occurred to me.. Once I’m done I export to a generic (non-Unreal Engine) format. Then I write a program to parse that file and convert it to our own format. This is a bit of a challenge. The Unreal Engine has a very different system from what we’re using. They use different coordinate systems at different scalesIn Unreal, the Z in XYZ is up, and 128 units = 1 meter. In our world, Y is up and 1 unit = 1 meter, and I think some of the XYZ axis might be flipped.. They have different ways of defining polygons, different ways to defining what textures are used on each polygon, different ways of expressing how those textures are mapped onto the polygons, and different ways of expressing the lighting and surface properties. This foreign format isn’t documented, so I have to do a bit of reverse-engineering to figure out how it worksThese days it would just be a Google search away. But in 1999? Not so much..
At least the file is text-based. I can open it up in Notepad and try to make sense of it by reading, which is better than groping around in a formless soup of binary data.
The converter works and turns the videogame level into a single object that we can use. That solves part of the problem. Now we have the level in our 3D world. There are still two problems:
Our software can’t support this many polygons in a single model. Once a model has more than N polygonsI forget the value of N. Maybe a thousand?, the collision detection assumes the object is a decorative statue or other object that doesn’t need per-polygon collision checking. Instead it will ignore the object during collision checks, thus making the whole thing non-solid. This is a safety measure we put in place because our software features a lot of user content and users tend to be reckless about adding heavy, CPU-sucking assets. The result is that you can view this level, but you can’t stand on any of the floors or bump into any of the walls.
Since the world is usually made by users building with prefab pieces, we can’t use the usual optimization tricks that games like Unreal and Quake use. In Quake, the developers run a program to figure out what rooms can be seen from which other rooms, so the game only draws what is completely necessary. It’s not possible to use something like this in a world where users are constantly moving and changing things. So we have to rely on the stone-age technique of “draw distance”. If you get more than N meters from an object, it will vanish from view. N is a variable that is controlled by the user, by changing a setting in the graphics menu. The problem is that this building is all one object. As soon as you get N meters from the origin of the building, it will vanish and you’ll find yourself in empty space, plummeting into the void belowIgnoring the fact that you’re ALREADY plummeting into the void, because you can’t stand on the floors.. Even if you set all of your graphics options to maximum, it still won’t be enough to allow you to explore the far reaches of the level.
My solution is to write another program that tears the entire level apart into its component polygons. Then it groups the polygons according to texture and location. It creates a new origin for this group. So instead of one big object, we have thousands of little ones. These objects are kind of funny. One object might be a couple of huge triangles that make up part of the floor in one room, along with one side of a pillar and half a door frame. It’s a bit like those 3D puzzles where individual pieces don’t make any sense, but when all the bits are in place it forms a seamless whole. My program effectively tears the model apart and then places the pieces in the world.
Sure, the artists could have built all of these pieces by hand in their 3D modelling program of choice. But if they needed to make a change – like making one room slightly larger and doubling the number of support pillars – it would require a ton of fussy work and changing many different objects. Instead, I just change the level in Unreal Edit and run my converter program.
This job would have been far too technical for the artists. Meanwhile, the programmers working on our core product wouldn’t have known about this problem because they weren’t concerned with the art production stuff. And even if they did know about it, this solution wouldn’t have occurred to them. And even if it did, they would have seen it as a low-priority job that took them away from the all-important core product.
As a result of being this odd artist / programmer hybrid, I am able to turn weeks of work into a couple of days of coding. I LOVE jobs like this, although the downside of being the only art coder on the team means that nobody is really in a position to appreciate just how much time I’ve saved us.
The other downside of having this skill set is that I’m seen as a socially high-functioning engineer. If we need to have a feasibility conversation with a client then I’m the one called into the meeting because I’m not going to baffle anyone with technical jargon when I’m asked a question.
See, just about every engineer puts “good communications skills” on their resume, and in the vast majority of cases it simply isn’t true. It’s not that they’re lying, it’s that they have no idea what “good communications skills” means. They think it means stating things bluntly and accurately. They transmit the data, and it’s up to the listener to decipher it. Once they spew out their brusque, jargon-filled facts, they feel like they’ve done their part. But of course the goal of communication is not to broadcast data, but to be understood.
I’m the rare person who understands the technical stuff but can also strip out the jargon for non-engineers. This is how I end up dragged into a meeting with our largest and most prestigious client. They’re some bigshots from a hot new dot-com venture.
To be continued…
 Combining two shapes together. For example, use a smaller cube to carve out a hollow area inside of a larger cube.
 I wonder now if I was violating some sort of license agreement? At the time it never even occurred to me.
 In Unreal, the Z in XYZ is up, and 128 units = 1 meter. In our world, Y is up and 1 unit = 1 meter, and I think some of the XYZ axis might be flipped.
 These days it would just be a Google search away. But in 1999? Not so much.
 I forget the value of N. Maybe a thousand?
 Ignoring the fact that you’re ALREADY plummeting into the void, because you can’t stand on the floors.
Why Google sucks, and what made me switch to crowdfunding for this site.
id Software Coding Style
When the source code for Doom 3 was released, we got a look at some of the style conventions used by the developers. Here I analyze this style and explain what it all means.
Mass Effect Retrospective
A novel-sized analysis of the Mass Effect series that explains where it all went wrong. Spoiler: It was long before the ending.
Good Robot Dev Blog
An ongoing series where I work on making a 2D action game from scratch.
Could Have Been Great
Here are four games that could have been much better with just a little more work.