Jacopo Ortolani did a huge breakdown on his awesome character project that he made in the custom engine, discussed the retopology and talked about his approach to hair creation and creating shaders.
In case you missed it
you might find it interesting
Introduction and Career
My name is Jacopo Ortolani. I’m a 3D Generalist currently based in the area of Milano, Italy.
Since I was a kid, I was always fascinated by video games and 3D art in general. At one point, I realized it was possible to actually do this kind of stuff at home. Then someone was kind enough to provide me with a copy of 3dsMax. That was back in 2001, I was 16, and I had no internet. I was always someone, who likes to experiment and figure things out for himself. Therefore, that’s how I started learning many of the things that I know today.
After having 3D art as a hobby for a while, I got to a point where I was employable as a 3D artist, and I finally got my first official job in a very small video production company in Milano. Then, after three years in that company, I decided that it was time for a change of pace, and I found a job as a Maya teacher in an Autodesk Training Centre. That went on for four years, and it was a very interesting and rewarding experience for me. However, I kept feeling like there was more that I could achieve by moving somewhere outside Italy, where more interesting opportunities and connections and better prosperity can be found. At the time of writing this, I’m still working towards that goal.
Recently I had a short experience in England, which sadly didn’t work out at all for me. So, for the time being, I'm back in Italy, and I’m working with a very nice company called Maga Animation, based in Monza.
About the Idea of the Project
When talking about the inspiration for this character, I could point out some of my favorite games. Those include 'the Uncharted series' and 'The Last Of Us'. However, my goal was to create an original character living in an original universe. So, those works were more like examples in the back of my head than actual references to follow.
My main focus was to come up with a character that could be considered beautiful while at the same time looking unconventional. Modeling a good looking female character is not an easy task itself. But if there was an easy way of doing that, it would be by sticking with what works. I guess I can’t help myself but making my life harder than it needs to be.
So, while starting this project, I wasn’t really relying on many references at all and just freely sculpting a female face based on what I know about facial anatomy. Collecting references was something I started doing at a later stage in order to avoid making something totally unrealistic. In a way, I based my references on the character that I was sculpting instead of the other way around.
Something else that was always in my mind while creating her was that she had to be someone who doesn’t really care about the way she looks. Her style had to look improvised and more practical than stylish. Even her survival knife – which is what gives the piece of its title – has an unassuming look: It’s just as simple as a knife can get. It’s not a piece of fashion, It’s just a tool to get stuff done.
For a long time, she was supposed to have a rather messy loose hairstyle to further underline the idea that she doesn’t really care about her look. But in the end, that didn’t really work for me. So I decided to accept a compromise on that front, for the sake of making her look more captivating, and gave her a more interesting hairstyle. Even so, the way she ties her hair had to look improvised and a bit messy.
If I have to create a hard-surface model, I tend to rely much more on Maya, but I might still create a simple sketch of it in ZBrush.
I like to plan ahead for how the rig is going to work. So, I tend to bring early versions of my work in Maya in order to experiment with those. That can sometimes inform my design choices. An example of this is the sheath on her right leg.
For the clothing, I just work in Marvelous Designer and then bring the result in ZBrush for finalizing and detailing.
Those, who followed me during the development of this project, already know that I wrote a little tool called 'jQuadCloth' that makes the ZBrush ready topology in a blink of an eye. It's not always perfect, and it crashes a lot but when it works it can save a huge amount of time.
The backpack was handled in MD as well for the most part. I simply fitted it with some "pillow-like" shapes imported as objs. Then I did the same process for the clothing. Straps and buckles are all made in Maya instead.
For the shoes, I learned some neat tricks from a tutorial by Henrique Naspolini. It was my first time creating shoes this realistic and it was pretty fun. This time around I wanted to rely more on geometry for the soles. That definitely was the hardest and most time-consuming part.
When it comes to texturing, I don’t really feel that confident in my skills and experience. I’m a total newbie with Substance Painter. So, that itself was an interesting challenge for me.
I didn’t handle any tiling details in SP simply because I didn’t know that it was a thing that one can do. So, I just handled the low-frequency textures in SP and the high-frequency details directly in the engine.
For the stitchings, I used two additional UV sets (two so that it’s easy to handle crossings). The biggest challenge there was the fact that, in order to be able to use additional UV sets, I had to implement that capability inside my engine. And in order to do that, I had to think about the way I handle tangents (cause they depend on UVs and they are fundamental for tangent-space normal mapping).
Getting the fabric to look good is something I definitely struggled with, and it's something I would like to explore better in some future project.
Creating the Hair
The hair is made by hand-placing cards. When it comes to positioning and shaping them, it’s really a matter of time and patience.
Even though there are tools out there that can help by quickly generating tons of cards, the result, in my experience, is never as clean as it could be by doing things by hand.
The hair textures were generated using XGen. I have a scene where I have a bunch of clumps with different shapes and densities that can then be rendered with whatever rendering engine is available (that would be VRay in my case) and then used as texture. I like to keep my hair textures generally straight so that I can handle the waviness through the geometry itself.
For a messy hairstyle, such as this one, I would not advise transferring normals from a simple geometry ‘cause that would take away the messy look.
In order to render the hair, I had to write a dedicated hair shader specifically to handle the anisotropic specularity of the hair. Hair has a very peculiar way of reflecting light. Ironically enough, I've learned about this by watching a talk from some of the Unreal Engine tech artists themselves.
For the skin, the first step was to project a TexturingXYZ set on the high-res model using Mari. The result can be used in order to get a very nice layer of details in ZBrush, containing pores and wrinkles.
Those details need to be then transferred on the low-res model as a normal map. I tend to use either xNormal or the 'transfer maps' function inside of Maya for that task. While in the engine, it also helps add a layer of high-frequency details on top of the normal map in order to break the specular highlights. For this project, I simply used a normal map generated from a noise. The result really looks much better than without the noise. However, one could get much fancier and use some more specific maps representing different kind of pores for different areas of the face. I would love to experiment with that in the future.
So, that takes care of the normal map.
About the skin colour, I used another TexturingXYZ set as a base. On top of that, I added some colour correction in order to achieve a skin tone that I liked. I also added a very subtle layer of colour variation, and then details and freckles are hand-painted. Mari offers some pretty neat brushes dedicated to painting freckles.
The skin shading is something different entirely 'cause that needs to be handled by a Sub Surface Scatter shader which - you guessed it - I had to write.
For the specific task of writing my SSS shader, I didn't rely on any documented technique. Instead, I wrote the shader by just relying on my own knowledge about the SSS phenomenon. My solution is most likely not the smartest around but I'm proud of how it looks. I might do some further research in the future and maybe explore some different techniques. But for now, I don't feel the need to do that.
For a very lame explanation of how my SSS shader works, it basically samples the lighting on a bunch of random points surrounding each pixel that needs to be shaded. Then, it averages those lighting information together keeping into account distance and scatter colour. It's a pretty naïve approach but it gets the job done.
There is also some interesting stuff to be said about how the eyes are rendered. More specifically I'm using a special trick for the tear line: I'm not relying on any additional geometry for that. Instead, I'm doing all in the shader. Basically I'm blending the normals and diffuse colour between the eye bulb and the eyelid. By doing that, I achieve the illusion of a smooth bevel in the area of contact between eyes and skin, which causes a specular highlight to form.
I came up with this technique myself and I'm not sure if it's being used by anyone else. In theory, it's pretty easy to implement but there's an engine requirement: it is necessary to have a way to guarantee that the eyes get rendered after the face so that all the information that needs to be blended is available when the eyes get rendered.
The illusion of depth on the iris is achieved using parallax occlusion. Sclera and iris are defined by one single geometry. So it is necessary to have a way of rendering two distinct surfaces that are defined by the same geometry. However, this is nothing really new and, in fact, it's one of those things that I mentioned was doable in UE3 but not in UE4 for a while.
After the model and textures for the character were finally done, I did set up a little rig in order to be able to pose her. This rig was not really meant to work in-engine. So, I made the pose in Maya and then exported everything as "static meshes". My engine already supports "skin meshes" and animations to an extent, and that's something I'd like to show off sometime in the future. But for this project, I figured it would have been much smarter to keep things simple and just have a set of static meshes to be rendered.
Topology is a task that I feel very comfortable with.
When retopologizing for real-time applications, not all people know that there's no point in having a full-quad topology: this style of topology is good for subdivision surfaces but only provided that there are no clusters of poles (vertices where the number of connected edges is not 4).
For real-time applications, where keeping a contained polycount is important, one might want to strategically use triangles every time it makes sense (cause every quad is made up by two triangles). When doing so, most decisions might be taken by simply looking at the silhouette of the object being retopologized. Whenever something has an impact on the silhouette, it's worth considering spending more of the budget there. If something is concave, chances are that it won't have any impact on the silhouette at all and, therefore, one can spare some triangles there.
I particularly like to use a technique that consists of using triangles to define convex surfaces such as spheres. If it is done properly, this technique can yield a much cleaner silhouette or a much smaller polycount.
Of course, for the case of a character, which needs to also be skinned and rigged, one needs to take into account deformations, and a decent edge-flow is desirable.
My tool of choice when doing retopology for this sort of project is Topogun. Maya's quad-draw is neat for full-quad topologies. But as mentioned before, such topologies can be counterproductive in the context of a real-time application.
One thing that I did for the very first time while working on this project is to make the topology such that it supports stitchings. As I said earlier, I used multiple UV sets in order to achieve the stitchings. In order for that to be possible, one has to properly set the topology so that poly loops run along the stitchings.
Setting everything up in the current version of my engine is not really the most interactive thing one could imagine. As mentioned before, there's no GUI. So everything still needs to be loaded and placed in the world via C++ code.
For the 3D models, I wrote a custom file exporter for Maya. I'm not relying on the FBX format 'cause I like to have full control over what exactly gets written into the file. Once I have a file saved on the disk, I have to write a little line of code to tell the engine that I want to load that file and that I want to deploy the mesh into the world.
Something similar happens for textures and materials. The materials specifically have to be written in GLSL (that is the OpenGL shading language).
Then, I have to write some code to associate textures with materials and materials with meshes. I can also mess with the position, rotation, and scale of any object, and I can play with the hierarchy.
Lights and cameras can be placed into the world in a similar manner.
Input from mouse and keyboard can be used to achieve whatever behavior one might want. So I've made a camera class that essentially mimics Maya's camera navigation style.
While thinking about the lighting to present this character, I wanted something that looked like natural lighting. So, I simply used a relatively warm directional light to simulate the sun, and some cooler environmental lighting (achieved through IBL).
Once I launch the program, rendering happens in real-time at an interactive speed. So, I can simply orbit the camera around and rotate the light and the character itself. Once I find a nice shot, I simply take a screengrab of it and that's that.
The biggest challenge for me when working on this character definitely was to stay motivated, especially when realizing the insane amount of time that it was taking me to complete her, and then, even more, while realizing how much time it would still have taken to do everything that I had planned in the beginning.
When I started this project, a couple of years ago, I wanted to show people that my dedication is no joke, and I can go many extra miles. So, I challenged myself in many ways just so that I could really hammer that point down. But in the end, some of the things that I had in mind would just have required too much time for it to be even worth it. This needed to be a portfolio piece after all.
Something that I wanted to do was to experiment with dynamic normal maps and corrective blend shapes. The latter, in particular, would have required some more work on the engine side of things plus a lot more work on the art side.
Something else that was planned in the beginning was a raincoat with working zipper and hood as well as cloth dynamics.
All of those things are still in my mind and ready to be explored in a future project. They will only take a lot of coding and experimenting and then coding again. If there is something I've learned, it is that one has to take one step at a time.
But in the end, it looks like my point came across regardless of the difficulties. I'm so glad and thankful for all of the people, who noticed my work and reacted so positively to it. That really made a huge difference, and it made it all worth it.
Also, I would like to say thanks to 80 Level for giving me the chance to talk about this character and my engine.