public override void OnInspectorGUI() { Init(); if (!isVisible) { return; } SetDefaultGUIWidths(); Material material = target as Material; int layerCount = MaxLayerCount; while (layerCount > 0 && !material.IsKeywordEnabled(GetPropertyName(LayerKeywordPrefix, layerCount))) { --layerCount; } if (layerCount == 0) { layerCount = 1; material.EnableKeyword("LAYERS_" + layerCount); } EditorGUILayout.LabelField("Global material properties"); EditorGUILayout.BeginVertical(EditorStyles.helpBox); TextureField("AlphaMask", material, AlphaMaskUniform); AvatarMaterialEditorGUILayout.ColorField("DarkMultiplier", material, DarkMultUniform); AvatarMaterialEditorGUILayout.ColorField("BaseColor", material, BaseColorUniform); bool normalMapEnabled = AvatarMaterialEditorGUILayout.KeywordToggle("Normal map enabled", material, NormalMapPrefix); if (normalMapEnabled) { TextureField("Normal map", material, NormalMapUniform); } bool parallaxEnabled = AvatarMaterialEditorGUILayout.KeywordToggle("Parallax enabled", material, ParallaxPrefix); if (parallaxEnabled) { TextureField("Parallax map", material, ParallaxMapUniform); } bool roughnessEnabled = AvatarMaterialEditorGUILayout.KeywordToggle("Roughness enabled", material, RoughnessPrefix); if (roughnessEnabled) { TextureField("Roughness map", material, RoughnessMapUniform); } MaskField("Base mask type", material, BaseMaskTypeUniform, BaseMaskParametersUniform, BaseMaskAxisUniform, baseMaskAxisCache, baseMaskParametersCache, normalMapEnabled); EditorGUILayout.EndVertical(); int layerVisibilityMask = 0; layerVisibilityMasks.TryGetValue(material, out layerVisibilityMask); EditorGUILayout.LabelField("Layers"); EditorGUI.indentLevel++; EditorGUILayout.BeginVertical(EditorStyles.helpBox); int?removeLayerIndex = null; int?swapSource = null; int?swapTarget = null; for (int i = 0; i < layerCount; ++i) { // Draw the preview material if (previewMaterials[i] == null) { previewMaterials[i] = CreatePreviewMaterial(material, i); } const int previewSize = 64; const int buttonSize = 20; Rect layerHeaderRect = GUILayoutUtility.GetRect(previewSize, previewSize, GUILayout.ExpandWidth(true)); // Draw the preview texture previewUtility.m_Camera.transform.position = Vector3.forward * 5.0f; previewUtility.m_Camera.transform.rotation = Quaternion.identity; previewUtility.m_Camera.transform.LookAt(Vector3.zero); previewUtility.BeginStaticPreview(new Rect(0, 0, previewSize, previewSize)); previewUtility.DrawMesh(previewMesh, Vector3.zero, Quaternion.identity, previewMaterials[i], 0); previewUtility.m_Camera.Render(); Texture preview = previewUtility.EndStaticPreview(); GUI.Label(new Rect(layerHeaderRect.xMax - previewSize - buttonSize, layerHeaderRect.y, previewSize, previewSize), preview); float yButton = layerHeaderRect.y; EditorGUI.BeginDisabledGroup(layerCount <= 1); if (GUI.Button(new Rect(layerHeaderRect.xMax - buttonSize, yButton, buttonSize, buttonSize), new GUIContent("X", "Remove layer"))) { removeLayerIndex = i; } yButton += buttonSize + 4; EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup(i == 0); if (GUI.Button(new Rect(layerHeaderRect.xMax - buttonSize, yButton, buttonSize, buttonSize), new GUIContent("^", "Move layer up"))) { swapSource = i; swapTarget = i - 1; } yButton += buttonSize; EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup(i == layerCount - 1); if (GUI.Button(new Rect(layerHeaderRect.xMax - buttonSize, yButton, buttonSize, buttonSize), new GUIContent("v", "Move layer down"))) { swapSource = i; swapTarget = i + 1; } yButton += buttonSize; EditorGUI.EndDisabledGroup(); // Create a toggleable group for the layer int layerMaskBit = 1 << i; bool layerVisible = (layerVisibilityMask & layerMaskBit) != 0; layerVisible = EditorGUI.Foldout(layerHeaderRect, layerVisible, string.Format("Layer {0}", i + 1)); if (layerVisible) { layerVisibilityMask |= layerMaskBit; } else { layerVisibilityMask &= ~layerMaskBit; } if (layerVisible) { EditorGUILayout.BeginVertical(EditorStyles.helpBox); EditorGUI.BeginChangeCheck(); { // Handle the blend mode AvatarMaterialEditorGUILayout.IntField("Blend mode", material, GetPropertyName(LayerBlendModePrefix, i), layerBlendModeLabels); // Handle the sample mode selector string layerSampleParametersProperty = GetPropertyName(LayerSampleParametersPrefix, i); EditorGUI.BeginChangeCheck(); LayerSampleMode sampleMode = (LayerSampleMode)AvatarMaterialEditorGUILayout.IntField("Sample mode", material, GetPropertyName(LayerSampleModePrefix, i), layerSampleModeLabels); if (EditorGUI.EndChangeCheck()) { material.SetVector(layerSampleParametersProperty, sampleParametersCache[i, (int)sampleMode]); } // Show the mode-specific sample controls EditorGUI.BeginChangeCheck(); AvatarMaterialEditorGUILayout.ColorField("Surface color", material, GetPropertyName(LayerColorPrefix, i)); switch (sampleMode) { case LayerSampleMode.Texture: TextureField("Surface texture", material, GetPropertyName(LayerSurfacePrefix, i)); AvatarMaterialEditorGUILayout.Vector2Field("Panning speed", material, layerSampleParametersProperty); break; case LayerSampleMode.TextureSingleChannel: TextureField("Surface texture", material, GetPropertyName(LayerSurfacePrefix, i)); AvatarMaterialEditorGUILayout.ChannelMaskField("Channel", material, layerSampleParametersProperty); break; case LayerSampleMode.Parallax: TextureField("Surface texture", material, GetPropertyName(LayerSurfacePrefix, i)); AvatarMaterialEditorGUILayout.VectorComponentField("Parallax min height", material, layerSampleParametersProperty, 0); AvatarMaterialEditorGUILayout.VectorComponentField("Parallax max height", material, layerSampleParametersProperty, 1); break; case LayerSampleMode.RSRM: TextureField("RSRM texture", material, GetPropertyName(LayerSurfacePrefix, i)); if (roughnessEnabled) { AvatarMaterialEditorGUILayout.VectorComponentField("Roughness min", material, layerSampleParametersProperty, 0); AvatarMaterialEditorGUILayout.VectorComponentField("Roughness max", material, layerSampleParametersProperty, 1); } else { AvatarMaterialEditorGUILayout.VectorComponentField("Roughness", material, layerSampleParametersProperty, 0); } if (normalMapEnabled) { AvatarMaterialEditorGUILayout.VectorComponentField("Normal map strength", material, layerSampleParametersProperty, 2); } break; } if (EditorGUI.EndChangeCheck()) { sampleParametersCache[i, (int)sampleMode] = material.GetVector(layerSampleParametersProperty); } // Handle the mask mode selector string maskParametersName = GetPropertyName(LayerMaskParametersPrefix, i); string maskAxisName = GetPropertyName(LayerMaskAxisPrefix, i); MaskField("Mask Type", material, GetPropertyName(LayerMaskTypePrefix, i), maskParametersName, maskAxisName, maskAxisCache[i], maskParametersCache[i], normalMapEnabled); } if (EditorGUI.EndChangeCheck()) { previewMaterials[i] = null; } EditorGUILayout.EndVertical(); } } layerVisibilityMasks[material] = layerVisibilityMask; if (layerCount < MaxLayerCount) { if (GUILayout.Button("Add layer")) { Undo.RecordObject(material, "Add layer"); SetLayerCount(material, layerCount + 1); removeLayerIndex = null; } } if (removeLayerIndex.HasValue) { Undo.RecordObject(material, "Remove layer"); for (int i = removeLayerIndex.Value; i < layerCount - 1; ++i) { CopyAttributes(material, i + 1, i); } SetLayerCount(material, layerCount - 1); } if (swapSource.HasValue && swapTarget.HasValue) { Undo.RecordObject(material, string.Format("Swap layers {1} and {0}", swapSource.Value, swapTarget.Value)); SwapAttributes(material, swapSource.Value, swapTarget.Value); } EditorGUI.indentLevel--; EditorGUILayout.EndVertical(); EditorUtility.SetDirty(target); }