0
\$\begingroup\$

For my game, I want some sort of indicator of if a space is walkable or not. To achieve this I figured I would create a decal projector and have it follow the mouse cursor around, displaying a decal beneath the cursor. I would then color this decal a different color depending on if the surface the cursor is over is walkable or not (e.g. red for not walkable and green for walkable). However, when I change the color of the decal's material the color of the decal does not change! How can I change the color of a decal in Unity using Universal Render Pipeline?

[RequireComponent(typeof(DecalProjector))]
public class DecalTinter : MonoBehaviour
{
    [SerializeField] private Color validColor = Color.green;
    [SerializeField] private Color invalidColor = Color.red;

    [SerializeField] private new Camera camera;

    private DecalProjector decalProjector;

    private void Start()
    {
        Assert.IsNotNull(camera);
        decalProjector = GetComponent<DecalProjector>();
    }

    private void Update()
    {
        var ray = camera.ScreenPointToRay(Input.mousePosition);
        if (!Physics.Raycast(ray, out var hitInfo, float.MaxValue, LayerMask.GetMask("Ground")))
        {
            return;
        }

        var material = decalProjector.material;
        // This does not work!
        material.color = NavMesh.SamplePosition(hitInfo.point, out _, 0.1f, NavMesh.AllAreas)
            ? validColor
            : invalidColor;
    }
} 
\$\endgroup\$
1
\$\begingroup\$

Unfortunately this does not seem possible with the default decal projector shader. Fortunately creating your own shader that does this is super easy!

  1. First create the decal projector and add your script that will tint the material.
  2. Then open up the editor for the decal shader:

picture showing an image of the decal projector and decal tinter script in the inspector view, with an arrow pointing to the "edit" button of the decal projector material's shader

  1. You should now be in the shader graph editor. From here, follow these steps:
  • Click the "+" on the blackboard, (1) on your left. If you do not have this window, activate it by clicking "Blackboard" in the top right corner. From this popup menu add a new "Color" attribute, and name it exactly Color (capitalization matters here!). This binds the variable to the Color field of your material.
  • Right-click anywhere and click "Create node". Add 1 Multiply node (2). image showing the shader graph editor, with numbers indicating where to click for each step
  1. Now that you have the multiply node and color input, arrange them like so:
  • Color input into Multiply (drag from Blackboard list).
  • Base Map Sample Texture 2D into Multiply.
  • Multiply into Base Color of the Fragment. image showing the setup described above
  1. Now save your shader by clicking "Save as..." in the top left and save it to wherever you like. Do NOT click "Save Asset", since that will override the default shader!

  2. Use the shader you just created, by going back to the inspector and selecting your shader in the dropdown. image showing where to click to select new shader

  3. Done! You can now tint your decal by changing the color of the material:

var decalProjector = GetComponent<DecalProjector>();
decalProjector.material.color = Color.red; // Whatever color you need

Since we used the Multiply node, the white parts of your decal will be brighter in color and the black parts will be darker in color. Transparent parts will still be transparent.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .