logo80lv
Articlesclick_arrow
Talentsclick_arrow
Events
Workshops
Aboutclick_arrow
profile_login
Log in
0
Save
Copy Link
Share

Creating a Game-Ready Peugeot 403 Using Unreal Engine & Substance 3D

Pedro Alexandre Pereira talked about the process behind the Peugeot 403 model, sharing what inspired the project, how he overcame the challenges of modeling the car, and how he created the details.

Introduction

My name is Pedro Pereira, and I am a 3D Artist from Portugal. I have been doing 3D Art professionally for more than 10 years. I have always had a fascination with 3D games from a young age, as I grew up in a time when games were transitioning from 2D to 3D. That, along with a passion for art, eventually led me to dabble with some programs as a teenager.

Later, I started studying 3D seriously, with the intention of pursuing a career during my college years. After some time working on advertising and television, I eventually started working at a game studio and shipped many multi-platform titles, mostly as an environment and prop artist. I've also worked as a freelancer.

The Peugeot 403

This project began because I originally wanted to create a car mod for Assetto Corsa, including a fully modeled interior. My wife and I are huge fans of the show "Columbo" from the 70's, and she was the one who actually challenged me to try to create Lt. Columbo's old and beat-up Peugeot 403 from the show.

Eventually, while working on the modeling, I decided to change the scope of the project to focus entirely on the exterior. While I kept the initial intention of creating the car as a game-ready asset, I chose to shift the project to a portfolio piece and use the Unreal Engine for rendering. I wanted to make the car look even more damaged, rusty, and dirty than the one on the show, and push my texturing skills further.

For reference, I started by trying to find a good blueprint of the car. This is an essential first step for modeling something as precise as a real-world car, as you can't get a sense of the real proportions using photo reference only. Then I took some screengrabs from the show and as many quality photos as I could of this car.

Since I did find some discrepancies in the elements of the car, between episodes, and some photos of the car claimed to be the one used on the show, I  decided to model out whatever elements I found that had better reference (especially close-ups) from the different sources I pulled into my PureRef board. I also modeled the wheel rim from another model, as I found its spoked rims to be more interesting.

Modeling

I started the modeling process by importing blueprint references into Maya and scaling them up to real-life size. It's a good rule of thumb to always make objects to real-life scale, as this helps with many systems in 3D packages and rendering engines. In my case, I was modeling this originally as an Assetto Corsa mod, so it was a requirement.

But even later, as it became intended to be imported and integrated into Unreal Engine, which uses a physically based rendering engine, with real-life values for light intensity and falloff, it remained important. I first created some curve guides along the main lines that form the shape of the car, so I had a reference for the general shape of the object and to help with topology. Then, edge loops were created following these main lines.

The process was to create the entire body as one single object, following those initial guiding curves. Then, different panels were cut, beveled, and extruded inward. Getting the shape of the car body correct was not an easy task, and I had to restart from scratch at one point, since I was unhappy with my first attempt. Even then, I kept changing things right almost until the end.

The resulting mesh from the extrusion (here in red) is then separated and eventually given a black material in Unreal, creating a watertight mesh. As I always like to explore different workflows and tools on personal projects, I decided to model the wheel rim in a CAD modeling tool I had been learning called Plasticity.

Here is the high-poly model of the wheel rim, converted from CAD and exported from Plasticity:

Here is the high-poly of the roof of the car. First modeled in Maya, then I imported it to ZBrush for detailing:

At this point, I decided to go for a mid-poly approach, except for the roof, since I already had a sculpted high-poly. I figured it would be easier to iterate on the model if I didn't have to commit to a high-poly model and have to change a second low-poly mesh accordingly. And as said previously, the tweaks on the model continued right until the very end.

The mid-poly technique was also something I had no previous experience with, so, once again, it was an excuse to learn something new. From here, any detailing that would otherwise be part of a high-poly model would be on a single Normal Map atlas, including the details of the tire and wheel rim, the lights, logos, and any small bevels.

Some of the high-poly details (screws, headlights, taillights, and tire pattern) that were baked into individual plane meshes later in Substance 3D Designer and arranged with the other procedural and imported details.

UV Unwrapping

In preparation for UV unwrapping, I aimed for a texel density of about 12 pixels per unit. My texture sets ended up as follows: Car Body (4K), Bumpers/Metal and rubber parts/Roof (4K), Glass / Lights (2k), Tire / Wheel Rim (2K). I used Maya's native UV tools for unwrapping.

My workflow is usually to start with a simple planar projection for the entire object, then cut my seams, project, and unfold. I have assigned planar projection for X, Y, and Z into shortcuts, which saves some time. I also try to straighten as many shells as possible, which saves UV space. A good tip is to select the middle edge loop and go to Modify > Straighten Shell.

For layout, for the most part, I use the Layout UVs tool for automatic packing. I set the Texture Map Size to my own, and I play around with the Packing Resolution, Iterations, and Shell Padding. I keep checking the texel density until I have a good result. If needed, I will move some shells manually, but I tend to do this only as a last resort.

Here are the Car Body Set Parts that share the same UV space, such as the duplicated side panels and doors (selected in green). I move the shells to the next tile. This way, Substance 3D Painter won't overlap baked textures, but I can still import the whole mesh.

I tend to use different UV sets a lot, including in this project. I use a script that automatically renames UV sets on all selected objects. This prevents issues where combined meshes that don't share the same names on UV sets will create extra unwanted sets. The script also selects a UV set from all selected objects, from a given name. This makes sure I'm not accidentally packing the wrong shells.

Texturing

Following UV unwrapping, I assigned the materials their final names to keep them consistent in Substance 3D and then Unreal. Different parts are keyframed in both their final position and with an offset. I selected either depending on whether I was exporting to Unreal or Substance 3D, respectively, as having them in the final position in Substance 3D Painter would result in unwanted shadows and normals during baking.

For exporting from Maya, I used the Game Exporter (File > Game Exporter). I selected Export Selection and Export to Multiple Files, with Move to Origin ticked. To expedite the export process, I created a Quick Selection Set with all my objects to export, meshes, and groups, gave them the name that will be on the file, and made sure the pivot is at the correct position.

This way, all I had to do was click on the saved Set on my shelf and export. Maya will move all objects to the origin and export to the correct directory with all the correct mesh names. Here is a ready-to-export model, with simple color materials and the selected keyframe with offset components, for texturing purposes.

Floating geometry (in Yellow), which later would use the decal Material. On the mirror, it projects the holes for the screws, and on the tire, all its details.

The front grill material uses a simple tileable 128x128 normal and opacity texture.

To create the normal texture atlas used in the decals and in the secondary UV set used throughout the car, I used Substance 3D Designer. I often use Designer even if I'm not necessarily using it to create procedural materials, but to composite textures from different sources, such as from baking, from Painter, or from Photoshop.

I find it convenient as a pipeline tool because it automatically updates all its inputs from all these sources and can automatically export the textures to their final path. This time, I needed to create a Normal Map and an Opacity Map, and I used a combination of procedural and baking.

Here is the final Substance 3D graph for the normal texture atlas and the final texture atlas:

The graph is very straightforward: a few bitmap inputs from the baked high-poly details, a procedural graph for the frontlight pattern detail, the trim sheet, the text details seen throughout the car, and the Peugeot logo for the front. Each one of these components has a transform node at the end, which I used to move it around and organize the final atlas.

Here are close-ups in Unreal Engine, showing different uses of the normal atlas on decals and as secondary blended normals.

For the main textures, I used Substance 3D Painter. I'm not going to break down every single texture set since the process of texturing the base material, damage, rust, and dust is the same for every set. We'll focus on the texturing of the car body. I started by giving it a base colour and some roughness variation.

I also created a fill layer that desaturates the base colour at the top of the body, to give it some discoloration. For the roughness variation, I created a fill layer with a MatFinish Rough filter, masked by a few Grunge Maps. These roughness layers also take into account the damage and rust, using anchor points, which I'll explain next.

Here is the Base Colour and Roughness with a layer of colour desaturation on top and a layer of roughness variation, and the Base Colour and Roughness layers:

For the damage details, I created a folder, before the Base layers, containing Height fill layers with different kinds of height information. Then, at the top of this folder, I created a fill layer with all its channels turned off, set to Passthrough Blending mode on the Height channel.

This effectively makes this layer contain all the height information from the layers in the folder, and, adding an Anchor point, I have the entire stack of damage details to reference anywhere in the project. I used this approach on the rust and dust, as we'll see next.

Some of the damage is manually painted with a basic brush and blurred out. In other cases, seen here, I use a Cell Noise filtered by Anisotropic Kuwahara and Blur, then mask only the parts I want.

For the rust, I used a similar approach. I created a stack of Height fill layers to paint masks of the rust areas. This group, called Rust Stack, is set to Disable blending mode and is used as an anchor point. Then, that group's anchor point is referenced by another group, Rust Height, where I created the peeling and rust bubbling effect.

This allows me to paint inside the Rust Stack group, and its Height value trickles down to the Rust Height to go from no rust, to rust bubbles, to completely peeling off the car paint.

At the bottom, I created the Height Hole layer, which, using Levels, references a certain value from the Rust Stack mask and creates a cutoff point between the paint and the rust. This cutoff mask's anchor point is used many times after, but the layer itself is disabled.

The mask view of the layers containing the bubbling effect, based on the Cells' noise. Notice the cutoff mask is used to subtract, thus only affecting the surrounding paint of the car and not the rust area. The smaller bubbles in the second image use the first one as a subtract mask, because these usually surround larger bubbles.

The peel-off effect is the cutoff mask once again, blurred and subtracted by itself, creating a falloff effect.

The group of layers containing the rust colour uses the previous Rust Height group's anchor points. Some colour variation is achieved with some grunge masks and Gradient filters. A High-pass filter is used to create a falloff between rust and paint. A similar approach is also used to create a half-transparent black fill layer, set to Multiply, creating an extra contact shadow effect from the paint layer to rust.

There are also some extra leaking rust layers, created by projecting a photo of a real rust leak as a mask.

The dust follows the same principle of creating a folder, set to Disabled blending mode, containing a stack of layers and a top fill layer serving as an anchor point. Then, a single fill layer containing the Colour and Roughness value of the dust is masked by the Dust Stack's anchor point, with some extra Levels tweaks.

Since, as seen in reference, dust settles mostly on the top, I used Position and Light generator masks first. I also created masks based on the baked curvature masks for crevices and the rust and damage stacks. Then, there was a long process of using procedural noises, real photos of dust, and different brushes to make the dust look realistically settled on the car, but also as if fingers and other external forces left marks.

Dust fill layer and partial view of some of the masks inside the Dust Stack group:

To set up the materials in Unreal, I used the Megascans Master materials as a starting point, namely the MS Base, for most surfaces and the  MS Glass for the windows and lights. I've also created a variation of the MS Base material for the car body, using the Clear Coat shader model. I then added the extra parameters and inputs I needed for these materials.

I added the secondary Normal Map blended to the main one, to make use of my normal atlas. Also added an extra texture input for an RGB texture with a different Grunge Map on each channel, with controllable tiling and minimum and maximum values.

This is blended with the main Roughness Map and value parameters to add some micro roughness variation when the car is seen up close. Close-ups in Unreal Engine, and the 512 x 512 grunge texture, showing how this micro Roughness setup helps the illusion of extra texel density.

I changed the original MS Glass material to use my own texture packing coming from Substance 3D Painter. I also changed the Post Process volume to use raytraced refraction for these kinds of materials.

Rendering

When I first created the Unreal project, I didn't have any particular lighting setup in mind, so I wouldn't give myself any restraints as far as quality settings. After all, the purpose is to showcase a prop, not to make an optimized scene. 

I started with the Advanced Lighting level from the Starter Content, because it already has all the scene objects and good starting values for high-quality rendering. I tweaked the Post Process Volume to maximize every possible value to the highest possible quality, including maximum quality raytraced shadows, reflections, and GI.

In my first experiments, even before textures, I played around with sunset lighting, with some shadows. I reason that the high contrast shadow and highlight would help emphasize the form and showcase the damage details better.

While I believed this approach to lighting was valid, it looked incomplete without a surrounding environment. Since I didn't want to spend time making one, as it went beyond the scope of the project, I decided to go for neutral, studio lighting instead. I kept the asphalt material I had previously for the floor, but only kept the Normal Map, so it wasn't too bland.

As I adjusted the new studio HDR light, I felt much more confident that this was the right approach. I placed a directional light coinciding with where the strongest light of the HDR was and an area light on the darker side, to make sure some detail wasn't lost in the shadows.

In the Post Processing volume, other than the quality settings mentioned above, I made almost no adjustments in terms of color grading, a small tweak to contrast and temperature. The contrast of the clean environment with the damaged car made for an interesting scene, and the almost frontal lighting on the main shots gave it an almost clinical look into the decay of the vehicle.

Finally, I rendered the final shots and turntable using the Movie Render Queue plugin. I set the console variables to make sure the final shots had the best possible quality. For the turntable, I had an issue with ghosting between frames, due to the temporal anti-aliasing, so I settled on 32 samples on the Render Warm-Up count and Temporal Sample Count.

Conclusion

I believe that creating good, realistic prop assets, for me at least, comes down to following a few principles:

  • First, good reference material is essential. Following the reference and what makes sense in terms of how an object is used, or how it works.
  • Second, following the principle of working from the basic blockout to the details. Focusing on primary form, then secondary and tertiary details in good proportion. In my case, I made deliberate choices on where rust and dust are placed and in what density, for example.
  • Third, understand technical aspects of how realistic rendering works. Because realism depends on a good balance of good materials, lighting, and post-processing, it's important to learn and follow the established rules, so that a reliable workflow is possible. Even the best model can absolutely be ruined by bad lighting.

The most challenging thing about this project was having to constantly reevaluate decisions, both large and small. It was hard to discard the first model of the car body for a do-over. It was also hard to decide, as I stated above, about how every layer of damage, rust, and dust should look.

It's only by getting all these small things right, balancing all aspects, that a realistic and believable render comes together and looks natural and grounded. Regardless of the challenges, I learned a great deal, from new tools to workflows, giving me more options and the ability to tackle new artistic and technical challenges for future projects.

Tackling car modeling is something I now feel much more confident at. Learning this mid-poly approach to modeling and texturing was also a valuable lesson, applicable to many props and environment projects. As for advice for beginners, I would point to not only what I said above about how to create realistic props, but I would add that, in the beginning, it's good to tackle simpler objects, with fewer materials.

Even making a simple object look real is plenty challenging. Additionally, I would say to never get too attached to anything. If the gut feeling is that something isn't really clicking, trust that feeling and do it again or try another approach. And finally, I think it's important to be efficient. Removing repetitive tasks and friction from the workflow by looking out for scripts, tools, or utilities that might help.

Keeping things organized and structured will also save time and headaches in the long run. Time is better spent solving artistic problems. I would like to thank 80 Level for the opportunity to share this breakdown of my work. I hope I have offered some help, in the same way I have learned from many artists on this platform!

Pedro Alexandre Pereira, Senior 3D Artist

Interview conducted by Emma Collins

Ready to grow your game’s revenue?
Talk to us

Comments

0

arrow
Type your comment here
Leave Comment
Ready to grow your game’s revenue?
Talk to us

We need your consent

We use cookies on this website to make your browsing experience better. By using the site you agree to our use of cookies.Learn more