How to Create Your Own Projected Texture

One of the things I've noticed across the Internet is there's no one place for figuring out how Projected Textures work in Unity. After a few hours of digging, testing, playing, etc. I wanted to jot down my notes for the future, and if others need this information.

You're in Unity, and you want to make an Area of Effect targeting reticule/cursor, like so:


The way that WoW does it, and many other games, is using a Projected Texture. In Unity, this can be achieved by using a Projector. Unity comes with a few Projectors pre-made for you, but little-to-no instructions on how to create one of your own.

The first thing to understand when making a Projector is that you need a Material, which combines your Shader and your Texture to perform the projection.

Create the texture first by dragging and dropping an image into your asset folder within Unity. PNG or GIF are two good options, but either way, you need to know what you're projecting. For this example, I'm using a simple circle. Note that if you'll be using an additive shader, you want your "empty" spots to be black (0,0,0). If you'll be using a multiplicative shader, you want your "empty" spots to be transparent. I'll discuss the difference later, but for this example, I'll be using multiplicative.

 
Also note that the image has a 1 pixel border, and is a power of 2 in size (64 by 64 pixels, in my case). The power of 2 is pretty standard for textures, but the 1 pixel border needs some explanation. I'll show you why in a bit, but for now, just understand that you need 1 pixel around your texture to be empty.

You'll also need to change the texture's wrap mode to "Clamp" rather than "Repeat", otherwise your texture will just get painted over and over and over again on your terrain.

Once you have your texture, you need a shader. If you import the Projector assets via Assets->Import Package->Projectors, you'll get a Light shader (as if you're pointing a flashlight), and a Multiply shader (great for shadows). We want an Multiplicative shader in this case, and Effectronica has a pretty good one for dealing with transparency, as well. That's the one I use in this example. (Note Effectronica claims it is an additive shader, which is incorrect. He's clearly multiplying the effects in the shader).

So in Unity, right-click in your Assets folder, and Create->Shader. Open that up in your favourite editor, and put in your new shader code.

Once you have a shader and a texture, you need to create a material. Right-click in your Assets folder and Create->Material. On the material at the top of the Inspector window, change the shader to your new one (for Effectronica's, if you just copy/pasted, you should find it under Effectronica/Zodiac_Additive). This should bring up a few things you can altar on the shader, like textures and color.

You'll want to drag and drop your texture to the Cookie texture slot, and change the color of your material to what you want on the terrain.

After all of this, you're ready to create the Projector. Create an Empty Game Object, and then go to the Add Component button in the Inspector. Search for "Projector" and add it. Throw your material onto it, and position the "camera" over the area you want to highlight, and turn it 90 degrees on the x-axis to point it down. You should see something like this:


Not too shabby, eh? If you don't see that, there's a couple things that may have gone wrong. If instead you see lines coming out of the four cardinal directions like below, chances are, you didn't leave a 1 pixel border around your texture. This is because a Projector really just redraws the entire surface, and duplicates the border pixels ad infinitum when the texture is clamped. If you let the texture be repeated instead, you'll see this will become obvious. This is good to note from a performance perspective, as well. Each Projector will cause another rendering pass as far as I can tell, so limit your Projectors.

Forgot your 1 pixel border, eh?

Another issue you may run into, especially in the perspective projector is similar to above, but it only appears at certain angles. What you'll want to do in that case is go to your texture, change the type from Texture to Advanced, then turn on Border Mipmaps.

Border mipmaps will remove these artifacts.
When dealing with this dynamically, having to calculate the precise distance you need to place the projector above to get a radius of a specific amount is difficult. You can make this easier on yourself by checking the "Orthographic" checkbox, and changing the Orthographic Size, which seems to be the "radius" in units.


Finally, perhaps you don't want your projector projecting on everything. It looks a bit sloppy. You can tell it to ignore certain layers. Ensuring that your terrain is on it's own layer, you can have it ignore all layers except terrain, and bam, now your spell circle goes underneath the objects.


And that's it! Play around with the shader, your texture, colors, etc. from there to customize your projected texture.

6 comments:

  1. Thanks for the article, but do you happen to have a link to a projector shader that will work with Unity 5? The one referenced in this article doesn't work anymore as they appear to have removed support for "fixed functions".

    ReplyDelete
    Replies
    1. I do not, unfortunately. We're stuck on Unity 4 for now as a studio, so I haven't had a chance to dig into 5 yet (or see what breaks). If I do, I'll be sure to update it here.

      Delete
  2. Unfortunately projectors go through objects, so it only works on fairly flat terrain and not at all when there's several layers of objects.

    ReplyDelete
    Replies
    1. you might try something with raycasting and adjusting the far clip plane...

      Delete
  3. any chance something like this will work with a movie texture?

    ReplyDelete
  4. Thanks so much for the awesome post. I ended up using the built in blobShadow projector and using my own texture. This post saved me some time working out the finer details of that.

    ReplyDelete