Search code examples
unity-game-engineshaderhlslshaderlab

How do I set a shader setting/property at runtime using MonoBehaviour?


I have a shader that displays a mesh's vertex colors and has the ability to clip vertices that are blue. I'd like the user to be able to turn this setting on/off while using the application.

I've tried the suggestions offered here Find and change property name in a shader and here How do I discard pixels based on vertex color and turn that on or off in a MonoBehaviour? but so far none of those have worked for me.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HoloToolkit.Unity;
using System;

public class AnchorScript : MonoBehaviour
{
private Renderer rend;
Vector3 scale;

public WorldAnchorManager worldAnchorManager;
// Start is called before the first frame update
void Start()
{
    rend = gameObject.GetComponent<Renderer>();
    // transform.localScale = scale;
    TurnOffContext();
}

private void Update()
{
    SaveScale();
    TurnOffContext();
}
public void AnchorIt()
{
    worldAnchorManager.AttachAnchor(this.gameObject);
    this.gameObject.GetComponent<Renderer>().material.color = Color.red;
}

public void ReleaseAnchor()
{
    worldAnchorManager.RemoveAnchor(this.gameObject);
    this.gameObject.GetComponent<Renderer>().material.color = 
Color.green;
}

public void ShowDifferences()
{
    gameObject.GetComponent<Renderer>().enabled = true; 
}

public void HideAugmentations()
{
    gameObject.GetComponent<Renderer>().enabled = false;
}
public void TurnOffContext()
{
    rend.material.SetFloat("_Toggle", 1);
    Debug.Log("Toggle ");
}

public void SaveScale()
{
    scale = gameObject.GetComponent<Transform>().localScale;
}
}

I expect this script to cause my mesh's blue parts to be discarded, because in my shader's fragment I have

clip(_Toggle * (0.5f - IN.vertColor.b)); 

Specifically the part that doesn't work is the line

rend.material.Setfloat("_Toggle", 1); 

The function is being called, but it's not setting the _Toggle value to 1 as expected.

If I manually change the _Toggle setting in the inspector panel from 0 to 1, the blue parts of the mesh are discarded, which is the expected result. The script I pasted above should have the same result as manually changing the setting in the inspector panel.


Solution

  • I don't know why your current solution doesn't work (it looks fine to me), but i know that you can work around this whole thing using shader variants.

    Inside your shader, add this line to the pragmas:

    #pragma multi_compile __ DISCARD_BLUE
    

    And then change your clip statement to this:

    #ifdef DISCARD_BLUE
    clip(0.5f - IN.vertColor.b);
    #endif
    

    To enable and disable this feature, just change the C# script to use rend.material.EnableKeyword("DISCARD_BLUE") and rend.material.DisableKeyword("DISCARD_BLUE") respectively. This has the added benefit that it saves a few instructions when the keyword is disabled. You can also enable/disable the keyword globally like this:

    Shader.Find("Custom/VertexColor").EnableKeyword("DISCARD_BLUE");
    

    Other than that, have you made absolutely sure that your script references the correct renderer?