Striving for Real-Time Photorealism
My name is Lasse Rode and I am part of studio xoio. We are a small agency specializing in visualization and illustration works for architecture and product marketing. Usually we work in a kind of “traditional” 3d environment utilizing applications like 3ds Max and the like. We are constantly checking out new rendering engines and right now making big use of Corona Renderer, V-Ray and Octane. Each engine has its strengths and we always try to use it like that: each for the best purpose.
In my eyes there have been several main trends within our industry: The strive for (photo)realism and becoming faster - if not real-time. Not having to wait for your rendering coming out of your render farm was always a dream for us - especially when rendering animations!
The main downside on the “real-time-thing” for a long time was the lack of quality you could achieve with it compared to pre-rendered still images or animations. So even though it looked very interesting, the application of it in a visualization context seemed to be hard to imagine - and honestly, the “gamey” look of it made it hard to sell for high-demanding clients from the architecture and brand fields.
This has changed rapidly. The results possible with real-time engines today are very beautiful and convincing!
Why Unreal Engine?
The release of UE4 gained a lot attention within our industry and the possibilities seemed to be endless. The PBR (Physically Based Rendering) material system and the easy-to-use importing pipeline for getting your models into the Unreal Engine was the most compelling reason for us to give it a try - in addition to the quality of output possible! If you have seen the work of Koola (also available as a download in the Marketplace) which went viral some weeks ago - you are probably as convinced as we are that Unreal Engine 4 is capable of impressive quality.
In the following article I want to give you an outline of the workflow I used to make the Berlin Flat scene you can download from the Marketplace and share some techniques and tricks I came across during the process. Some of them I found myself, while others are derived from information I found on the web. The Unreal Engine forums and the documentation are a vast and great resource, as are the starter content that comes with the engine and the assets and scenes you can get from the Marketplace.
The Berlin Flat
I made a series of images of this flat in a historic building in Berlin beginning of 2013 using 3ds Max with the Corona Renderer. It’s flexible way of handling the color-mapping, which really helped to pull off the very whitish mood of the whole set. This actually was also the reason for choosing it when giving UE4 a try.
I noticed UE4 being very successfully used on scenes with gloomy lighting and busy textures. I suspected it to be not that easy to get precise shadow and GI within an ultra-white interior.
And honestly: It is a tricky task!
Above is one of the original renders done with 3ds Max and Corona Renderer. To have a look at the whole set, click here
But I will start from the beginning:
The Original Scene
The entire modelling was done in 3dsmax in a rush, so I actually detailed only the parts that are visible in the final images. This is an approach that of course is not possible in a real-time environment. Repurposing the scene for use with Unreal Engine I had to reduce the scope a bit because furnishing and detailing the whole space would have taken too much time for testing purposes.
I decided to export only two rooms: the ones you see on the lower part of the screenshot above.
Exporting the Geometry for Unreal Engine
This is a very easy task IF you keep some things in mind!
It makes sense to split things up a bit. Because the lightmass is calculated into a separate map for every object, it is good to be a bit careful with high values especially on big plain objects like walls and ceiling. Because of this I only exported the inner faces of the walls which we actually see.
I also added a bit to the top and bottom of the walls to intersect them later with the ceilings. I found this to be a good way to prevent “lightleaks” - lighting artifacts that happen when geometry is not closed or not intersecting. This is no problem when having a gloomy scene with lots of busy textures - but since we are going to have an ultra-white space it is important to get as precise GI as possible, especially in the corners.
The second crucial thing is to create unwrapped UV coordinated for the channel the GI is going to be stored in by Unreal Engine’s lightmass calculation. In 3ds Max this would be UV-channel 2.
Channel 1 is for use by all the other textures like diffuse, roughness, normal, etc. Unreal Engine counts the channels starting from 0, which can cause some confusion in the beginning - but once you get it, it is fairly simple.
Note: Unwrapping is only important for the lightmap channel! For the texture channel any kind of mapping can work, such as cubic or cylindrical mapping. In most cases a simple “flatten mapping” in 3ds Max unwrap does the job to create sufficient UV-coordinates!
If you want to put your scene together in UE4 like it has been in your max-scene, it is good for the whole “space” to leave it in place when exporting because the object’s coordinates are easier to align. For single objects like chairs and other assets it is very comfortable to export it only once and instance them in your Unreal Engine scene. For this purpose it is good to move them near the center of your 3ds Max scene because the new object’s pivot in Unreal Engine will be there.
You see I am using high-poly geometry without any LOD simplification. This of course is only recommended in small scenes like this one but since I’m after a smooth experience and don’t want to have any jagged edges on my furniture, this was logical for me. I have no doubt there’s room for optimization, though ;).
Make sure your assets are merged into one object and have different material-ID’s applied to handle the different materials later in UE4!
Well, then you save your geometry as .fbx and off you go over to the Unreal Engine editor!
Importing into Unreal Engine 4
Importing FBX files into Unreal Engine 4 works pretty smooth! I did it in several steps.
I prepared different files that made sense :
- The geometry of the room in a separate fbx file.
- Different file for the assets, each with some objects in them.
Just make sure to uncheck the “Combine Meshes” to receive your objects separately and not baked into a single Mesh!
I am a very straightforward guy and a big fan of simple setups! It’s kind of a philosophical thing, but achieving things with the least effort possible is far superior to using a setup only you understand or you can’t remember when opening a scene half a year later.
So this example of a shader is very simple, consisting of a diffuse map, desaturated and blended with black colour. The same map then is color corrected and inverted to put into the roughness channel of the material. Done :-D
A normal map would have been too much here, but feel free to explore the materials for yourself in the scene!
Here you see the wood material applied to the chairs and the table - a dark dyed wood with a crisp matte reflection revealing the wood structure and texture.
In this image you see two more materials which might be of interest, the curtain which is back-lit by sunlight - a two sided material.
You have to set the Shading Model to “Subsurface” and add a constant node with a value smaller than 1 and wire it to the Opacity property of your material to get this effect.
The jar in the foreground has a very simple glas material applied:
It has a fairly dark diffuse color, zero roughness and a high specular value. I also involved a Fresnel-node with a value of 1.5 to control the opacity and refraction. There are a lot more complex ways to generate more realistic glass - but I honestly had some trouble to really get control over that, so this easy glass seems to be good enough as well :)
Note I checked “Two Sided” and set Translucency Lighting Mode to “TLM Surface” in the Details tab on the left.
One material I want to show here as well is the floor, because this one is the only one having a normal map applied.
Here you see a material defined by a diffuse color, a roughness texture and a normal map.
The diffuse color is a simple very light grey, defined by a 4-value constant.
Roughness looks a bit more complex: On the left you see the same map three times scaled differently with a TexCoord node. The red channel of each then is multiplied with the others and then wired as an alpha into a Linear interpolation node (Lerp) to blend to values. 0.3 and 0.2 in this example to get a subtle noisy reflection on the floor planks. This then is fine-tuned with a “Power” node to get just the right amount of roughness that looks OK.
The normal map again is influenced by a TexCoord and then being flattened by a fair amount via a “FlattenNormal” node to get just a subtle relief on the material.
Preparing the Assets
Before dropping the assets into your scene it is always best to apply the materials onto them within the geometry editor. You would have to do it only once and still can apply different materials in the main scene if needed. This is a fast process: Here you see it is important to apply different Material-IDs to your objects to put the different materials where they belong!
Building the scene
Well, this is kind of brief, but: put the thing together. First you have to drag in the room geometry. Best way is to select all the parts needed and drag & drop them into the empty scene. Afterwards all the furniture and assets have to be placed in the environment.
Here you (don’t) see the back faces of the outer walls - as I’ve explained above: they are only single-sided for better lightmass calculation.
For this exact purpose it is also good to set the lightmap resolution for your larger objects to a high value, for the walls I set at 2048 for example.
As mentioned above, light leaks can be an issue. To prevent these I put black boxes around the whole scene. It looks kind of messy from the outside - though more clean on the inside ;)
Lighting and Lightmass
The lighting also is a fairly simple setup: I used the “Koola method”: a combination of a sun and planes with spotlights in front of the window to simulate a skylight. It is rather effective and easy to control!
To now calculate the global illumination only a few tweaks are important:
I drastically increased the lighting bounces and the indirect lighting quality. I also decreased the smoothness to 0.6. Details are pronounced better and the shadows don’t wash away so much.
I also set the direct lighting to a dynamic shadow for getting better shadows. This also is important to have the light moving later in the animation!
Last step before hitting “Build” would be to set the Lighting Quality to “Production”!
This should result in a smooth lighting everywhere!
Actually when getting to this point the first time I was kind of thrilled! This is actually the strongest part of this engine: to thrill you! Being able to move inside my “rendering” in real-time was really a delighting moment!
One of the greatest features is the possibility to apply color correction and camera effects just within the editor. This can be done with a PostProcessVolume for global settings. I did some tweaks on the saturation, fringing and vignette, the bloom and disabled the auto exposure by setting the min and max values to 1 and increased the overall brightness by setting the Exposure Bias to some 1.42. I also added a lense flare which I find really awesome happening in real time!
Setting up the Animation
The ability to move freely inside the scene makes doing animation a very easy and pleasing task because of the instant feedback nature of the real-time environment. As a frequent user of compositing software it took not much time for me to adapt to the integrated Matinee tool and set up an animation. First thing to do is setting up a Matinee Actor.
When opening Matinee you will see a window with a track section and a curve editor.
Setting up the cameras and animation work is very self-explanatory. Motion is controlled by key frames and curves just like any other animation software. Also the “cutting” work is done just within the Matinee editor.
I created a couple cameras moving slowly through the space: seeing exactly what you are doing really helps to tweak the timing of cuts and speed of camera movement!
You can see the camera trajectories just in the editor and control the editing on the fly!
After getting the rough “cut” done in Matinee, I then exported the whole animation as an avi and fine-tuned it in Premiere and aligned it to the music.
The entire process starting at exporting from 3ds Max and importing into Unreal Engine 4, working out the shading and lighting to produce the animation and then posting on YouTube took me about one day. This speed is unheard of in ArchVIZ and reflects very much the key potential that lies in the use of Unreal Engine 4 for visualization works.
The absence of render times in terms of “producing” images really makes the process of creation very flexible and free. The fast feedback of your action is the real revolution!
We are constantly thinking and testing the possibilities of applying this kind of production and workflow into our daily work and our environment as a whole.
There are a lot of possible applications and we are very eager to explore them!
I hope I gave some insight into the my motivation and process and wish a lot of fun with the Berlin flat scene ;)