{"id":35248,"date":"2016-11-17T06:00:37","date_gmt":"2016-11-17T10:00:37","guid":{"rendered":"http:\/\/www.shamusyoung.com\/twentysidedtale\/?p=35248"},"modified":"2016-11-15T00:18:54","modified_gmt":"2016-11-15T04:18:54","slug":"crash-dot-com-part-2-the-meeting","status":"publish","type":"post","link":"https:\/\/www.shamusyoung.com\/twentysidedtale\/?p=35248","title":{"rendered":"Crash Dot Com Part 2: The Art Coder"},"content":{"rendered":"<p>It&#8217;s now 1999, and I have an odd job<span class='snote' title='1'><img decoding=\"async\" src=\"images\/odd_job.jpg\"><\/span>. Our product is a multi-user social environment. In four years, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Second_Life\">Second Life<\/a> will show up and make a more successful version of this idea, but for right now we&#8217;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.<\/p>\n<p>I&#8217;m technically an &#8220;artist&#8221; in the sense that a lot of my job involves creating models and textures. But I&#8217;m more an engineer in terms of inclination and skill set. I don&#8217;t have a solid grip on aesthetics and I really envy my fellow artists who can nail a particular architectural style like &#8220;Gothic&#8221;, &#8220;modern&#8221;, &#8220;whimsical&#8221;, or whatever. I don&#8217;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&#8217;m likely to just build exactly what I&#8217;m shown, while the real artists on the team are able to get the &#8220;vibe&#8221; the client is going for. <\/p>\n<p>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. <\/p>\n<p><!--more--><\/p>\n<h3>For example&#8230;<\/h3>\n<p><div class='imagefull'><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/cdc_unreal.jpg' width=100% alt='I don&apos;t have any screenshots of the project, but here&apos;s a shot of Unreal Tournament. This is from the same time period and it&apos;s kind of what I was shooting for.' title='I don&apos;t have any screenshots of the project, but here&apos;s a shot of Unreal Tournament. This is from the same time period and it&apos;s kind of what I was shooting for.'\/><\/div><div class='mouseover-alt'>I don&apos;t have any screenshots of the project, but here&apos;s a shot of Unreal Tournament. This is from the same time period and it&apos;s kind of what I was shooting for.<\/div><\/p>\n<p>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 <a href=\"?p=4759\">BSP<\/a> based levels like that, and our tools aren&#8217;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.<\/p>\n<p>We don&#8217;t really have good tools for building something like this. The 3D modeling program we use is called <a href=\"https:\/\/en.wikipedia.org\/wiki\/TrueSpace\">truSpace<\/a>. It&#8217;s basically tolerable for making small-scale models. It&#8217;s okay for making stuff you might put IN an environment, but it&#8217;s terrible for making the environments themselves. It&#8217;s fiddly and buggy and the interface is inscrutable. The most egregious shortcoming is that the program can&#39;t do boolean operations<span class='snote' title='2'>Combining two shapes together. For example, use a smaller cube to carve out a hollow area inside of a larger cube.<\/span> to save its life. Some of my friends at work have a saying we use: &#8220;Truespace is a 3D program that is bad at math.&#8221; 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.<\/p>\n<p>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 Unreal<span class='snote' title='3'>I wonder now if I was violating some sort of license agreement? At the time it never even occurred to me.<\/span>. Once I&#8217;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&#8217;re using. They use different coordinate systems at different scales<span class='snote' title='4'>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.<\/span>. 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&#8217;t documented, so I have to do a bit of reverse-engineering to figure out how it works<span class='snote' title='5'>These days it would just be a Google search away. But in 1999? Not so much.<\/span>. <\/p>\n<p>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.<\/p>\n<p>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:<\/p>\n<p>Problem One: <\/p>\n<p>Our software can&#8217;t support this many polygons in a single model. Once a model has more than N polygons<span class='snote' title='6'>I forget the value of N. Maybe a thousand?<\/span>, the collision detection assumes the object is a decorative statue or other object that doesn&#8217;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 <a href=\"?p=20689\">users tend to be reckless about adding heavy, CPU-sucking assets<\/a>. The result is that you can view this level, but you can&#8217;t stand on any of the floors or bump into any of the walls.<\/p>\n<p>Problem Two: <\/p>\n<p>Since the world is usually made by users building with prefab pieces, we can&#8217;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&#8217;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 &#8220;draw distance&#8221;. 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&#8217;ll find yourself in empty space, plummeting into the void below<span class='snote' title='7'>Ignoring the fact that you&#8217;re ALREADY plummeting into the void, because you can&#8217;t stand on the floors.<\/span>. Even if you set all of your graphics options to maximum, it still won&#8217;t be enough to allow you to explore the far reaches of the level.<\/p>\n<p><div class='imagefull'><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/cdc_unrealed.jpg' width=100% alt='A screenshot of the level editors of the time period.' title='A screenshot of the level editors of the time period.'\/><\/div><div class='mouseover-alt'>A screenshot of the level editors of the time period.<\/div><\/p>\n<p>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&#8217;s a bit like those 3D puzzles where individual pieces don&#8217;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.<\/p>\n<p>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 &#8211; like making one room slightly larger and doubling the number of support pillars &#8211; 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.<\/p>\n<p>This job would have been far too technical for the artists. Meanwhile, the programmers working on our core product wouldn&#8217;t have known about this problem because they weren&#8217;t concerned with the art production stuff. And even if they did know about it, this solution wouldn&#8217;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. <\/p>\n<p>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&#8217;ve saved us. <\/p>\n<h3>Communication Skills<\/h3>\n<p>The other downside of having this skill set is that I&#8217;m seen as a socially high-functioning engineer. If we need to have a feasibility conversation with  a client then I&#8217;m the one called into the meeting because I&#8217;m not going to baffle anyone with technical jargon when I&#8217;m asked a question. <\/p>\n<p>See, just about every engineer puts &#8220;good communications skills&#8221; on their resume, and in the vast majority of cases it simply isn&#8217;t true. It&#8217;s not that they&#8217;re lying, it&#8217;s that they  have no idea what &#8220;good communications skills&#8221; means. They think it means stating things bluntly and accurately. They transmit the data, and it&#8217;s up to the listener to decipher it. Once they spew out their brusque, jargon-filled facts, they feel like they&#8217;ve done their part. But of course the goal of communication is not to <em>broadcast<\/em> data, but to <strong>be understood<\/strong>. <\/p>\n<p>I&#8217;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&#8217;re some bigshots from a hot new dot-com venture.<\/p>\n<p>To be continued&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;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&#8217;re doing pretty good. Sometimes clients come along and ask us to build custom environments for them. A [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16],"tags":[],"class_list":["post-35248","post","type-post","status-publish","format-standard","hentry","category-personal"],"_links":{"self":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/35248","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=35248"}],"version-history":[{"count":0,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/35248\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=35248"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=35248"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=35248"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}