unity-game-engineshaderhlslhololensshaderlab

How do I discard pixels based on vertex color and turn that on or off in a MonoBehaviour?


I've written a shader that uses a mesh's vertex colors and also has a function that clips all vertices that have an interpolated vertex color in the blue channel greater than 0.5 (discards all blue vertices).

I'm trying to create a voice command that allows the user to call the function when they are ready. However, in Microsoft's Mixed Reality Toolkit Speech Input Handler, it only allows me to call functions from components (Mesh Renderer, Mesh Filter, Mesh Collider, etc.) of the GameObject I'm referencing, not the shader or material of the object.

How can I make it so that a voice command can call my 'hide' function that I've shared below?

I've tried to code the 'hide' functionality outside of the shader but that didn't seem to work.

Shader "Custom/VertexColor" { // Where it will appear inside of the Shader Dropdown Menu of the Material / Name of the shader
Properties{
    _Toggle ("Toggle context", int) = 0
}
SubShader{
    Tags { "RenderType" = "Opaque" }
    LOD 200


    CGPROGRAM
    #pragma surface surf Lambert vertex:vert
    #pragma target 3.0
    #include "UnityCG.cginc"



    struct Input {
        float4 vertColor;
    };

    void vert(inout appdata_full v, out Input o) {
        UNITY_INITIALIZE_OUTPUT(Input, o);
        o.vertColor = v.color;
    }

    void surf(Input IN, inout SurfaceOutput o) {

        #include "UnityCG.cginc"
        int _Toggle = 0;
        o.Albedo = IN.vertColor.rgb;
        clip(_Toggle * (0.5f - IN.vertColor.b));

    }



    ENDCG
}
    FallBack "Diffuse"
}

I expected the Speech Input Handler to allow me to call functions from a shader but it does not.

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

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

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

private void Update()
{
    SaveScale();
}
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);
}

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

I put the TurnOffContext() function in the Start() function just to test to see if it works. In theory it should immediately set the _Toggle property to 1 which should discard all the blue pixels, but I still see the full original mesh upon starting my app. I also tried not putting it in the Start() function and just using my voice command which runs the function TurnOffContext(), but that also didn't work.

Here is a screenshot of my GameObject's material's inspector panel. https://i.sstatic.net/PlXqi.jpg


Solution

  • You have a redundant #include in your shader code, and you're declaring the _Toggle variable in the wrong place. Also, you shouldn't initialize int _Toggle, you only want to declare it so that unity can set its value.

    Get rid of the 2nd #include "UnityCG.cginc", get rid of the int _Toggle = 0; and put int _Toggle; (note: no initialization) somewhere below CGPROGRAM.

    Also, change the Properties block to use capital I Int:

    Shader "Custom/VertexColor" { // Where it will appear inside of the Shader Dropdown Menu of the Material / Name of the shader
    Properties{
        _Toggle ("Toggle context", Int) = 0
    }
    SubShader{
        Tags { "RenderType" = "Opaque" }
        LOD 200
    
    
        CGPROGRAM
        #pragma surface surf Lambert vertex:vert
        #pragma target 3.0
        #include "UnityCG.cginc"
    
        int _Toggle;
    
        struct Input {
            float4 vertColor;
        };
    
        void vert(inout appdata_full v, out Input o) {
            UNITY_INITIALIZE_OUTPUT(Input, o);
            o.vertColor = v.color;
        }
    
        void surf(Input IN, inout SurfaceOutput o) {
            o.Albedo = IN.vertColor.rgb;
            clip(_Toggle * (0.5f - IN.vertColor.b));
        }
    
        ENDCG
    }
        FallBack "Diffuse"
    }
    

    Then, in your c# code, you need to use SetInt instead of SetFloat because _Toggle is an int.

    Also, use renderer.sharedMaterial instead of renderer.material!