I feel like I’m missing some fundamental understanding of how Material Property Drawers and the Serialization of their information works.
No matter how long I scroll through documentation, where the information lives and how to make it flow from one thing to another, just never seems to click. So just to double check my rapidly decreasing sanity…
Let’s say I have a Shader, it’s assigned to my Main Material…
- I want to make a Material Property Drawer that displays the Color from another Referenced Material.
- I want to close out Unity, and come back in, and none of these References have been forgotten
- I want to use this Material Property Drawer multiple times in a Shader, Referencing different Materials
The below can get me part of the way there, but as soon as I reload in any way the Referenced Materials are lost. I understand to some abstract degree Serialization is involved here, but for the life of me I can’t seem to wrap my head around it.
Which of all the things that say Serialization in Unity documentation is it, and why does [SerializedField] not work? Where does the information live? Does the Serialized information from two different instances of the drawer live in two different places? How can a single drawer go find information if it lives in two different places? What the implications of this across multiple instances of the Shader?
Any direction you kind folks could give me would be greatly appreciated.
Material Property Drawer:
using UnityEngine;
using System.Collections;
using UnityEditor;
public class MatPropertyDrawer : MaterialPropertyDrawer
{
public Material refMat;
public override void OnGUI(Rect position, MaterialProperty prop, string label, MaterialEditor editor)
{
//assign the Reference Material just once in an event-like way. This is pressing a button when you have a Material in the Resources folder selected
//(Need to lock Inspector on Main Material to use properly).
if (GUILayout.Button("Reference Material"))
{
Debug.Log("Referenced Material has been assigned...");
foreach (Object o in Selection.objects)
{
if (o.GetType() == typeof(Material))
{
refMat = Resources.Load<Material>(o.name);
}
}
}
//Check if null to emphasize when I lose it and avoid any null reference exceptions...
if (refMat == null)
{
Debug.Log("Referenced Material is lost..");
}
//Display Color from referenced Material
else
{
Color matColor = refMat.color;
EditorGUI.ColorField(position, refMat.color);
}
}
}
Shader:
Shader "URPUnlitShaderBasic"
{
// The properties block of the Unity shader. In this example this block is empty
// because the output color is predefined in the fragment shader code.
Properties
{
[MatPropertyDrawer]
_MainTex ("Texture", 2D) = "white" {}
[MatPropertyDrawer]
_MainTex2 ("Texture", 2D) = "white" {}
}
// The SubShader block containing the Shader code.
SubShader
{
// SubShader Tags define when and under which conditions a SubShader block or
// a pass is executed.
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalRenderPipeline" }
Pass
{
// The HLSL code block. Unity SRP uses the HLSL language.
HLSLPROGRAM
// This line defines the name of the vertex shader.
#pragma vertex vert
// This line defines the name of the fragment shader.
#pragma fragment frag
// The Core.hlsl file contains definitions of frequently used HLSL
// macros and functions, and also contains #include references to other
// HLSL files (for example, Common.hlsl, SpaceTransforms.hlsl, etc.).
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
// The structure definition defines which variables it contains.
// This example uses the Attributes structure as an input structure in
// the vertex shader.
struct Attributes
{
// The positionOS variable contains the vertex positions in object
// space.
float4 positionOS : POSITION;
};
struct Varyings
{
// The positions in this struct must have the SV_POSITION semantic.
float4 positionHCS : SV_POSITION;
};
// The vertex shader definition with properties defined in the Varyings
// structure. The type of the vert function must match the type (struct)
// that it returns.
Varyings vert(Attributes IN)
{
// Declaring the output object (OUT) with the Varyings struct.
Varyings OUT;
// The TransformObjectToHClip function transforms vertex positions
// from object space to homogenous space
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
// Returning the output.
return OUT;
}
// The fragment shader definition.
half4 frag() : SV_Target
{
// Defining the color variable and returning it.
half4 customColor;
customColor = half4(0.5, 0, 0, 1);
return customColor;
}
ENDHLSL
}
}
}