in shader, tutorial, Unity3D

3D Printer Shader Effect – Part 1

Share Button

This tutorial will recreate the 3D printer effect seen in games such as Astroneer and Planetary Annihilation. It’s an interesting effect that shows an object in the process of being created. Despite looking simple, there are many challenges that are far from being trivial.

a1

This is a two part tutorials:

A link to download the Unity package (code, shader and 3D models) is provided at the end of the tutorial.

Introduction: A First Attempt

In order to replicate this effect, let’s start with something simpler. A shader that colours an object differently, depending on its position. To achieve this, we need to access the world position of the pixels being drawn. This is possible by adding the field worldPos to the Input structure of a Unity 5 surface shader.

In the surface function, we can then use the Y coordinate of the world position to change the colour of the object. This is done by changing the Albedo property of the SurfaceOutputStandard structure.

The result is a first approximation to the effect seen in Astroneer. The main problem is that the coloured part is still shaded.

01

Unlit Surface Shader

In a previous tutorial, PBR and Lighting Models, we have explored how to create custom lighting models for surface shaders. An unlit shader always produces the same colour, regardless of external lighting and view direction. We can implement it as follow:

It’s only purpose is to return a single, solid colour. As we can see, it refers to SurfaceOutput, which is used in Unity 4. If we want to create a custom lighting model that works with PBR and global illumination, we need to implement a function that takes SurfaceOutputStandard as an input. In Unity 5, it is the following function:

The gi parameter is there for the global illumination; but it serves no purpose in our unlit shader. Despite working, there is a big problem with this approach. Unity does not allow surface shader to selectively change lighting function. We cannot use the standard Lambertian lighting to the bottom part of the object, and the unlit for the top part. We can only specify a single lighting function for the entire object. It’s up to us to change the way the object is rendered depending on its position.

02

Passing Paramters to the Lighting Function

Unfortunately, the lighting function has no access to the object position. The easiest way to provide that information is to use a boolean variable (called building) that we set in the surface function. The variable can then be queried by our new lighting function.

Extending the Standard Lighting Function

The last challenge that we have to face is a tricky one. As explained in the previous paragraph, we can use building to change the way lighting is calculated. The section of the object that is currently being built will be unlit, while the other should have proper lighting. If we our material to use PBR, we cannot possibly re-write the entire code for photorealistic lighting. The only reasonable solution is to invoke the standard lighting function that Unity has already implemented.

In  a traditional standard surface shader, the #pragma directive that specifies to use the PBR lighting function is the follow:

Following Unity’s naming convention, it’s easy to see that the function that they use should be called LightingStandard. This function is found in a file called  UnityPBSLighting.cginc, which can be included if necessary.

The plan is to create a custom lighting function called LightingCustom. In normal conditions it simply invokes the Unity standard PBR LightingStandard. When necessary, however, it adopts the previously defined  LightingUnlit.

In order for this code to compile, Unity 5 requires an additional function to be defined:

That is used to calculate the lighting contributions for global illumination, but is unnecessary for the purposes of this tutorial.

The result is exactly what we expect:

03

Conclusion

This first post focused on how to use two different lighting models in the same shader. This allowed us to have half of the model rendered with PBR, while the other half uses is unlit. The next post will conclude this tutorial, showing how to animate and improve the effect.

08

Patreon You can download the Unity project for this tutorial on Patreon.

A big thanks goes to the guys at System Era, and in particular to Jacob Liechty.

Support this blog! ♥

In the past two years I've been dedicating more and more of my time to the creation of quality tutorials, mainly about game development and machine learning. If you think these posts have either helped or inspired you, please consider supporting this blog.

PatreonBecome a Patron Oo4th_patreon_name
PaypalDonate on PayPal
Twitter_logoFollow on Twitter

Don't miss the next tutorial!

There's a new post every Wednesday: leave your email to be notified!


Write a Comment

Comment

  1. Hey Alan,
    Thanks for the tutorial! I am currently stuck on the part with the unlit surface shader. After following your steps, there is an error saying that the surface shader lighting model ‘Unlit’ is missing a GI function, and I am unsure of how to proceed. Could you help me with this? Thanks again!

  2. Hi Alan,

    Your tutorials are great, there is one part I don’t understand though. In the part where the unlit lighting is being applied to the whole model, why is the entire thing not lit orange because the lighting function always returns the construct color? I guess I don’t know the way the surface and lighting functions intermingle.

    • Hey!

      If you use “return _ConstructColor;” as your lighting function then YES, your object will have a single, unlit colour.

      The picture where the object is half orange / half white with flat lighting comes from the fifth code snippet, which uses “int building”. That lighting function has a condition inside!

Webmentions

  • 3D Printer Shader Effect - Part 2 - Alan Zucconi March 26, 2017

    Alan,

    I can’t seem to get this shader working in Unity5.5+ as they seemed to have refactored several things in the shader code-base (https://docs.unity3d.com/Manual/UpgradeGuide55.html). Any chance at an update, or providing a working version of this shader for Unity 5.5? Thanks!!