About Me

Hi. I'm Josh Ols. Lead Graphics Developer for RUST LTD.


View Joshua Ols's profile on LinkedIn


Entries in Unity3D (29)


SH 0th order as an ambient light sensor


The other day an Alloy customer came to me with a weird problem that I never could have anticipated. Basically, they have a full PBR pipeline including physical materials, high intensity lights, and filmic tonemapping with automatic eye adaption. Their game also has a slick in-world 3D UI system involving an emissive holographic display. Independently, these things are great, but apparently they break down when put together.



You see, the emissive display looked great in typical indoor lighting settings, but would become unreadably dark when the player went outside into direct sunlight. The culprit was the automatic eye adaption responding to the bright sunlit surroundings and dropping the exposure to darken everything, including the emissive display. Essentially, this is the exact same problem that smartphone displays face in the real world.



So how do smartphones try to deal with this problem? They use ambient light sensors to determine the overall brightness of their environment and crank up their screen brightness to compensate. So how do we accomplish this with a shader?

It turns out that Unity provides all the information we need in the form of light probes. Specially, the probe’s Spherical Harmonic’s (SH) 0th order is a constant color representing the average of all incoming ambient light at that point in space. Thus, the luminance of this color is a pretty accurate measure of the light intensity of its surroundings.

With this information in hand it was easy to dynamically scale the display’s emission intensity based on a curve, which now made it viewable under all lighting conditions.



Unity shader code injection


I’m sure many of you have had this thought, “Boy, Alloy is great but I really wish I could use its area lights and nice attenuation with other Unity shaders!” As luck would have it, I am implementing that very ability using a little known feature of Unity’s shader system.

“What might that feature be?”, I hear you ask. Well…


Shader code injection

That’s right, it is possible to force a shader to use custom code without having to modify the shader. It works because of how Unity’s shader system resolves “#include” directives for handling headers. If you use it like “#include “myHeader.cginc” with just the filename and no path then Unity will first look in the same directory as the shader file, and then search the editor’s hidden include directory.

So basically, if the shader uses an editor header (eg. “UnityCG.cginc”) you can trick that shader into using a customized local version by copying the header into the same directory as the shader. Then you can simply modify that local copy and the shader will use that instead. This will work for any shader code, even the Standard shader and the generated output of a Unity surface shader.



After mucking around in surface shader output, and mangling some of Unity’s macros, I now have it working with Alloy. So any surface shaders that use the Standard and StandardSpecular lighting models can now be lit using Alloy’s lighting model and material options. This way, forward-only shaders can now match deferred-compatible shaders when used alongside Alloy.

Keep an eye out, as we will be releasing this new feature in beta form in our next bugfix release.



Unity, Consoles, Shaders...


Also it seems like it would be a good idea to test in OpenGL mode on an AMD/Intel GPU. Their GLSL compilers seem especially strict, so you're likely to catch the most bugs on those platforms.



Apparently you also need to assume some of the strict assignment and swizzling rules of GLSL. Certain things like accidentally assigning a four component vector input to a three component variable will pass for Direct3D, but blow up once you hit OpenGL.



To all the people authoring shaders for Unity with the goal of having them work on all of Unity's supported platforms I say the following:

  1. The shaders are HLSL! Unity still calls them Cg for legacy reasons, but they've all but abandoned that platform. So when looking up how to do something in the shaders, look for HLSL tips!
  2. Read the header "HLSLSupport.cginc" and burn its contents into your memory. Inside you will find all the crazy preprocessor juggling that Unity has to do to hide platform and language API differences. 

Today I learned this lesson the hard way with Alloy's parallax occlusion mapping code. Basically, in Cg if you want to apply texture coordinate derivatives then you use an overloaded version of tex2D(). In HLSL, you have to use an explicit intrinsic called tex2Dgrad().

Guess which one is platform-safe in Unity's shaders? To find the answer, follow tip #2. :p


Alloy 3.1 - Asset Store Madness

It's that time again! The Unity Asset Store is having another madness sale. For this week only, you can pick up Alloy 3.1 half off at just $62.50! If you've been hesitating due to price, now's the time to jump in and grab it! XD

Alloy - Unity Asset Store


Alloy 3 is up on the asset store!

After months and months of work it is finally here! See the Unity forum thread for details:

Alloy - Unity Asset Store