MatCap Mayhem! [Part II]

So I’ve gone over why using matcaps can be an efficient way to get some good-looking materials in 3d graphics, but we also came across one of the main downsides of matcaps: they’re camera relative and that’s pretty limiting. So if we’re hell-bent on using matcaps we either live with this limitation – obviously unacceptable – or we hack the **** out of it!

Matcap_CameraLink

Ever since I tried out Rodrigo Fernández’ tutorial on painting with render textures I’ve found a part of me always trying to solve problems with them. I won’t even blame you if you stopped reading this at the link and started following that tutorial instead – it’s worth it. Do you want to do a quick footprint system? Point a camera at a ‘canvas’ somewhere, spawn some bad boys on there and apply the texture back to your ground plane. Do you need to paint asteroid hits onto a planet’s surface with displacement? This example has 3 cameras hidden throughout the scene capturing the planet surface with dust, the emissive from the asteroid hit, and black and white rings for the displacement:EarthContraAsteroids_Grey_02Is it going to be the most efficient method to achieve certain things? Honestly, oftentimes not. Is it a great technique to aid you in a pinch or to do obscure things that might otherwise be rather complex? You betcha! The above giffy is from a weekend game-jam; I don’t think my turtle-brain could have come up with any other solution to get that effect over the course of a day.

So that’s exactly the technique we’ll use for our camera-independent matcaps. In fact, the concept is quite straight-forward, although we’ll [sort of] stop using the typical flat matcap image as the actual source for our material. Instead, we’ll bake out our material to a texture mapped onto a sphere:Matcaps_BakedSkinSphere

See where I’m going with this?

Then we’ll set up a scene where we have an orthographic camera pointing at our sphere and ideally add occlusion layers to both it and the main camera so that the main camera can never see our matcap and our baking camera never sees our scene. For testing it’s not necessary but if you ever want to actually use this method you might end up with some delightful bugs if you don’t. I’ve also set my clipping planes pretty aggressively just to be safe. Finally, I’ve created a new render texture (right-click anywhere in your “project” pane > Create > Render Texture to create one) and pointed the camera to render to it every frame.Matcap_CameraSetup_01

Now it’s time to write a simple script that will match the capture camera’s rotation to that of the main camera. For simplicity’s sake I’ve actually parented the cameras under empty nodes I’ll be using to control their rotations as if those nodes were their pivot points. So now we get something that looks like this in our scene view when we rotate our camera’s parent with the game running:Matcap_CameraLinkSince the scene view camera isn’t duped by this trickery at all, we can see that the shading on the character is now changing based on the camera’s direction. If we look through our main camera we should see something more like this:Matcap_CameraLink_CamView

Nothing weird or interesting at all. Rather it simply looks like what you would expect from a normal material – which is exactly what we want. Here’s a look at four of the matcaps our camera is actually ‘baking’ out to the render texture as we go around:

Matcap_RenderTextureExamples_01

For reference here’s the camera follower script I was using:

public class CameraFollow : MonoBehaviour {

    public GameObject followTarget;
    Quaternion offset;

    void Start () {
        offset = this.transform.rotation * Quaternion.Inverse (followTarget.transform.rotation);
    }

    void Update () {
        if (followTarget != null) {
            this.transform.rotation = followTarget.transform.rotation * offset;
        }
    }
} 

Honestly that’s pretty much it. For this proof-of-concept the setup is rather basic but you can easily take it off the rails and do some interesting stuff with it. In this example I’ve extended it to have a script that also makes the hottest spot of the sphere follow the directional light’s rotation (plus an offset for ease-of-use):Matcap_LightLink

Light-follow script for reference:

public class LightLookat : MonoBehaviour {

    public GameObject light;
    public Vector3 eulerAdjust;

    void Update () {
        if (light != null) {
            this.transform.rotation = light.transform.rotation * Quaternion.Euler(eulerAdjust);
        }
    }
}

Now this of course comes with it’s own limitations, before we could simply paint a 2d image and get interesting or bizarre effects pretty quickly. This method not only requires you to pay the costs of a render texture, a potentially larger source texture and some extra geometry in your scene, but it also asks you to create a “3d” source. We can still get interesting hand-painted effects with the likes of Substance Painter, zBrush and the like but admittedly it takes a bit longer getting there. Just to prove the point though here’s a quick an dirty “stylized” version of our creepy skin ball:Matcaps_BakedSkinSphere_Stylized

Please excuse the careless use of Photoshop filters; I’m not proud of it but it was getting late…. Below is the effect on our actual character:

Matcap_Stylized3DExampleApplied_01

At any rate, thanks for sticking around! If [Part III] ever shows up perhaps we’ll try to stick these fun-times into the shader as opposed to using this hacky method – I can’t think of any reason why we couldn’t and it would certainly be more elegant. Otherwise we can take a look at some additional effects like layering matcaps with standard shaders! Oh the possibilities!!!

Until then!

-Greg

3 thoughts on “MatCap Mayhem! [Part II]

Leave a reply to gpuzniak Cancel reply