My name is Thorsten Ruploh, I’m a 3D Artist and currently living in Berlin. My journey started in 2010 when I was moving here to start studying Game Design at the University of Applied Sciences. During my study, I got a broad overview of all the different aspects that are needed to create an actual game. Meanwhile, 3D became my passion because it requires an artistic eye but at the same time an understanding of your work on a technical level. After university, I worked at different companies on very different projects – from mobile titles to console to PC VR games. Along the way, I met great colleagues, new friends and learned a ton about the importance of teamwork and streamlined workflows.
I stumbled across a concept for this environment on ArtStation. The concept was done by Rasmus Poulsen and greatly fitted my need for a small environment that does not look like something you would regularly see in other portfolios. At that time, I was thinking about doing an environment piece for my portfolio since I didn’t have anything up to date. My goal was to capture the initial mood from the concept (especially for the lighting), try to stick to the reference as close as possible and utilize Unreal blueprint to minimize iteration time. Additionally, I wanted to create the other side of the room, which is not seen in the concept, to be able to provide different angle views of the environment.
“Mr. Alexeev will see you now” by Rasmus Poulsen
In the beginning, I tried to break down the concept into different things.
First, I planned the backside of the room in regards to what could make sense for the environment (Where do all the cables come from? How can a person enter the room? Where do the plants on the bottom come from? etc.) Then I tried to get a feel for the room dimensions. Since I got no floor plan with exact numbers, I used the man from the concept as a starting point to measure proportions and based all my size calculations on these results.
After that, I started to quickly block out the scene in Unreal with some basic meshes to get a feel for the space. This process involves a lot of iteration and constantly checking the blockout against the proportions of the concept. Once the blockout was in place, I started to think about environment materials, the props I needed to create and gathered references for all of that.
Like always, lighting plays a big role in selling the atmosphere of a project. I took another look at the concept and tried to find all the important lights in the scene. The windows and lamps attached to the book cases are definitely creating the atmosphere of the room. These are my primary lights that I definitely needed to match to the concept. So the first thing I started to do was to tweak my directional light and my skylight to the point where it came close enough. The skylight captures an HDR image that acts as my sky and is set at an intensity of about 0.25 cd/m². The directional light has an intensity of 3 lux and uses a temperature of 6000K. This was a really long process and required a lot of back and forth. Luckily, Luoshuang’s GPU Lightmass baker saved me countless hours of waiting time and provided great results even on lower quality settings.
When I was done with the initial setup, I moved on to work on the environment and left the details of the lighting open until the end of the project. At the end, I started to place some fill lights where I needed to have some accents in the scene based on my camera locations. These fill lights were static lights with the same color temperature as the sun because most of the time, they should enhance the light that was meant to fall through the windows.
The lights for the bookcases consist of two lights per lamp. The first light is a stationary point light with an IES profile and creates the harsh lightcone that illuminates the books. The static rectangular light acts as a fill light that illuminates the surroundings to simulate the light that is cast further into the room. This creates subtle illumination on the floor and the other parts surrounding the book cases. The temperature for these lights is around 3200K to create the warm lighting that is in contrast to the blue light from the outside.
The light coming from the windows was pretty tricky to set up. The blue color that is cast from the sky was not as intense as needed to match the concept. So after a long period of testing different light scenarios with different post-process effects, I decided to add translucent emissive planes to the windows to fake the colored bloom happening there. The material is set to unlit translucent and I added a depth fade to hide the transition of the plane and create a soft gradient at the edges.
The overhead light is visually interesting and creates a nice contrast for the interior lighting with the cold color. I positioned the rectangular lights lower than expected because otherwise the ceiling would have been illuminated too much. Additionally, the reflections of the lights were not visible from some camera angles if the lights were placed correctly.
Since there are many books in the environment, I knew from the start that it’s not really efficient to place them all by hand and performance can go out of hand quickly. So I decided to let a blueprint handle all the placement and color variations of the books. The randomization happens on two levels: during the placement of the meshes and in the book material to get different colors and variations. The book mesh is placed as an instanced static mesh to reduce draw calls and to allow me to use the PerInstanceRandom node in the material for the color variation.
The Blueprint is based on one of Unreal Engine content examples for procedural blueprint placement of a fence. I can place the blueprint in the level, move the endpoint to where I want it to be, set the thickness of the mesh and the blueprint places the book meshes with small random offsets between start and endpoint. One important aspect is to use a ‘random stream’ because it’s deterministic. With this setup, I can reopen the level and the books are still at the same place as before (because the random numbers are still the same) and the lightbake is not broken. You can still adjust the random offset by changing the random stream input seed. Check out Unreal Engine documentation here if you want to know more.
At the start, I created the textures inside Substance Painter. The textures are created like a flipbook texture: every quarter of my UV space represents a new book cover with different materials and decorations. The alpha slot acts as a mask to lerp between the color tint and the base texture.
The material itself is pretty simple. It basically shifts the UVs of the mesh to display the different book covers and tints the base color map with a color swatch that I created as a color curve in the engine. This saved me quite some iteration time since I didn’t need to leave the engine to adjust the colors.
The UV offset and the color tint are driven by the PerInstanceRandom node which outputs a value between 0-1 for each mesh instance of my instanced meshes. This output determines the position of the UVs inside the flipbook node and the UV offset is passed on to the actual book textures.
The bookcases are basically tileset meshes in different variations. They share the same texture sheet and fit exactly inside the wall meshes where they are located. Additionally, I created a blueprint for them and attached the lamps with the according lighting setup inside the blueprint as well. Because the lamps are a separate blueprint, I only need to tweak that blueprint and all changes are passed on to the bookcases.
All props in the scene are modeled with the same ‘big to small’ approach: it all starts with reference gathering and the blockout. After that I place the mesh in the scene and make some adjustments if needed. When the blockout works fine, I start to work on the highpoly, lowpoly and the textures.
For the highpoly modeling process I really like to use the ‘Turbochamfer’ plugin from Wahyu Nugraha. I added the ability to control the amount of chamfer edges and am using it ever since. Grab it here, and throw some money at him! In general, I like to work this way because I can easily adjust edge loops or delete modifiers from the highpoly to get a good base for the lowpoly. This was especially true for the center desk because most of the details were spline-based and I could just lower the interpolation steps for them to get the lowpoly.
After that, I merged some meshes with boolean operations and did my UVs. Baking and textures are done in Substance Painter. The base material for the desk was taken from one of the wood materials that ship with Substance Painter. I applied some color tweaks and layered dents, scratches and dirt on top.
For the projector, I was lucky to find a good model with lots of reference photos and some size measurements, so the blockout in 3ds Max was relatively easy because I had exact sizes for the most important parts like the main corpus and the film reels.
Since the blockout was done pretty quick on this asset, the blockout mesh evolved into my basemesh for the highpoly. Once the base forms were okay, I used booleans to add more details to my mesh. This process enabled me to not worry too much about the topology in detail because when the details line up correctly, everything else starts to fall into place. For example, the film reels may seem tedious to model by hand, but with a bit of preplanning and matching cylinder sides, everything turned out quite nicely. I’m even able to make adjustments to the mesh after most of the other stuff is done – this keeps me super flexible.
After my basemesh was done, I used a combination of the TurboChamfer plugin and ZBrush dynamesh method to generate my highpoly for different parts. On some occasions, I had to use ZBrush because the chamfering algorithm tends to produce some odd topology that is not suited for subdivision in 3ds Max. Since my basemesh consisted of proBoolean meshes, I could copy the whole thing and lower the interpolation steps of chamfers for my lowpoly and then do the UVs. Substance Painter was again my tool of choice to bake the textures and create the final material.
The meshes in the upper part of the room were things that I spent quite some time on. The ceiling itself was initially done with Substance Designer and refined in Substance Painter, plus I built a mesh in 3ds Max to support the overall silhouette that was needed for that piece. For the upper walls, I did a basic blockout of the mesh and later created one texture sheet for the entire mesh collection of the top part.
For the ceiling, I created a substance graph that was used to generate the overall heightmap. The smaller details were created in different subgraphs to keep things organized and more readable.
The tricky part was to place the different details on the according parts of the ceiling while at the same time have accurate masks to hide the details where they were not needed. In the end, I created a normal map from my base ceiling shape and selected different parts depending on the slope of the ceiling and which detail needed to be masked.
Once I was done with the height, normal and ambient occlusion map, I imported the textures to Substance Painter because I wanted to layer a plaster material that I did earlier on top. This would totally be feasible in Substance Designer, but I prefer to work in Substance Painter because the node connections can get messy pretty quickly for layering different materials together. Additionally, I am still flexible and can change materials quickly or add more dirt and grime on top if needed.
The other walls that attach to the ceiling are handled like all other tileset meshes. They were blocked out in the beginning, then refined step by step. Initially, I planned to use a trimsheet for all the wall decorations but I ended up using one texture sheet per wall tileset.
Floor & Column Materials
All tileset materials were created in Substance Designer or Substance Painter. For the floor, I created a base material in Substance Designer and refined the mesh with a simple vertex blend shader to create more macro variations across the surface. Additionally, I tinted the basecolor map inside Unreal to have direct feedback about slight color changes in the engine.
The trickiest part was to balance the roughness details and have just the right amount of contrast to avoid a uniform and too noisy look. In the end, I used a flat roughness value in the shader and let the vertex painted detail modulate the roughness values. This created a low contrast variation across the surface that created macro details without looking repetitive.
For the concrete columns, I created the material in Substance Designer. Basically I stuck to the general rule of thumb when working on materials: work macro to micro, create the heightmap first and then roughness and basecolor. For concrete materials, I think that the basecolor map can be difficult to create because of the very faint color variation across the surface. If the contrast is too high, the material does not look like a real surface, if the contrast is too low, the material looks dull.
Especially for concrete, I like to apply gradient mapping to some kind of cloud noise. The resulting noise is great to use for roughness details or faint basecolor variation.
The vegetation pushed me out of my comfort zone. On some occasions I have already worked on vegetation but only on small stuff. For the small bushes I used a free tool called TreeIt. It was totally sufficient for my needs. Because I needed to save production time, I used Quixel Megascans for the vegetation textures. Usually I try to create all the important parts of portfolio projects by myself, but in this case I decided that the textures are just a small part of the environment.
The creation in TreeIt was pretty straight forward for the bushes. I exported the final mesh as an .obj and fixed the UVs for the leaves to match the Megascans data since it was a texture atlas. After that, I imported the mesh to the engine and started to paint the foliage at the desired places.
The hanging plants were created a bit differently. Because I needed to have more control over the placement of the leaf cards, I decided to use the object paint tool inside 3ds Max. At first, I created a plane on which I painted some splines to have the stems for the leaves.
Then I created some leaf cards in different sizes and used these cards with the object painting tool.
The important part is to paint several times with different leaf sizes. First, I painted the bigger leaves with size variation. After that the medium and small leaves. Once everything was roughly in place, I hand-edited the positions of some leaves to be closer to their stem and prevent clipping. Additionally, I tried to establish different layers of leaves to give some depth to the whole plant. At the end I applied a bend and an FFD modifier to further enhance the volume of the whole mesh.
One of the bigger challenges was to nail the mood I was going for with the lighting and the post-process effects. Initially, my lighting was quite different and I never got the contrast right between the interior brightness and the brightness with the bloom effect of the exterior. The exterior should be bright enough to create a subtle bloom and only give a hint about what is happening on the outside. I tried several different lighting intensities in combination with different bloom settings, but in the end, it did not turn out the way I wanted it to be. My solution was to stick with the lighting and post-process effects that already worked at that point. On top, I added some emissive translucent planes in front of the windows that have a blue tint to simulate the bright exterior with the color accent. This combination came pretty close to the effect that I had in mind.
On the other hand, I had the problem of time management and being able to work on the scene for some longer periods of time to deliver the quality I wanted to achieve. Creating a scene while still having a regular day job can be a pretty exhausting task and putting more than one or two hours after work into the project was often not possible. I tried to find smart solutions and to cut corners whenever I could. An example of that would be the busts and statues that are scattered around the environment. Since it was definitely out of scope to create all these by hand, I tried to search for 3d scans of the exact same things online (because I think that every artwork was placed in the room for a very specific reason). Sadly, I could not find any of them. Instead, I went for a different approach and thought about what could be the reason for the busts to be hidden. So I came to the conclusion that the inhabitant of the room planned to leave the place for quite some time and distributed blankets to protect important stuff against dust. This gave me the ability to cut down production time and even have a little bit of storytelling going on in this piece.