private void OpenConfiguration() { m_CurrentPanelView = PanelView.Configuration; if (m_MainCacheMaterials == null || m_CurrentMeshACIndex < 0 || m_CurrentMeshACIndex >= m_MainCacheMaterials.Count) { return; } Material mat = m_MainCacheMaterials[m_CurrentMeshACIndex]; Shader shader = mat.shader; if (ShaderMetaDataUtility.IsValidShader(shader)) { #pragma warning disable 0618 // Data conversion between Polybrush Beta and Polybrush 1.0. string path = ShaderMetaDataUtility.FindPolybrushMetaDataForShader(shader); if (!string.IsNullOrEmpty(path)) { ShaderMetaDataUtility.ConvertMetaDataToNewFormat(shader); } #pragma warning restore 0618 m_LoadedAttributes = ShaderMetaDataUtility.LoadShaderMetaData(shader); } }
// Called when the mouse begins hovering an editable object. internal override void OnBrushEnter(EditableObject target, BrushSettings settings) { base.OnBrushEnter(target, settings); if (target.editMesh == null) { return; } bool refresh = (m_CacheTarget != null && !m_CacheTarget.Equals(target)) || m_CacheTarget == null; if (m_CacheTarget != null && m_CacheTarget.Equals(target.gameObjectAttached)) { var targetMaterials = target.gameObjectAttached.GetMaterials(); refresh = !AreListsEqual(targetMaterials, m_CacheMaterials); } if (refresh) { m_CacheTarget = target; m_CacheMaterials = target.gameObjectAttached.GetMaterials(); m_MeshAttributesContainer = null; currentMeshACIndex = 0; ArrayUtility.Clear(ref m_AvailableMaterialsAsString); m_LikelySupportsTextureBlending = CheckForTextureBlendSupport(target.gameObjectAttached); RebuildCaches(target.editMesh); } if (m_LikelySupportsTextureBlending && (brushColor == null || !brushColor.MatchesAttributes(meshAttributes))) { brushColor = new SplatWeight(SplatWeight.GetChannelMap(meshAttributes)); SetBrushColorWithAttributeIndex(selectedAttributeIndex); } RebuildColorTargets(brushColor, settings.strength); }
private void ReloadJson() { editor = null; container = null; modified = false; AssetDatabase.Refresh(); }
/// <summary> /// Test a gameObject and it's mesh renderers for compatible shaders, and if one is found /// load it's attribute data into meshAttributes. /// </summary> /// <param name="go">The GameObject being checked for texture blend support</param> /// <returns></returns> internal bool CheckForTextureBlendSupport(GameObject go) { AttributeLayoutContainer detectedMeshAttributes; bool supports = false; var materials = Util.GetMaterials(go); m_MeshAttributesContainers.Clear(); Material mat; List <int> indexes = new List <int>(); for (int i = 0; i < materials.Count; i++) { mat = materials[i]; if (PolyShaderUtil.GetMeshAttributes(mat, out detectedMeshAttributes)) { m_MeshAttributesContainers.Add(detectedMeshAttributes); indexes.Add(i); supports = true; } } if (supports) { m_MeshAttributesContainer = m_MeshAttributesContainers.First(); foreach (int i in indexes) { ArrayUtility.Add <string>(ref m_AvailableMaterialsAsString, materials[i].name); } } return(supports); }
internal override void OnEnable() { base.OnEnable(); m_CurrentPanelView = PanelView.Paint; m_LikelySupportsTextureBlending = false; m_MeshAttributesContainer = null; brushColor = null; if (meshAttributes != null) { OnMaterialSelected(); } foreach (GameObject go in Selection.gameObjects) { m_LikelySupportsTextureBlending = CheckForTextureBlendSupport(go); if (m_LikelySupportsTextureBlending) { break; } } }
private void CloseConfiguration(bool saveOnDisk) { if (saveOnDisk) { Material mat = m_CacheMaterials[currentMeshACIndex]; Shader shader = mat.shader; ShaderMetaDataUtility.SaveShaderMetaData(shader, m_LoadedAttributes); foreach (GameObject go in Selection.gameObjects) { m_LikelySupportsTextureBlending = CheckForTextureBlendSupport(go); if (m_LikelySupportsTextureBlending) { break; } } if (m_CacheTarget != null) { RebuildCaches(m_CacheTarget.editMesh); } } m_LoadedAttributes = null; m_CurrentPanelView = PanelView.Paint; }
/// <summary> /// Store user-set shader attribute information. /// </summary> /// <param name="container">container that will have the shader and the metadata to write</param> /// <param name="overwrite">overwrite data if already existing</param> /// <param name="logErrors">log errors or not</param> /// <returns>Returns the path written to on success, null otherwise.</returns> internal static string SaveMeshAttributesData(AttributeLayoutContainer container, bool overwrite = false, bool logErrors = true) { if (container == null) { return(string.Empty); } return(SaveMeshAttributesData(container.shader, container.attributes, overwrite)); }
public static bool TryReadAttributeLayoutsFromJson(string jsonText, out AttributeLayoutContainer container) { container = ScriptableObject.CreateInstance <AttributeLayoutContainer>(); JsonUtility.FromJsonOverwrite(jsonText, container); ResolveShaderReference(container); return(true); }
public void LoadShaderMetaData_ValidShaderWithoutMeta_ReturnsAttributes() { Shader shaderWithMeta = Shader.Find(k_PathToShaderWithNoMeta); Assume.That(shaderWithMeta != null); AttributeLayoutContainer attributes = ShaderMetaDataUtility.LoadShaderMetaData(shaderWithMeta); Assert.IsNotNull(attributes); Assert.IsNull(attributes.attributes); }
void RebuildMaterialCaches() { ArrayUtility.Clear(ref m_AvailableMaterialsAsString); m_CurrentMeshACIndex = 0; m_MainCacheMaterials.Clear(); if (m_MainCacheTarget == null) { return; } m_MeshAttributesContainer = null; m_CurrentMeshACIndex = 0; m_LikelySupportsTextureBlending = CheckForTextureBlendSupport(m_MainCacheTarget.gameObjectAttached); }
void OnEnable() { if (target == null) { GameObject.DestroyImmediate(this); return; } AttributeLayoutContainer container = target as AttributeLayoutContainer; shader = container.shader; p_attributes = serializedObject.FindProperty("attributes"); }
/// <summary> /// Deserialize the shader's attributes from UserData in the shader's importer. /// If none exists, it returns a new AttributeLayoutContaine instance. /// </summary> /// <param name="shader"></param> /// <returns></returns> internal static AttributeLayoutContainer LoadShaderMetaData(Shader shader) { if (shader == null) { throw new ArgumentNullException("shader"); } string path = AssetDatabase.GetAssetPath(shader); AssetImporter importer = AssetImporter.GetAtPath(path); AttributeLayoutContainer data = AttributeLayoutContainer.Create(shader, null); JsonUtility.FromJsonOverwrite(importer.userData, data); return(data); }
/// <summary> /// Serialize the shader's attributes as UserData in the shader's importer. /// </summary> /// <param name="shader"></param> /// <param name="attributes"></param> internal static void SaveShaderMetaData(Shader shader, AttributeLayoutContainer attributes) { if (shader == null) { throw new ArgumentNullException("shader"); } if (attributes == null) { throw new ArgumentNullException("attributes"); } string path = AssetDatabase.GetAssetPath(shader); AssetImporter importer = AssetImporter.GetAtPath(path); importer.userData = JsonUtility.ToJson(attributes); importer.SaveAndReimport(); }
internal override void OnEnable() { base.OnEnable(); m_LikelySupportsTextureBlending = false; m_MeshAttributesContainer = null; brushColor = null; foreach (GameObject go in Selection.gameObjects) { m_LikelySupportsTextureBlending = CheckForTextureBlendSupport(go); if (m_LikelySupportsTextureBlending) { break; } } }
/// <summary> /// Test a gameObject and it's mesh renderers for compatible shaders, and if one is found /// load it's attribute data into meshAttributes. /// </summary> /// <param name="go">The GameObject being checked for texture blend support</param> /// <returns></returns> internal bool CheckForTextureBlendSupport(GameObject go) { bool supports = false; var materials = Util.GetMaterials(go); m_MeshAttributesContainers.Clear(); Material mat; List <int> indexes = new List <int>(); for (int i = 0; i < materials.Count; i++) { mat = materials[i]; if (ShaderMetaDataUtility.IsValidShader(mat.shader)) { AttributeLayoutContainer detectedMeshAttributes = ShaderMetaDataUtility.LoadShaderMetaData(mat.shader); { if (detectedMeshAttributes != null) { m_MeshAttributesContainers.Add(detectedMeshAttributes); indexes.Add(i); m_MainCacheMaterials.Add(mat); supports = true; } } } } if (supports) { m_MeshAttributesContainer = m_MeshAttributesContainers.First(); foreach (int i in indexes) { ArrayUtility.Add <string>(ref m_AvailableMaterialsAsString, materials[i].name); } } if (meshAttributes == null) { supports = false; } return(supports); }
private static void TestMeshAttributeContainer(AttributeLayoutContainer meshAttributes, Material mat) { Assert.IsNotNull(meshAttributes); Assert.IsTrue(meshAttributes.shader == mat.shader); //test textures preview and default values for (int i = 0; i < meshAttributes.attributes.Length; i++) { AttributeLayout attributeLayout = meshAttributes.attributes[i]; //preview Texture attributeTexture = mat.GetTexture(attributeLayout.propertyTarget); Assert.IsTrue(attributeTexture == attributeLayout.previewTexture); //default Assert.IsTrue(Enum.IsDefined(typeof(MeshChannel), attributeLayout.channel)); Assert.IsTrue(attributeLayout.min == 0); Assert.IsTrue(attributeLayout.max == 1); //if the index is part of the enum ComponentIndex Assert.IsTrue(Enum.IsDefined(typeof(ComponentIndex), attributeLayout.index)); } }
public void ConvertMetaDataToNewFormat_ArgumentValid_NoException() { if (!Directory.Exists(k_AssetShaderFolder)) { Directory.CreateDirectory(k_AssetShaderFolder); } // Setup environment for this specific tests. FileUtil.CopyFileOrDirectory(k_FilePathToShaderWithOldMetaFormat, k_DestFilePathToShaderWithOldMetaFormat); FileUtil.CopyFileOrDirectory(k_FilePathToShaderWithOldMetaFormatPBS, k_DestFilePathToShaderWithOldMetaFormatPBS); AssetDatabase.Refresh(); Shader shader = Shader.Find(k_PathToShaderWithOldMetaFormat); Assume.That(shader != null); #pragma warning disable 0618 // We should find a .pbs.json file for the shader. Assert.IsFalse(String.IsNullOrEmpty(ShaderMetaDataUtility.FindPolybrushMetaDataForShader(shader))); // Convert the data from .pbs.json to meta data. ShaderMetaDataUtility.ConvertMetaDataToNewFormat(shader); // After conversion, we shouldn't find a .pbs.json file for the shader. Assert.IsTrue(String.IsNullOrEmpty(ShaderMetaDataUtility.FindPolybrushMetaDataForShader(shader))); #pragma warning restore 0618 // Check tha AttributeLayoutContainer attributes = ShaderMetaDataUtility.LoadShaderMetaData(shader); Assert.IsNotNull(attributes); Assert.IsNotNull(attributes.attributes); // Clean up FileUtil.DeleteFileOrDirectory(k_DestFilePathToShaderWithOldMetaFormat); FileUtil.DeleteFileOrDirectory(k_DestFilePathToShaderWithOldMetaFormat + ".meta"); FileUtil.DeleteFileOrDirectory(k_DestFilePathToShaderWithOldMetaFormatPBS); FileUtil.DeleteFileOrDirectory(k_DestFilePathToShaderWithOldMetaFormatPBS + ".meta"); AssetDatabase.Refresh(); }
/// <summary> /// Try to read AttributeLayouts from a .pbs.json file located at "path" /// </summary> /// <param name="path">Path of the file to read from</param> /// <param name="container">AttributeLayoutContainer retrieved from the json</param> /// <returns>true if it worked, false if the file doesn't exist or is empty</returns> public static bool TryReadAttributeLayoutsFromJsonFile(string path, out AttributeLayoutContainer container) { container = null; if (!File.Exists(path)) { return(false); } string json = File.ReadAllText(path); if (string.IsNullOrEmpty(json)) { return(false); } container = ScriptableObject.CreateInstance <AttributeLayoutContainer>(); JsonUtility.FromJsonOverwrite(json, container); ResolveShaderReference(container); return(true); }
/// <summary> /// Loads AttributeLayout data from a shader. Checks for both legacy (define Z_TEXTURE_CHANNELS) and /// .pbs.json metadata. /// </summary> /// <param name="material"></param> /// <param name="attribContainer"></param> /// <returns></returns> internal static bool GetMeshAttributes(Material material, out AttributeLayoutContainer attribContainer) { attribContainer = null; if (material == null) { return(false); } // first search for json, then fall back on legacy if (ShaderMetaDataUtility.FindMeshAttributesForShader(material.shader, out attribContainer)) { Dictionary <string, int> shaderProperties = new Dictionary <string, int>(); for (int i = 0; i < ShaderUtil.GetPropertyCount(material.shader); i++) { shaderProperties.Add(ShaderUtil.GetPropertyName(material.shader, i), i); } foreach (AttributeLayout a in attribContainer.attributes) { int index = -1; if (shaderProperties.TryGetValue(a.propertyTarget, out index)) { if (ShaderUtil.GetPropertyType(material.shader, index) == ShaderUtil.ShaderPropertyType.TexEnv) { a.previewTexture = (Texture2D)material.GetTexture(a.propertyTarget); } } } return(true); } return(false); }
/// <summary> /// Searches only by looking for a compatibly named file in the same directory. /// </summary> /// <param name="shader">Shader associated with the metadata</param> /// <param name="attributes">result if any metadata found</param> /// <returns></returns> internal static bool FindMeshAttributesForShader(Shader shader, out AttributeLayoutContainer attributes) { attributes = null; string path = AssetDatabase.GetAssetPath(shader); string filename = Path.GetFileNameWithoutExtension(path); string directory = Path.GetDirectoryName(path); string[] paths = new string[] { string.Format("{0}/{1}.{2}", directory, filename, SHADER_ATTRIB_FILE_EXTENSION), string.Format("{0}/{1}.{2}", directory, PolyShaderUtil.GetMetaDataPath(shader), SHADER_ATTRIB_FILE_EXTENSION) }; foreach (string str in paths) { if (TryReadAttributeLayoutsFromJsonFile(str, out attributes)) { return(true); } } return(false); }
/// <summary> /// Store the shader's attributes in the new format. /// Erase the .pbs.json on success. /// </summary> internal static void ConvertMetaDataToNewFormat(Shader shader) { if (shader == null) { throw new NullReferenceException("shader"); } string path = ShaderMetaDataUtility.FindPolybrushMetaDataForShader(shader); // If not null, it means we have data stored with the old format. // Proceed to conversion. if (path != null) { AttributeLayoutContainer attributesContainer = ScriptableObject.CreateInstance <AttributeLayoutContainer>(); ShaderMetaDataUtility.TryReadAttributeLayoutsFromJsonFile(path, out attributesContainer); if (attributesContainer != null) { ShaderMetaDataUtility.SaveShaderMetaData(shader, attributesContainer); FileUtil.DeleteFileOrDirectory(path); FileUtil.DeleteFileOrDirectory(path + ".meta"); AssetDatabase.Refresh(); } } }
// Inspector GUI shown in the Editor window. Base class shows BrushSettings by default internal override void DrawGUI(BrushSettings brushSettings) { base.DrawGUI(brushSettings); using (new GUILayout.HorizontalScope()) { GUILayout.FlexibleSpace(); paintMode = (PaintMode)GUILayout.Toolbar((int)paintMode, m_ModeIcons, GUILayout.Width(130)); GUILayout.FlexibleSpace(); } GUILayout.Space(4); if (!m_LikelySupportsTextureBlending) { EditorGUILayout.HelpBox("It doesn't look like any of the materials on this object support texture blending!\n\nSee the readme for information on creating custom texture blend shaders.", MessageType.Warning); } // Selection dropdown for material (for submeshes) if (m_AvailableMaterialsAsString.Count() > 0) { EditorGUILayout.BeginHorizontal(); EditorGUI.BeginChangeCheck(); EditorGUILayout.LabelField("Material :", GUILayout.Width(60)); currentMeshACIndex = EditorGUILayout.Popup(currentMeshACIndex, m_AvailableMaterialsAsString, "Popup"); if (EditorGUI.EndChangeCheck()) { m_MeshAttributesContainer = m_MeshAttributesContainers[currentMeshACIndex]; } EditorGUILayout.EndHorizontal(); } GUILayout.Space(4); if (meshAttributes != null) { RefreshPreviewTextureCache(); int prevSelectedAttributeIndex = m_SelectedAttributeIndex; m_SelectedAttributeIndex = SplatWeightEditor.OnInspectorGUI(m_SelectedAttributeIndex, ref brushColor, meshAttributes); if (prevSelectedAttributeIndex != m_SelectedAttributeIndex) { SetBrushColorWithAttributeIndex(m_SelectedAttributeIndex); } #if POLYBRUSH_DEBUG GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("MetaData", EditorStyles.miniButton)) { Debug.Log(meshAttributes.ToString("\n")); string str = EditorUtility.FindPolybrushMetaDataForShader(meshAttributesContainer.shader); if (!string.IsNullOrEmpty(str)) { TextAsset asset = AssetDatabase.LoadAssetAtPath <TextAsset>(str); if (asset != null) { EditorGUIUtility.PingObject(asset); } else { Debug.LogWarning("No MetaData found for Shader \"" + meshAttributesContainer.shader.name + "\""); } } else { Debug.LogWarning("No MetaData found for Shader \"" + meshAttributesContainer.shader.name + "\""); } } GUILayout.EndHorizontal(); GUILayout.Space(4); if (GUILayout.Button("rebuild targets")) { RebuildColorTargets(brushColor, brushSettings.strength); } GUILayout.Label(brushColor != null ? brushColor.ToString() : "brush color: null\n"); #endif } }
// Inspector GUI shown in the Editor window. Base class shows BrushSettings by default internal override void DrawGUI(BrushSettings brushSettings) { base.DrawGUI(brushSettings); using (new GUILayout.HorizontalScope()) { GUILayout.FlexibleSpace(); paintMode = (PaintMode)GUILayout.Toolbar((int)paintMode, Styles.k_ModeIcons, GUILayout.Width(150)); GUILayout.FlexibleSpace(); } GUILayout.Space(4); // Selection dropdown for material (for submeshes) if (m_AvailableMaterialsAsString.Count() > 0) { EditorGUILayout.BeginHorizontal(); EditorGUI.BeginChangeCheck(); EditorGUILayout.LabelField("Material :", GUILayout.Width(60)); if (m_CurrentPanelView == PanelView.Configuration) { GUI.enabled = false; } currentMeshACIndex = EditorGUILayout.Popup(currentMeshACIndex, m_AvailableMaterialsAsString, "Popup"); if (m_CurrentPanelView == PanelView.Configuration) { GUI.enabled = true; } // Buttons to switch between Paint and Configuration views if (m_CurrentPanelView == PanelView.Paint && GUILayout.Button("Configure", GUILayout.Width(70))) { OpenConfiguration(); } else if (m_CurrentPanelView == PanelView.Configuration) { if (GUILayout.Button("Revert", GUILayout.Width(70))) { CloseConfiguration(false); } if (GUILayout.Button("Save", GUILayout.Width(70))) { CloseConfiguration(true); } } if (EditorGUI.EndChangeCheck()) { m_MeshAttributesContainer = m_MeshAttributesContainers[currentMeshACIndex]; OnMaterialSelected(); } EditorGUILayout.EndHorizontal(); } EditorGUILayout.Space(); if (m_CurrentPanelView == PanelView.Paint) { DrawGUIPaintView(); } else if (m_CurrentPanelView == PanelView.Configuration) { Material selectedMat = m_CacheMaterials[currentMeshACIndex]; string[] names = selectedMat.GetTexturePropertyNames(); using (new GUILayout.VerticalScope()) { for (int i = 0; i < names.Length; ++i) { string n = names[i]; if (selectedMat.HasProperty(n)) { DrawConfigurationPanel(GetPropertyInfo(n), n, selectedMat); } } } } }
static void ResolveShaderReference(AttributeLayoutContainer container) { container.shader = Shader.Find(container.shaderPath); }
/// <summary> /// Saves the metadata of the shader passed in parameters, can overwrite if necessary /// </summary> /// <param name="shader">Shader associated with the metadata</param> /// <param name="attributes">Metadata to write</param> /// <param name="overwrite">Will overwrite if already existing file</param> /// <param name="logErrors">Log errors or not</param> /// <returns></returns> internal static string SaveMeshAttributesData(Shader shader, AttributeLayout[] attributes, bool overwrite = false, bool logErrors = true) { if (shader == null || attributes == null) { if (logErrors) { Debug.LogError("Cannot save null attributes for shader."); } return(null); } string path = FindPolybrushMetaDataForShader(shader); string shader_path = AssetDatabase.GetAssetPath(shader); string shader_directory = Path.GetDirectoryName(shader_path); string shader_filename = Path.GetFileNameWithoutExtension(path); // metadata didn't exist before if (string.IsNullOrEmpty(path)) { if (string.IsNullOrEmpty(shader_path)) { // how!? path = EditorUtility.SaveFilePanelInProject( "Save Polybrush Shader Attributes", shader_filename, SHADER_ATTRIB_FILE_EXTENSION, "Please enter a file name to save Polybrush shader metadata to."); if (string.IsNullOrEmpty(path)) { Debug.LogWarning(string.Format("Could not save Polybrush shader metadata. Please try again, possibly with a different file name or folder path.")); return(null); } } else { shader_filename = Path.GetFileNameWithoutExtension(shader_path); path = string.Format("{0}/{1}.{2}", shader_directory, shader_filename, SHADER_ATTRIB_FILE_EXTENSION); } } if (!overwrite && File.Exists(path)) { // @todo Debug.LogWarning("shader metadata exists. calling function refuses to overwrite and lazy developer didn't add a save dialog here."); return(null); } try { AttributeLayoutContainer container = AttributeLayoutContainer.Create(shader, attributes); string json = JsonUtility.ToJson(container, true); File.WriteAllText(path, json); //note: convert it here to be able to load it using AssetDatabase functions shader_filename = Path.GetFileNameWithoutExtension(shader_path); path = string.Format("{0}/{1}.{2}", shader_directory, shader_filename, SHADER_ATTRIB_FILE_EXTENSION); //------- return(path); } catch (System.Exception e) { if (logErrors) { Debug.LogError("Failed saving Polybrush Shader MetaData\n" + e.ToString()); } return(path); } }