Procedural Beijing Buildings - But how about internals?
Welcome, this is article number two of a series where I'll be attempting to break down how I've been approaching and developing my digital assets to generate buildings procedurally inside Houdini so far. Click here to read chapter 1 if you haven't already.
I previously talked about how my first steps in Houdini were already rendering me some nice results. In this chapter I'll cover how big and ambitious my next step would've come to be, what lessons I learned after almost biting more than I could chew on, and how that doesn't always have to be a bad thing.
Please note that this chapter covers mostly my naive approaches to solving many simple problems a rookie could encounter when first getting familiarised with an unknown software, and nonetheless stubbornly insisting on making it work somehow. The next chapter will catch up with the project current's state where I intend to share a few clever techniques I've discovered and created on my own.
But how about internals?
I started from scratch once again with that idea in mind. I could already almost visualize a FPS camera running around, and even dreamt in daylight about VR applications. After around ten days from the previous developments and long hours learning core concepts more in-depth, practicing and trying to wrap my head around how did a For Each Loop actually worked¹, a new idea struck me and fast enough I was again at it.
I realised I wanted to be able to input curves into a digital asset and have it automatically generate walls based off that single input, be it hand-drawn or coming from some sort of shape generator. I searched the web and soon found this great tutorial series by GameTutor, and that was basically my underlying logic on how to approach this for quite a while. I learned so much from GaTu that I can't even start to list it here.
After I had this first WallTool asset working rather nicely, I started to research ways of randomly selecting points from a given dataset, aiming to improve my previous technique for the placement of windows, doors and other details. For example, taking any simple curve as input, we would then break their internal points resulting in a bunch of single elements (Carve SOP² does this quite nicely). We'd then Resample each one of them with equally spaced points, Delete always the first and last (0 $N) to avoid any unwanted corner placements, and our reference points were all perfectly set. It was now a matter of sorting them randomly and procedurally selecting a set of them.
I discovered this cheap technique I guess over at odforce forums utilising the older Group SOP, filtering it by the following expression, $PT < ch("../elemCount") * npoints("../originPts"), where elemCount is just a parameter where you control how many elements you want, and originPts is the name of the group containing all incoming points (both arbitrary names), appended after a Sort SOP randomising the point order, and also promoting its seed value to the upper level. This isn't that much of a great solution since it utilises now almost depreciated nodes, but how was I supposed to know? At least it worked. I had now two sliders for controlling the point selection, both the element count parameter (in this case, windows), and a random seed.
You can observe here how I was handling multiple inputs. The fact that I was utilising various copies of the same assets was counter-intuitive and kind of funny, but I just didn't know yet how to handle this any differently. I would only come to implement a little multiple instancing system inside these assets weeks later. I was doing what I could with what I had at my disposal.
I won't go into much further detail regarding these techniques, since I've come to understand their limitations in regards to this project in specific, but I thought it would be nonetheless interesting to give an overview of how things were working for me in the beginning. After all, I kept perfecting them for the next weeks, and by the time I decided to start from scratch again (hold your horses, chapter 3), they were much different.
Deep in development, weeks went by
Things were starting to take shape. I had gotten much better at organising my node networks, and I felt that struggling with foreach loops was a thing from the past. I came up with so many solutions to all sorts of problems that I could've never imagined weeks before. But..
Things were starting to get out of hand. To illustrate what I mean, imagine I had built a clever system to stack these floors on top of each other. It was necessary to always reference the previous floor to the next one so it could boolean its own floor geometry at the same spot where the previous' roof had been booleanized, so the stairwell system would match. If that sounds insane, it's because it is. Ditto, this indeed rendered me so much control over every single aspect of every asset at any given instanced position that I could virtually design whatever I wanted, and it really was tons of fun.
But that's where I always think about some some of advice I heard many years ago. If you have limited tools at your disposal, – either by choice or lack of knowledge – you end up coming up with clever solutions to all sorts of problems. Having too much to choose from might disperse your focus and overwhelm you with so many possibilities.
Coming back to the out project, you might have noticed things weren't that procedural anymore. Yes, I had built an interesting set of tools to actually design these types of buildings, but not to be generated procedurally. Of course I had realised this right off the start, and it was a conscious decision to keep working on it regardless. Very often the journey will be more worthwhile than the destination itself. In this case, every little challenge I encountered was teaching me valuable lessons, and if I say I wasn't happy with the results so far I would've been lying.
This video above shows the one of the last development demos I showed off with this iteration of the project. It was almost two weeks before I stopped working on it altogether. In retrospect, even though I kept doing things related to it, I wasn't that focused anymore. I was mainly working with some terrain tools, studying L-Systems and generating procedural trees. Taking breaks is beneficial, don't be hard on yourself. Try to always keep your long-term objectives in mind, and enjoy these diversions as much as you can. You will come back to your projects with a freshened perspective.
Even Unity got a taste of it
At this stage I was ready to actually move on and try a different approach to this project. Before splitting I decided to test at least one of my building outcomes inside Unity, just to get that FPS feeling going. Since I had no access to Houdini's Engine, the integration with Unity was lacking. Therefore I had to rework the geometry groups for quite a while inside Unity to get at least some colours in. I realised performance was definitely an issue, but I felt some great sense of accomplishment regardless (no pun intended).
I also apologize for the potato quality on this one. My old hardware was doing its best rendering this real-time and recording my screen, the resolution had to be lowered down a lot.
I think this wraps up this chapter, and I hope I'll be able to share some more technical insights and even small tutorials about the next iteration of this project soon, which happens to be the one I'm currently working on and have been so excited about lately. If you'd like to see an archive containing all of the logs from this iteration of the project please visit this link, or check my older tweets from around November 2017.
Stay tuned for this series' next chapter. It will be linked here as well once it's ready.
(¹) Oh yes, I remember the struggle quite well. Many days without success passed by until I finally found this absolute gem, Geometry Workflows in H16, by Jeff Old-school Wagner. Helped me finally understand how foreach loops worked, after taking notes and practicing for the next days.
(²) Surface Operator. I think this is where I should link you to one of the most important places for deepening your knowledge in Houdini. Matt Estela's cgwiki is an absolute must, go check it out if you haven't heard of it yet.