YL2 Update Nov 2018 - Texture builder demonstration/tutorial
We hope you're doing great!
This month we've been integrating the texture building system into the editor. This system is our attempt to facilitate the creation of color schemes for your characters, all while having a small performance and bandwidth footprint. By utilizing the GPU for all texture operations, response is immediate and interactive. This system has been a long time in the making, so we are super excited about it finally being fully integrated!
Before we begin ...
In our last update, we showed a roadmap of what is left to be done before we feel ready to release a patron build. In it we mentioned the texture building system. However, I realize afterwards I wasn't properly expressing the amount of work still required to finish it. There's much more to it than just writing different states for different object selections. The states are a big part of it, but so is the whole event driven architecture that has to be meticulously setup in order to cause the right things to happen when you change objects connected to it, and also actually handling the input and output of the system. It was these parts that I forgot to properly communicate the depth of. But! It's all implemented now and works like magic, so let's just jump right into it!
The texture builder is a system designed to generate textures used by characters in YL2.
Textures are huge resources, so in order to minimize the bandwidth usage and download times, we have opted for creating a system that procedurally generates textures. This also comes with other benefits, such as being able to change colors and have the whole stack of layers update dynamically.
The texture builder makes use of "masks" and "layers" when filling in the textures used by a character. Each mask can also have many different kinds of filters added to them to achieve different kinds of effects. Furthermore, each layer can be blended according to many different blend modes. You can use both procedural masks (computer generated) as well as custom made ones (imported textures). While custom masks are much heavier than procedurally generated ones, they're still relatively small in comparison to full color textures. Combine these options to achieve the kind of look you want!
Demonstration / Tutorial
The character is missing normal/AO maps, ears and hair, so it does not represent final quality. These are examples of the texture building system only - nothing more, nothing less.
Also, I recommend opening the gyazo links because the framerate in those is much better than in these gif files (unfortunately, Patreon doesn't allow video embed). Plus, they start from the beginning, making it easier to follow.
Let's go through the different type of masks and layers to see how they work and how they can be used together.
By default, a character spawns with the most simple type of layer - a "Fill" layer. All it does is simply fill each channel with a value. It works well as a starting point to give the character the general appearance you're going for. Let's go through some of this layer's settings:
Now, let's try to create something more interesting by using masks!
The linear gradient is one of the procedural masks. It simply smoothly blends from black to white according to two placed points in the scene. These points can be snapped to the character, either directly on the surface or to a bone. That way, if you were to alter the character (for example change body type, height or bone scale), the points would remain in their relative locations.
To add a linear gradient, simply browse to the plus symbol beneath "Masks" in "TextureBuilder":
As you can see, when the gradient is added, it is automatically selected and the editor transitions into a special state tailored for this object.
The linear gradient has two main inputs - a point where it starts and a point where it ends. Simply click on a point to activate its 3D gizmo, and then drag it around. You can also quick-select a certain point using the number keys - "1" for the starting point and "2" for the end point.
Let's assume we want to create a gradient on the arm that goes from white to black (using number keys to select points):
Here, we're also making use of another shortcut - Shift + Mouse 1 to snap the points to a bone. (These shortcuts are displayed at the bottom of the screen.)
The arm looks fine now, but the problem is that the mask is also affecting the torso and legs. There are many ways one could fix this. Let's try to fix it by using another mask that only selects the arm, and then combine it with the one we just made:
When creating the linear gradient, we are snapping the points using the "snap to surface" shortcut, Ctrl + Mouse 1. Then we add another mask, "Mask operation". This mask can be used to combine masks together into a single mask. The default blend mode "multiply" will simply multiply any referenced masks, thus only filling the intersecting selections.
Now we have an arm filled in the manner we want. We want it on the other side too though. Does that mean we have to repeat this whole process for the other side as well? Luckily no, we can just use a "mirror" filter:
A mask by itself doesn't really do anything. It needs to be referenced somewhere. Let's add a mask layer to do just that:
In YL2, all colors used by a character are defined in the main character object. These colors can then be referenced in other objects. This means you have a single location to control all colors.
By default, a new layer will always fill the albedo channel with the color at index 0. You can of course change what channels to fill and what colors to use:
Since we're using a PBR shader, you can also make the character metallic if you wish (for whatever reason). Let's try to make our mask look like gold:
Granted, this example is a bit silly, but it proves what control you have over the channels.
Let's revert back to the old green color by undoing these steps:
(Undoing steps, first by menu commend and all following times with keyboard-shortcut.)
Almost all actions in the editor are possible to undo. The exception is deletion of local assets, which will be released from memory if deleted. Other actions, such as altering objects or even completely deleting them are possible to undo.
Now, let's assume we wanted this kind of effect on the legs too. Let's create a new linear gradient:
Since this gradient doesn't affect any other body part than the legs, we only need one gradient. We still need to mirror it though:
By default, a mirror filter simply mirrors the texture and then adds it together with the original one. In this case, this is not what we want. We want the character's right side to mirror to its left side. So lets go into the mirror filter's options and change it to do just that:
Excellent! Now we have a satisfactory mask selection on the legs. Let's combine it with the arm selection by creating another mask operation, but this time, instead of intersecting the layers (multiply), let's just add them together (linear dodge):
Then, reference this newly created mask in the mask layer:
In this case, I think the gradient on the legs doesn't transition quite as smoothly as I want it to. Let's try to remedy that by adding another filter on the linear gradient for the legs. Also, by using the "FINAL" mode in the display options, we can preview the changes directly as we're altering the mask:
There's a lot going on here to make all of this work. Essentially what's happening is that as we're changing the linear gradient for the legs, it's sending an event to whoever is listening that "Hey, I've changed!". The listener, in this case, is the operation mask (the one combining the arms with the legs), which in turn says "Hey, I've changed!". This causes the fill mask layer to notice the changes, which says to the texture building system that the stack has changed, and finally the textures are updated.
(The "Power" filter simply raises the mask according to the exponent, i.e. mask^exponent, causing it to smooth out.)
Let's spice this texturing up a little bit with decals.
We have prepared a heart image. Let's import it and start adding decals!
By using the tools, you can transform a decal after it has been added. Simply click one of the tool buttons, or access them quickly through the displayed keyboard shortcuts:
Now, let's mirror this group and add it to the rest of the masks to have it included:
Since we're just using masks and color references, we can easily change the colors of all items by simply altering color in the main character object:
We can of course also play around with other channel settings:
Let's check out some more layers and filters on a new color scheme.
I asked dogson to create a tiger stripe mask texture. Let's import it and see what we can do with it:
Now, let's explore another type of layer, the "gradient fill" layer. This layer requires two masks - one for the gradient and one for masking. Let's start by creating a new gradient:
Next, let's add a liner gradient that's going to act as the gradient mask input for the gradient fill:
And finally, let's add the actual gradient layer itself!
The way the gradient fill layer works is by simply looking up a color value in the referenced gradient using the provided gradient mask. Black means the color to the left, and white means the color to the right, and any colors in between are interpolated.
Let's try playing around a bit more with the gradient:
Naturally, if you change anything in the stack, the textures will update automatically and immediately to reflect the changes. Here we're adding a grow-shrink filter to the texture mask:
This goes for any layer and stack. So if we for example change the texture mask into a decal group instead, it would work the same way!
(Silly decal example.)
Having seen this demonstration, I'm sure you have your own ideas of how to use these layers and masks!
The texture building system marks a major milestone in our development. Since everything has been implemented in a modular and extensible fashion, we can easily keep on adding more types of layers, masks and filters with time!
Here's a few words from Dogson:
Hello, this is Dogson, the character modeller. After the announcement of our new separate anus mesh in combination with our seamless tech we realized we had to change the topology for the area of the anus for better deformation.
Pondering about this, some old luggage that had been in the back of my mind gnawing started to creep back and that was while the mesh we had was very much optimised and lightweight, verts-wise, it had one rather big problem: It wouldn’t handle big shapes such as exaggerated muscle or exaggerated fat that well, the quads on the arms and would always stretch out to elongated quads, this is bad for both deformation and map-baking.
It handles slender or normal shapes fine, but we’ve built much of our fanbase with the help of our fans that loves fun-sized characters and not being fully able to give them what they’re here for would be very bad.
And for each day that passed, the window of opportunity to change the mesh to better handle deformation would shrink bit by bit and I knew that not fixing it would make me regret it for a very long time.
So after talking to Odes I went to work, I could just add more edge loops to the old one, but what would that point be if I couldn't make it even more deform friendly. I looked at a lot of references on how to generally draw out strips of topology that would be crucial for deformation. By using circles in our topology instead of straight lines, crucial shapes such as the buttocks and belly conserve their shape much better when they’re deformed. And after a while and some revisions later, I think we got it.
A bit more poly-heavy, but it behaves much more better for deformation and map baking.
Here are some few examples of it being an upgrade that can serve.
Old mesh with baked maps.
New mesh with baked maps
Inflate belly, old mesh, problematic even if we’d use our tessellation shader (tessellation not used here though).
Inflate belly, new mesh, the mesh can handle it much better than the old one
This mesh works much better for our needs, and I’m very excited about the future!
This is something we experimented with last month but completely forgot to include in the update! So we're doing it now instead. HDRP is the future of high fidelity rendering in Unity. Last month, we were doing some testing to see how we could eventually transition into HDRP, and also upgraded our project to Unity 2018.2, bringing HDRP within our reach.
One of the many new features that HDRP offers is true support for sub-surface scattering (SSS). This feature allows us to render characters and parts in a much more believable manner. Here's an example we experimented with where we toggle SSS on and off on a horse dick. It's a very subtle effect and yet it makes a huge difference. The dick really comes off as something made out of flesh when SSS is enabled.
HDRP isn't quite where we want it to be in terms of maturity just yet, but it's definitely something we're interested in and will probably transition to at some point in the future. (Probably not for the first build though.)
The texture building system is finally integrated into the editor, making it accessible to the user. This marks a major milestone in our development, so it feels great finally having it completed.
Dogson has been working on a new iteration of our universal mesh, making it more adaptable to the types of deformation we want to implement (inflation and body types).