How can I expose 'Surface Type' in shader graph

Hi

The Universal Render Pipeline/Lit shader has a ‘Surface Type’ property for making something transparent/opaque. In shader graph, it only seems possible to set this directly on the PBR master node.

Is it possible to add this to the blackboard somehow to expose it?

1 Like

You can set this via .SetInt(“_SurfaceType”, …) without manual exposing per material. Note that you also have to set the render queue accordingly.

Transparent:
.SetInt(“_SurfaceType”, 1);
.SetInt(“_RenderQueueType”, 4);

Opaque:
.SetInt(“_SurfaceType”, 0);
.SetInt(“_RenderQueueType”, 1);

Edit: I don’t remember how I figured out which are the right numbers. Maybe debugging…

1 Like

Thank you this worked perfectly!

I just discovered that in my case A LOT more shader flags have to be set and that only the transparent → opaque conversion worked with the subset of flags shared earlier.

Transparent:

transparentMat.EnableKeyword("_BLENDMODE_ALPHA");
transparentMat.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
transparentMat.EnableKeyword("_ENABLE_FOG_ON_TRANSPARENT");
transparentMat.DisableKeyword("_BLENDMODE_ADD");
transparentMat.DisableKeyword("_BLENDMODE_PRE_MULTIPLY");

transparentMat.SetFloat("_SurfaceType", (int)SurfaceType.Transparent);
transparentMat.SetFloat("_RenderQueueType", 5);
transparentMat.SetFloat("_BlendMode", 0);
transparentMat.SetFloat("_AlphaCutoffEnable", 0);
transparentMat.SetFloat("_SrcBlend", 1f);
transparentMat.SetFloat("_DstBlend", 10f);
transparentMat.SetFloat("_AlphaSrcBlend", 1f);
transparentMat.SetFloat("_AlphaDstBlend", 10f);
transparentMat.SetFloat("_ZTestDepthEqualForOpaque", 4f);

transparentMat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;

Opaque:

opaqueMat.SetInt("_SurfaceType"_STRING, (int)SurfaceType.Opaque);
opaqueMat.SetInt("_RenderQueueType", (int)1);
opaqueMat.SetFloat("_AlphaDstBlend", 0f);
opaqueMat.SetFloat("_DstBlend", 0f);
opaqueMat.SetFloat("_ZTestDepthEqualForOpaque", 3f);
opaqueMat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry;
4 Likes
void ViewObstructed()
    {
        RaycastHit hit;
        if(Physics.Raycast(transform.position, target.position - transform.position, out hit))
            if(hit.collider.gameObject.name != HitObj)
            {
                Obstruction.gameObject.GetComponent<MeshRenderer>().material.SetInt("_SurfaceType", 0);
                Obstruction.gameObject.GetComponent<MeshRenderer>().material.SetFloat("Vector1_2B798094", 1f);
            }

            if(hit.collider.gameObject.tag != "Player")
            {
                Obstruction = hit.transform;
                Obstruction.gameObject.GetComponent<MeshRenderer>().material.SetInt("_SurfaceType", 1);
                Obstruction.gameObject.GetComponent<MeshRenderer>().material.SetFloat("Vector1_2B798094", 0.3f);
                HitObj = hit.collider.gameObject.name;
            }
            else
            {
                Obstruction.gameObject.GetComponent<MeshRenderer>().material.SetInt("_SurfaceType", 0);
                Obstruction.gameObject.GetComponent<MeshRenderer>().material.SetFloat("Vector1_2B798094", 1f);
            }
        }
    }

Obstruction.gameObject.GetComponent().material.SetInt(“_SurfaceType”, 0);
it’s for Opaque surface of PBR Master.

Obstruction.gameObject.GetComponent().material.SetInt(“_SurfaceType”, 1);
it’s for Transparent surface of PBR Master.

but i dont know it doesnt work… please help me…

1 Like

ohh, of course i also add it too…
Obstruction.gameObject.GetComponent().material…SetInt(“_RenderQueueType”, 4);
Obstruction.gameObject.GetComponent().material…SetInt(“_RenderQueueType”, 1);

1 Like

Ah Excellent thanks @youngjinna97 !

this didn’t work for me at all

these do get changed but they have no effect

I must be missing something. Sorry for my n00bness, but you’re all talking about code where the Shader graph is, well, a graph tool for shaders. What am I missing? where do you implement the code you all talk about?

1 Like

I don’t when this might have changed, but I tried this in Unity 2021 and there was no such value as _SurfaceType, but if you change it to _Surface then it works.

I missed this at first too. He’s saying instead of setting this in ShaderGraph as a variable, you don’t need to do this, because ALL URP materials have these variables dynamically defined.

i.e., why would we want a variable? So we can change it in C#, right? Well, we can change it in C# without declaring a variable.

I made a new solution for this problem for a custom shader graph built on lit.

What I’ve done to solve the problem, which feels a bit more reliable to me, is just to make two shaders (one transparent, one opaque), then, when I need to toggle at runtime (or from within the materials editor) I just do material.shader = Shader.Find("Transparent_counterpart")

All of the prop values get transferred seamlessly, and, presumably, this will work across versions. I think it should be the recommended method, even though it creates some duplicate code/graph.