From 9acd73e65d959b22339f68720830ea7580398909 Mon Sep 17 00:00:00 2001 From: Victor Soupday <79094830+soupday@users.noreply.github.com> Date: Mon, 28 Nov 2022 18:00:56 +0000 Subject: [PATCH 01/10] 1.4.1 - hide hair bake when enable color not enabled in any hair materials. --- Editor/CharacterInfo.cs | 22 ++++++++++++++++++++-- Editor/ImporterWindow.cs | 10 ++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Editor/CharacterInfo.cs b/Editor/CharacterInfo.cs index 371e4f7..ff1a0ff 100644 --- a/Editor/CharacterInfo.cs +++ b/Editor/CharacterInfo.cs @@ -51,7 +51,8 @@ public enum RigOverride { None = 0, Generic, Humanoid } public RigOverride UnknownRigType { get; set; } private bool bakeCustomShaders = true; private bool bakeSeparatePrefab = true; - private bool useTessellation = false; + private bool useTessellation = false; + private GameObject prefabAsset; public ProcessingType BuildType { get { return logType; } set { logType = value; } } public MaterialQuality BuildQuality @@ -184,7 +185,8 @@ public GameObject PrefabAsset { get { - return Util.FindCharacterPrefabAsset(Fbx); + if (!prefabAsset) prefabAsset = Util.FindCharacterPrefabAsset(Fbx); + return prefabAsset; } } @@ -293,6 +295,22 @@ public BaseGeneration Generation } } + public bool HasColorEnabledHair() + { + Renderer[] renderers = PrefabAsset.GetComponentsInChildren(); + foreach (Renderer r in renderers) + { + foreach (Material m in r.sharedMaterials) + { + if (m.HasProperty("BOOLEAN_ENABLECOLOR")) + { + if (m.GetFloat("BOOLEAN_ENABLECOLOR") > 0f) return true; + } + } + } + return false; + } + public void CheckGeneration() { BaseGeneration oldGen = generation; diff --git a/Editor/ImporterWindow.cs b/Editor/ImporterWindow.cs index 5a20205..8b879fc 100644 --- a/Editor/ImporterWindow.cs +++ b/Editor/ImporterWindow.cs @@ -753,18 +753,20 @@ private void OnGUIActionArea(Rect actionBlock) GUILayout.Space(ACTION_BUTTON_SPACE); - if (contextCharacter.BuiltBasicMaterials) GUI.enabled = false; + if (contextCharacter.tempHairBake) { - if (GUILayout.Button(new GUIContent(iconActionBakeHairOn, "Restore Hair materials."), + if (GUILayout.Button(new GUIContent(iconActionBakeHairOn, "Restore original hair materials."), GUILayout.Width(ACTION_BUTTON_SIZE), GUILayout.Height(ACTION_BUTTON_SIZE))) { restoreHairAfterGUI = true; } } - else + else if (!contextCharacter.BuiltBasicMaterials && contextCharacter.HasColorEnabledHair()) { - if (GUILayout.Button(new GUIContent(iconActionBakeHair, "Bake hair materials."), + //if (contextCharacter.BuiltBasicMaterials || !contextCharacter.HasColorEnabledHair()) GUI.enabled = false; + + if (GUILayout.Button(new GUIContent(iconActionBakeHair, "Bake hair materials, to preview the baked results of the 'Enable Color' in the hair materials."), GUILayout.Width(ACTION_BUTTON_SIZE), GUILayout.Height(ACTION_BUTTON_SIZE))) { bakeHairAfterGUI = true; From 5fd11f2631b8999adb276e87fcbb31d7e83e366e Mon Sep 17 00:00:00 2001 From: Victor Soupday <79094830+soupday@users.noreply.github.com> Date: Tue, 29 Nov 2022 17:06:25 +0000 Subject: [PATCH 02/10] 1.4.1 Remember lighting preset. --- Editor/PreviewScene.cs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Editor/PreviewScene.cs b/Editor/PreviewScene.cs index 71d504e..485205f 100644 --- a/Editor/PreviewScene.cs +++ b/Editor/PreviewScene.cs @@ -97,7 +97,43 @@ public static void CycleLighting() active++; if (active >= lightingContainers.Count) active = 0; + lightingContainers[active].SetActive(true); + + EditorPrefs.SetString("RL_Lighting_Preset", lightingContainers[active].name); + } + } + + public static void RestoreLighting() + { + if (EditorPrefs.HasKey("RL_Lighting_Preset")) + { + string presetName = EditorPrefs.GetString("RL_Lighting_Preset"); + + PreviewScene ps = WindowManager.GetPreviewScene(); + + List lightingContainers = new List(); + Util.FindSceneObjects(ps.lighting, "LightingConfig", lightingContainers); + + bool found = false; + for (int i = 0; i < lightingContainers.Count; i++) + { + if (lightingContainers[i].name == presetName) + { + lightingContainers[i].SetActive(true); + found = true; + } + else + { + lightingContainers[i].SetActive(false); + } + } + + if (!found) + { + lightingContainers[0].SetActive(true); + EditorPrefs.SetString("RL_Lighting_Preset", lightingContainers[0].name); + } } } @@ -235,6 +271,8 @@ public void PostProcessingAndLighting() ppv.isGlobal = true; ppv.profile = volume; #endif + + RestoreLighting(); } } } From bd673b7cb86d9f8f59891ca5ec119cbb8b0df30a Mon Sep 17 00:00:00 2001 From: Victor Soupday <79094830+soupday@users.noreply.github.com> Date: Tue, 29 Nov 2022 19:07:37 +0000 Subject: [PATCH 03/10] 1.4.1 - --- Editor/CharacterInfo.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Editor/CharacterInfo.cs b/Editor/CharacterInfo.cs index ff1a0ff..6537558 100644 --- a/Editor/CharacterInfo.cs +++ b/Editor/CharacterInfo.cs @@ -297,14 +297,17 @@ public BaseGeneration Generation public bool HasColorEnabledHair() { - Renderer[] renderers = PrefabAsset.GetComponentsInChildren(); - foreach (Renderer r in renderers) + if (PrefabAsset) { - foreach (Material m in r.sharedMaterials) + Renderer[] renderers = PrefabAsset.GetComponentsInChildren(); + foreach (Renderer r in renderers) { - if (m.HasProperty("BOOLEAN_ENABLECOLOR")) + foreach (Material m in r.sharedMaterials) { - if (m.GetFloat("BOOLEAN_ENABLECOLOR") > 0f) return true; + if (m.HasProperty("BOOLEAN_ENABLECOLOR")) + { + if (m.GetFloat("BOOLEAN_ENABLECOLOR") > 0f) return true; + } } } } From 9587d4c0fc0254df9df0357289c2b4cdcf939d9f Mon Sep 17 00:00:00 2001 From: soupday <79094830+soupday@users.noreply.github.com> Date: Thu, 1 Dec 2022 04:05:26 +0000 Subject: [PATCH 04/10] 1.4.1 Tra specular and scalp fixes. --- CHANGELOG.md | 8 + Editor/Importer.cs | 19 +- Editor/ImporterMenu.cs | 9 +- Editor/ImporterWindow.cs | 585 ++++++++++++++++++++++++++--------- Editor/LodSelectionWindow.cs | 19 +- Editor/MeshUtil.cs | 26 +- Editor/Pipeline.cs | 74 +++-- Editor/Util.cs | 29 +- package.json | 2 +- 9 files changed, 572 insertions(+), 199 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50bee02..41d9564 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ Changelog ========= +### v 1.4.1 +- Traditional material glossiness fix. +- High poly (sub-division) hair mesh extraction fix. +- SSS Diffusion profile added. +- Remembers last used lighting preset on character preview change. +- Character icon list side bar can be dragged into a more compact list view. + - Character list sorted alphabetically. + ### v 1.4.0 - Import & Setup - ActorBuild detection separated from ActorCore (ActorBuild can have more advanced materials) diff --git a/Editor/Importer.cs b/Editor/Importer.cs index f82d23c..166dd35 100644 --- a/Editor/Importer.cs +++ b/Editor/Importer.cs @@ -375,7 +375,7 @@ private void ProcessObjectBuildPass(Renderer renderer) QuickJSON matJson = GetMatJson(obj, sourceName); // determine the material type, this dictates the shader and template material. - MaterialType materialType = GetMaterialType(obj, sharedMat, sourceName, matJson); + MaterialType materialType = GetMaterialType(obj, sharedMat, sourceName, matJson); Util.LogInfo(" Material name: " + sourceName + ", type:" + materialType.ToString()); @@ -897,7 +897,9 @@ private void ConnectDefaultMaterial(GameObject obj, string sourceName, Material else { Shader specShader = Shader.Find("Standard (Specular setup)"); + int renderQueue = mat.renderQueue; mat.shader = specShader; + mat.renderQueue = renderQueue; } } @@ -1178,10 +1180,17 @@ private void ConnectDefaultMaterial(GameObject obj, string sourceName, Material if (jsonMaterialType.iEquals("Tra")) { - mat.SetFloatIf("_Smoothness", 0.5f); - mat.SetFloatIf("_GlossMapScale", 0.5f); - mat.SetFloatIf("_Glossiness", 0.5f); - mat.SetMinMaxRange("_SmoothnessRemap", 0f, 0.5f); + float glossiness = 0.5f; + float specular = 1f; + Color specularColor = Color.white; + if (matJson != null && matJson.PathExists("Glossiness")) glossiness = matJson.GetFloatValue("Glossiness"); + if (matJson != null && matJson.PathExists("Specular")) specular = matJson.GetFloatValue("Specular"); + if (matJson != null && matJson.PathExists("Specular Color")) specularColor = Util.LinearTosRGB(matJson.GetColorValue("Specular Color")); + glossiness = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, glossiness); + mat.SetFloatIf("_Smoothness", glossiness); + mat.SetFloatIf("_GlossMapScale", glossiness); + mat.SetFloatIf("_Glossiness", glossiness); + mat.SetMinMaxRange("_SmoothnessRemap", 0f, glossiness); } } diff --git a/Editor/ImporterMenu.cs b/Editor/ImporterMenu.cs index b1c00b8..f1b4d28 100644 --- a/Editor/ImporterMenu.cs +++ b/Editor/ImporterMenu.cs @@ -77,21 +77,20 @@ public static bool ValidateShowAnimationRetargeter() return WindowManager.IsPreviewScene && AnimPlayerGUI.IsPlayerShown(); } - [MenuItem("Assets/Reallusion/Import Character", priority = 2000)] + /* + [MenuItem("Assets/Reallusion/Import Character (Single Character Mode)", priority = 2000)] public static void InitAssetCC3ImportGUI() { ImporterWindow.Init(ImporterWindow.Mode.single, Selection.activeObject); } - [MenuItem("Assets/Reallusion/Import Character", true)] + [MenuItem("Assets/Reallusion/Import Character (Single Character Mode)", true)] public static bool ValidateInitAssetCC3ImportGUI() { if (Util.IsCC3Character(Selection.activeObject)) return true; return false; - } + }*/ - - // Scene Tools // diff --git a/Editor/ImporterWindow.cs b/Editor/ImporterWindow.cs index 8b879fc..58103c7 100644 --- a/Editor/ImporterWindow.cs +++ b/Editor/ImporterWindow.cs @@ -25,6 +25,10 @@ using UnityEngine.SceneManagement; using UnityEditor.SceneManagement; using Object = UnityEngine.Object; +using UnityEditor.Experimental.GraphView; +using UnityEngine.EventSystems; +using UnityEngine.UIElements; +using System.Runtime.Remoting.Messaging; namespace Reallusion.Import { @@ -61,12 +65,30 @@ public enum ImporterWindowMode { Build, Bake, Settings } const float INFO_HEIGHT = 80f; const float OPTION_HEIGHT = 170f; const float ACTION_HEIGHT = 76f; - const float ICON_WIDTH = 100f; + const float ICON_WIDTH = 100f; // re-purposed below for draggable width icon area const float ACTION_WIDTH = ACTION_BUTTON_SIZE + 12f; const float TITLE_SPACE = 12f; const float ROW_SPACE = 4f; - private GUIStyle logStyle, mainStyle, buttonStyle, labelStyle, boldStyle, iconStyle; + // additions for draggable width icon area + const float DRAG_BAR_WIDTH = 2f; + const float DRAG_HANDLE_PADDING = 8f; + const float ICON_WIDTH_MIN = 100f; + const float ICON_WIDTH_DETAIL = 140f; + const float ICON_SIZE_SMALL = 25f; + const float ICON_DETAIL_MARGIN = 2f; + private float CURRENT_INFO_WIDTH = 0f; + const float INFO_WIDTH_MIN = 0f; + private bool dragging = false; + private bool repaintDelegated = false; + + private Styles importerStyles; + //GUIStyle dragBarStyle; + //GUIStyle nameTextStyle; + //GUIStyle fakeButton; + //GUIStyle fakeButtonContext; + + //private GUIStyle logStyle, mainStyle, buttonStyle, labelStyle, boldStyle, iconStyle; private Texture2D iconUnprocessed; private Texture2D iconBasic; private Texture2D iconHQ; @@ -92,7 +114,7 @@ public enum ImporterWindowMode { Build, Bake, Settings } private Texture2D iconSettingsOn; private Texture2D iconLighting; private Texture2D iconCamera; - private Texture2D iconBuildMaterials; + private Texture2D iconBuildMaterials; // SerializeField is used to ensure the view state is written to the window // layout file. This means that the state survives restarting Unity as long as the window @@ -100,7 +122,22 @@ public enum ImporterWindowMode { Build, Bake, Settings } [SerializeField] TreeViewState treeViewState; //The TreeView is not serializable, so it should be reconstructed from the tree data. - CharacterTreeView characterTreeView; + CharacterTreeView characterTreeView; + + public static float ICON_AREA_WIDTH + { + get + { + if (EditorPrefs.HasKey("RL_Importer_IconAreaWidth")) + return EditorPrefs.GetFloat("RL_Importer_IconAreaWidth"); + return ICON_WIDTH; + } + + set + { + EditorPrefs.SetFloat("RL_Importer_IconAreaWidth", value); + } + } public static void StoreBackScene() { @@ -203,42 +240,20 @@ private void InitData() Current = this; RefreshCharacterList(); + + if (titleContent.text != windowTitle) titleContent.text = windowTitle; + } - logStyle = new GUIStyle(); - logStyle.wordWrap = true; - logStyle.fontStyle = FontStyle.Italic; - logStyle.normal.textColor = Color.grey; - - mainStyle = new GUIStyle(); - mainStyle.wordWrap = false; - mainStyle.fontStyle = FontStyle.Normal; - mainStyle.normal.textColor = Color.white; - - iconStyle = new GUIStyle(); - iconStyle.wordWrap = false; - iconStyle.fontStyle = FontStyle.Normal; - iconStyle.normal.textColor = Color.white; - iconStyle.alignment = TextAnchor.MiddleCenter; - - boldStyle = new GUIStyle(); - boldStyle.alignment = TextAnchor.UpperLeft; - boldStyle.wordWrap = false; - boldStyle.fontStyle = FontStyle.Bold; - boldStyle.normal.textColor = Color.white; - - labelStyle = new GUIStyle(); - labelStyle.alignment = TextAnchor.UpperLeft; - labelStyle.wordWrap = false; - labelStyle.fontStyle = FontStyle.Normal; - labelStyle.normal.textColor = Color.white; - - buttonStyle = new GUIStyle(); - buttonStyle.wordWrap = false; - buttonStyle.fontStyle = FontStyle.Normal; - buttonStyle.normal.textColor = Color.white; - buttonStyle.alignment = TextAnchor.MiddleCenter; + private void PreviewCharacter() + { + StoreBackScene(); - if (titleContent.text != windowTitle) titleContent.text = windowTitle; + WindowManager.OpenPreviewScene(contextCharacter.Fbx); + + if (WindowManager.showPlayer) + WindowManager.ShowAnimationPlayer(); + + ResetAllSceneViewCamera(); } private void RefreshCharacterList() @@ -347,12 +362,22 @@ private void CreateTreeView(bool clearSelection = false) private void OnGUI() { + if (importerStyles == null) importerStyles = new Styles(); + RestoreData(); RestoreSelection(); - + if (validCharacters == null || validCharacters.Count == 0) { + GUILayout.BeginVertical(); + GUILayout.FlexibleSpace(); + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); GUILayout.Label("No CC/iClone Characters detected!"); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.EndVertical(); return; } @@ -364,12 +389,18 @@ private void OnGUI() if (contextCharacter.Generation == BaseGeneration.Unknown) optionHeight += 14f; optionHeight += 14f; - Rect iconBlock = new Rect(0f, TOP_PADDING, ICON_WIDTH, innerHeight); - Rect infoBlock = new Rect(iconBlock.xMax, TOP_PADDING, width - ICON_WIDTH - ACTION_WIDTH, INFO_HEIGHT); - Rect optionBlock = new Rect(iconBlock.xMax, infoBlock.yMax, infoBlock.width, optionHeight); - Rect actionBlock = new Rect(iconBlock.xMax + infoBlock.width, TOP_PADDING, ACTION_WIDTH, innerHeight); - Rect treeviewBlock = new Rect(iconBlock.xMax, optionBlock.yMax, infoBlock.width, height - optionBlock.yMax); - Rect settingsBlock = new Rect(iconBlock.xMax, TOP_PADDING, width - ICON_WIDTH - ACTION_WIDTH, innerHeight); + Rect iconBlock = new Rect(0f, TOP_PADDING, ICON_AREA_WIDTH, innerHeight); + + // additions for draggable width icon area + Rect dragBar = new Rect(iconBlock.xMax, TOP_PADDING, DRAG_BAR_WIDTH, innerHeight); + + Rect infoBlock = new Rect(dragBar.xMax, TOP_PADDING, width - ICON_AREA_WIDTH - ACTION_WIDTH, INFO_HEIGHT); + CURRENT_INFO_WIDTH = infoBlock.width; + + Rect optionBlock = new Rect(dragBar.xMax, infoBlock.yMax, infoBlock.width, optionHeight); + Rect actionBlock = new Rect(dragBar.xMax + infoBlock.width, TOP_PADDING, ACTION_WIDTH, innerHeight); + Rect treeviewBlock = new Rect(dragBar.xMax, optionBlock.yMax, infoBlock.width, height - optionBlock.yMax); + Rect settingsBlock = new Rect(dragBar.xMax, TOP_PADDING, width - ICON_AREA_WIDTH - ACTION_WIDTH, innerHeight); previewCharacterAfterGUI = false; refreshAfterGUI = false; @@ -381,7 +412,9 @@ private void OnGUI() CheckDragAndDrop(); - OnGUIIconArea(iconBlock); + //OnGUIIconArea(iconBlock); + OnGUIFlexibleIconArea(iconBlock); + OnGUIDragBarArea(dragBar); if (windowMode == ImporterWindowMode.Build) OnGUIInfoArea(infoBlock); @@ -397,116 +430,39 @@ private void OnGUI() if (windowMode == ImporterWindowMode.Build) OnGUITreeViewArea(treeviewBlock); - // functions to run after the GUI has finished... - + // functions to run after the GUI has finished... if (previewCharacterAfterGUI) { - StoreBackScene(); - - WindowManager.OpenPreviewScene(contextCharacter.Fbx); - - if (WindowManager.showPlayer) - WindowManager.ShowAnimationPlayer(); - - ResetAllSceneViewCamera(); + EditorApplication.delayCall += PreviewCharacter; } else if (refreshAfterGUI) { - RefreshCharacterList(); + EditorApplication.delayCall += RefreshCharacterList; } else if (buildAfterGUI) { - BuildCharacter(); + EditorApplication.delayCall += BuildCharacter; } else if (bakeAfterGUI) { - BakeCharacter(); + EditorApplication.delayCall += BakeCharacter; } else if (bakeHairAfterGUI) { - BakeCharacterHair(); + EditorApplication.delayCall += BakeCharacterHair; } else if (restoreHairAfterGUI) { - RestoreCharacterHair(); + EditorApplication.delayCall += RestoreCharacterHair; } else if (physicsAfterGUI) { - RebuildCharacterPhysics(); + EditorApplication.delayCall += RebuildCharacterPhysics; } } bool doubleClick = false; - - private void OnGUIIconArea(Rect iconBlock) - { - GUILayout.BeginArea(iconBlock); - - Event e = Event.current; - if (e.isMouse && e.type == EventType.MouseDown) - { - if (e.clickCount == 2) doubleClick = true; - else doubleClick = false; - } - - using (var iconScrollViewScope = new EditorGUILayout.ScrollViewScope(iconScrollView, GUILayout.Width(iconBlock.width - 10f), GUILayout.Height(iconBlock.height - 10f))) - { - iconScrollView = iconScrollViewScope.scrollPosition; - GUILayout.BeginVertical(); - - for (int idx = 0; idx < validCharacters.Count; idx++) - { - CharacterInfo info = validCharacters[idx]; - GUILayout.BeginHorizontal(); - GUILayout.Space(7f); - Texture2D iconTexture = iconUnprocessed; - - if (info.bakeIsBaked) - { - if (info.BuiltBasicMaterials) iconTexture = iconMixed; - else if (info.BuiltHQMaterials) iconTexture = iconBaked; - } - else - { - if (info.BuiltBasicMaterials) iconTexture = iconBasic; - else if (info.BuiltHQMaterials) iconTexture = iconHQ; - } - - Color background = GUI.backgroundColor; - Color tint = background; - if (contextCharacter == info) - tint = Color.green; - GUI.backgroundColor = Color.Lerp(background, tint, 0.25f); - - if (GUILayout.Button(iconTexture, - GUILayout.Width(ICON_SIZE), - GUILayout.Height(ICON_SIZE))) - { - SetContextCharacter(info.guid); - if (doubleClick) - { - previewCharacterAfterGUI = true; - } - } - - GUI.backgroundColor = background; - - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - string name = Path.GetFileNameWithoutExtension(AssetDatabase.GUIDToAssetPath(info.guid)); - GUILayout.Box(name, iconStyle, GUILayout.Width(ICON_SIZE)); - GUILayout.FlexibleSpace(); - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - } - GUILayout.EndVertical(); - } - GUILayout.EndArea(); - } - + private void OnGUIInfoArea(Rect infoBlock) { string importType = "Unprocessed"; @@ -526,13 +482,13 @@ private void OnGUIInfoArea(Rect infoBlock) GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); - GUILayout.Label(contextCharacter.name, boldStyle); + GUILayout.Label(contextCharacter.name, importerStyles.boldStyle); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); - GUILayout.Label(contextCharacter.folder, labelStyle); + GUILayout.Label(contextCharacter.folder, importerStyles.labelStyle); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); @@ -541,13 +497,13 @@ private void OnGUIInfoArea(Rect infoBlock) GUILayout.Label("(" + contextCharacter.Generation.ToString() + "/" + contextCharacter.FaceProfile.expressionProfile + "/" + contextCharacter.FaceProfile.visemeProfile - + ")", boldStyle); + + ")", importerStyles.boldStyle); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); - GUILayout.Label(importType, boldStyle); + GUILayout.Label(importType, importerStyles.boldStyle); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); @@ -968,7 +924,7 @@ private void OnGUISettingsArea(Rect settingsBlock) GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); - GUILayout.Label("Settings", boldStyle); + GUILayout.Label("Settings", importerStyles.boldStyle); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(TITLE_SPACE); @@ -1004,7 +960,7 @@ private void OnGUISettingsArea(Rect settingsBlock) GUILayout.Space(ROW_SPACE); GUILayout.Space(10f); - GUILayout.BeginVertical(new GUIContent("", "Override mip-map bias for all textures setup for the characters."), labelStyle); + GUILayout.BeginVertical(new GUIContent("", "Override mip-map bias for all textures setup for the characters."), importerStyles.labelStyle); GUILayout.Label("Mip-map Bias"); GUILayout.Space(ROW_SPACE); GUILayout.BeginHorizontal(); @@ -1016,7 +972,7 @@ private void OnGUISettingsArea(Rect settingsBlock) GUILayout.Space(ROW_SPACE); GUILayout.Space(10f); - GUILayout.BeginVertical(new GUIContent("", "When setting up the physics capsule and sphere colliders, shrink the radius by this amount. This can help resolve colliders pushing out cloth too much during simulation."), labelStyle); + GUILayout.BeginVertical(new GUIContent("", "When setting up the physics capsule and sphere colliders, shrink the radius by this amount. This can help resolve colliders pushing out cloth too much during simulation."), importerStyles.labelStyle); GUILayout.Label("Physics Collider Shrink"); GUILayout.Space(ROW_SPACE); GUILayout.BeginHorizontal(); @@ -1028,7 +984,7 @@ private void OnGUISettingsArea(Rect settingsBlock) GUILayout.Space(ROW_SPACE); GUILayout.Space(10f); - GUILayout.BeginVertical(new GUIContent("", "When assigning weight maps, the system analyses the weights of the mesh to determine which colliders affect the cloth simulation.Only cloth weights above this threshold will be considered for collider detection. Note: This is the default value supplied to the WeightMapper component, it can be further modified there."), labelStyle); + GUILayout.BeginVertical(new GUIContent("", "When assigning weight maps, the system analyses the weights of the mesh to determine which colliders affect the cloth simulation.Only cloth weights above this threshold will be considered for collider detection. Note: This is the default value supplied to the WeightMapper component, it can be further modified there."), importerStyles.labelStyle); GUILayout.Label("Physics Collider Detection Threshold"); GUILayout.Space(ROW_SPACE); GUILayout.BeginHorizontal(); @@ -1359,6 +1315,355 @@ public static void ResetOptions() Physics.PHYSICS_SHRINK_COLLIDER_RADIUS = 0.5f; Physics.PHYSICS_WEIGHT_MAP_DETECT_COLLIDER_THRESHOLD = 0.25f; Util.LOG_LEVEL = 0; + ICON_AREA_WIDTH = ICON_WIDTH; + } + + // additions for draggable width icon area + + private void OnGUIDragBarArea(Rect dragBar) + { + Rect dragHandle = new Rect(dragBar.x - DRAG_HANDLE_PADDING, dragBar.y, 2 * DRAG_HANDLE_PADDING, dragBar.height); + EditorGUIUtility.AddCursorRect(dragHandle, MouseCursor.ResizeHorizontal); + HandleMouseDrag(dragHandle); + + GUILayout.BeginArea(dragBar); + GUILayout.BeginVertical(importerStyles.dragBarStyle); + GUILayout.EndVertical(); + GUILayout.EndArea(); + } + + private void OnGUIFlexibleIconArea(Rect iconBlock) + { + if (ICON_AREA_WIDTH > ICON_WIDTH_DETAIL) + { + OnGUIDetailIconArea(iconBlock); // detail view icon area layout + } + else + { + OnGUILargeIconArea(iconBlock); // adapted original icon area layaout + } + } + + // adapted original icon area layaout + private void OnGUILargeIconArea(Rect iconBlock) + { + GUILayout.BeginArea(iconBlock); + + Event e = Event.current; + if (e.isMouse && e.type == EventType.MouseDown) + { + if (e.clickCount == 2) doubleClick = true; + else doubleClick = false; + } + + using (var iconScrollViewScope = new EditorGUILayout.ScrollViewScope(iconScrollView, GUILayout.Width(iconBlock.width - 1f), GUILayout.Height(iconBlock.height - 10f))) + { + iconScrollView = iconScrollViewScope.scrollPosition; + GUILayout.BeginVertical(); + + for (int idx = 0; idx < validCharacters.Count; idx++) + { + CharacterInfo info = validCharacters[idx]; + Texture2D iconTexture = iconUnprocessed; + string name = Path.GetFileNameWithoutExtension(AssetDatabase.GUIDToAssetPath(info.guid)); + if (info.bakeIsBaked) + { + if (info.BuiltBasicMaterials) iconTexture = iconMixed; + else if (info.BuiltHQMaterials) iconTexture = iconBaked; + } + else + { + if (info.BuiltBasicMaterials) iconTexture = iconBasic; + else if (info.BuiltHQMaterials) iconTexture = iconHQ; + } + + Color background = GUI.backgroundColor; + Color tint = background; + if (contextCharacter == info) + tint = Color.green; + GUI.backgroundColor = Color.Lerp(background, tint, 0.25f); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + GUILayout.BeginVertical(); + if (GUILayout.Button(iconTexture, + GUILayout.Width(ICON_SIZE), + GUILayout.Height(ICON_SIZE))) + { + SetContextCharacter(info.guid); + if (doubleClick) + { + previewCharacterAfterGUI = true; + } + } + + GUI.backgroundColor = background; + + GUILayout.Space(2f); + + GUILayout.Box(name, importerStyles.iconStyle, GUILayout.Width(ICON_SIZE)); + GUILayout.Space(2f); + GUILayout.EndVertical(); + + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + } + GUILayout.EndVertical(); + } + GUILayout.EndArea(); + } + + // detail view icon area layout + private void OnGUIDetailIconArea(Rect iconBlock) + { + importerStyles.FixMeh(); + + GUILayout.Space(TOP_PADDING); + + float rowHeight = ICON_SIZE_SMALL + 2 * ICON_DETAIL_MARGIN; + + Rect boxRect = new Rect(0f, 0f, ICON_AREA_WIDTH - 4f, rowHeight); + Rect posRect = new Rect(iconBlock); + Rect viewRect = new Rect(0f, 0f, ICON_AREA_WIDTH - 14f, rowHeight * validCharacters.Count); + + iconScrollView = GUI.BeginScrollView(posRect, iconScrollView, viewRect, false, false); + for (int idx = 0; idx < validCharacters.Count; idx++) + { + CharacterInfo info = validCharacters[idx]; + Texture2D iconTexture = iconUnprocessed; + string name = Path.GetFileNameWithoutExtension(AssetDatabase.GUIDToAssetPath(info.guid)); + if (info.bakeIsBaked) + { + if (info.BuiltBasicMaterials) iconTexture = iconMixed; + else if (info.BuiltHQMaterials) iconTexture = iconBaked; + } + else + { + if (info.BuiltBasicMaterials) iconTexture = iconBasic; + else if (info.BuiltHQMaterials) iconTexture = iconHQ; + } + + float heightDelta = ICON_SIZE_SMALL + 2 * ICON_DETAIL_MARGIN; + boxRect.y = idx * heightDelta; + + GUILayout.BeginArea(boxRect); + + GUILayout.BeginVertical(contextCharacter == info ? importerStyles.fakeButtonContext : importerStyles.fakeButton); + GUILayout.FlexibleSpace(); + + GUILayout.BeginHorizontal(); // horizontal container for image and label + + GUILayout.BeginVertical(); // vertical container for image + GUILayout.FlexibleSpace(); + + GUILayout.Box(iconTexture, new GUIStyle(), + GUILayout.Width(ICON_SIZE_SMALL), + GUILayout.Height(ICON_SIZE_SMALL)); + GUILayout.FlexibleSpace(); + GUILayout.EndVertical(); // vertical container for image + + GUILayout.BeginVertical(); // vertical container for label + GUILayout.FlexibleSpace(); + GUILayout.Label(name, importerStyles.nameTextStyle); + GUILayout.FlexibleSpace(); + GUILayout.EndVertical(); // vertical container for label + + GUILayout.FlexibleSpace(); // fill horizontal for overall left-justify + + GUILayout.EndHorizontal(); // horizontal container for image and label + + GUILayout.FlexibleSpace(); + GUILayout.EndVertical(); //(fakeButton) + + GUILayout.EndArea(); + + if (HandleListClick(boxRect)) + { + RepaintOnUpdate(); + SetContextCharacter(info.guid); + if (fakeButtonDoubleClick) + { + previewCharacterAfterGUI = true; + } + } + } + GUI.EndScrollView(); + } + + private void HandleMouseDrag(Rect container) + { + Event mouseEvent = Event.current; + if (container.Contains(mouseEvent.mousePosition) || dragging) + { + if (mouseEvent.type == EventType.MouseDrag) + { + dragging = true; + ICON_AREA_WIDTH += mouseEvent.delta.x; + if (ICON_AREA_WIDTH < ICON_WIDTH_MIN) + ICON_AREA_WIDTH = ICON_WIDTH_MIN; + + //float INFO_WIDTH_CALC = position.width - WINDOW_MARGIN - ICON_WIDTH - ACTION_WIDTH; + if (CURRENT_INFO_WIDTH < INFO_WIDTH_MIN) + ICON_AREA_WIDTH = position.width - WINDOW_MARGIN - ACTION_WIDTH - INFO_WIDTH_MIN; + + RepaintOnUpdate(); + } + + if (mouseEvent.type == EventType.MouseUp) + { + dragging = false; + + RepaintOnUpdate(); + } + } + } + + private bool fakeButtonDoubleClick = false; + + private bool HandleListClick(Rect container) + { + Event mouseEvent = Event.current; + if (container.Contains(mouseEvent.mousePosition)) + { + if (mouseEvent.type == EventType.MouseDown) + { + if (mouseEvent.clickCount == 2) + { + fakeButtonDoubleClick = true; + } + else + fakeButtonDoubleClick = false; + return true; + } + } + return false; + } + + void RepaintOnUpdate() + { + if (!repaintDelegated) + { + repaintDelegated = true; + EditorApplication.update -= RepaintOnceOnUpdate; + EditorApplication.update += RepaintOnceOnUpdate; + } + } + + void RepaintOnceOnUpdate() + { + Repaint(); + EditorApplication.update -= RepaintOnceOnUpdate; + repaintDelegated = false; + } + + public static Texture2D TextureColor(Color color) + { + const int size = 32; + Texture2D texture = new Texture2D(size, size); + Color[] pixels = texture.GetPixels(); + for (int i = 0; i < pixels.Length; i++) + { + pixels[i] = color; + } + texture.SetPixels(pixels); + texture.Apply(true); + return texture; + } + + + + public class Styles + { + public GUIStyle logStyle; + public GUIStyle mainStyle; + public GUIStyle buttonStyle; + public GUIStyle labelStyle; + public GUIStyle boldStyle; + public GUIStyle iconStyle; + public GUIStyle dragBarStyle; + public GUIStyle nameTextStyle; + public GUIStyle fakeButton; + public GUIStyle fakeButtonContext; + public Texture2D dragTex, contextTex; + + public Styles() + { + logStyle = new GUIStyle(); + logStyle.wordWrap = true; + logStyle.fontStyle = FontStyle.Italic; + logStyle.normal.textColor = Color.grey; + + mainStyle = new GUIStyle(); + mainStyle.wordWrap = false; + mainStyle.fontStyle = FontStyle.Normal; + mainStyle.normal.textColor = Color.white; + + iconStyle = new GUIStyle(); + iconStyle.wordWrap = false; + iconStyle.fontStyle = FontStyle.Normal; + iconStyle.normal.textColor = Color.white; + iconStyle.alignment = TextAnchor.MiddleCenter; + + boldStyle = new GUIStyle(); + boldStyle.alignment = TextAnchor.UpperLeft; + boldStyle.wordWrap = false; + boldStyle.fontStyle = FontStyle.Bold; + boldStyle.normal.textColor = Color.white; + + labelStyle = new GUIStyle(); + labelStyle.alignment = TextAnchor.UpperLeft; + labelStyle.wordWrap = false; + labelStyle.fontStyle = FontStyle.Normal; + labelStyle.normal.textColor = Color.white; + + buttonStyle = new GUIStyle(); + buttonStyle.wordWrap = false; + buttonStyle.fontStyle = FontStyle.Normal; + buttonStyle.normal.textColor = Color.white; + buttonStyle.alignment = TextAnchor.MiddleCenter; + + //color textures for the area styling + + + dragBarStyle = new GUIStyle(); + dragBarStyle.normal.background = dragTex; + dragBarStyle.stretchHeight = true; + dragBarStyle.stretchWidth = true; + + nameTextStyle = new GUIStyle(); + nameTextStyle.alignment = TextAnchor.MiddleLeft; + nameTextStyle.wordWrap = false; + nameTextStyle.fontStyle = FontStyle.Normal; + nameTextStyle.normal.textColor = Color.white; + + fakeButton = new GUIStyle(); + //fakeButton.normal.background = nonContextTex; + fakeButton.padding = new RectOffset(1, 1, 1, 1); + fakeButton.stretchHeight = true; + fakeButton.stretchWidth = true; + + fakeButtonContext = new GUIStyle(); + fakeButtonContext.name = "fakeButtonContext"; + fakeButtonContext.normal.background = contextTex; + fakeButtonContext.padding = new RectOffset(1, 1, 1, 1); + fakeButtonContext.stretchHeight = true; + fakeButtonContext.stretchWidth = true; + } + + public void FixMeh() + { + if (!dragTex) + { + dragTex = TextureColor(Color.white * 0.1f); + dragBarStyle.normal.background = dragTex; + } + if (!contextTex) + { + contextTex = TextureColor(new Color(0.259f, 0.345f, 0.259f)); + fakeButtonContext.normal.background = contextTex; + } + } } } } diff --git a/Editor/LodSelectionWindow.cs b/Editor/LodSelectionWindow.cs index 340884d..ab62826 100644 --- a/Editor/LodSelectionWindow.cs +++ b/Editor/LodSelectionWindow.cs @@ -74,9 +74,9 @@ public static LodSelectionWindow InitLodSelector() window.BuildModelPrefabDict(path); else window.BuildModelPrefabDict(Selection.objects); - + window.minSize = new Vector2(boxW * 3f + 8f, boxH * 2f + 24f); - window.Show(); + window.Show(); return window; } @@ -198,6 +198,19 @@ private void ContainerGUI() //Debug.Log(model.Value); } + if (modelList.Count == 0) + { + GUILayout.BeginVertical(); + GUILayout.FlexibleSpace(); + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.Label("No character prefabs detected in folder or selection."); + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + GUILayout.FlexibleSpace(); + GUILayout.EndVertical(); + } + GUI.EndScrollView(); return; @@ -271,7 +284,7 @@ private void BuildModelPrefabDict(string folder) AssetToModelList(bakedPathSuffix, path, guid, assetName, ref largest); } - nameField.SetValueWithoutNotify(nameHint + "_LODGroup"); + nameField.SetValueWithoutNotify(nameHint + "_LOD"); SortAndAutoSelect(); } diff --git a/Editor/MeshUtil.cs b/Editor/MeshUtil.cs index 394a3b6..fb49d60 100644 --- a/Editor/MeshUtil.cs +++ b/Editor/MeshUtil.cs @@ -275,6 +275,7 @@ public static void PruneBlendShapes(Object obj) string meshFolder = Path.Combine(folder, PRUNED_FOLDER_NAME); Mesh dstMesh = new Mesh(); + dstMesh.indexFormat = srcMesh.indexFormat; dstMesh.vertices = srcMesh.vertices; dstMesh.uv = srcMesh.uv; dstMesh.uv2 = srcMesh.uv2; @@ -344,6 +345,7 @@ public static void PruneBlendShapes(Object obj) public static Mesh CopyMesh(Mesh srcMesh) { Mesh dstMesh = new Mesh(); + dstMesh.indexFormat = srcMesh.indexFormat; dstMesh.vertices = srcMesh.vertices; dstMesh.uv = srcMesh.uv; dstMesh.uv2 = srcMesh.uv2; @@ -412,6 +414,7 @@ public static void ReverseTriangleOrder(Object obj) } Mesh dstMesh = new Mesh(); + dstMesh.indexFormat = srcMesh.indexFormat; dstMesh.vertices = srcMesh.vertices; dstMesh.uv = srcMesh.uv; dstMesh.uv2 = srcMesh.uv2; @@ -720,6 +723,7 @@ public static Mesh ExtractSubMesh(Mesh srcMesh, int index) // now create the extracted mesh Mesh newMesh = new Mesh(); + newMesh.indexFormat = srcMesh.indexFormat; Vector3[] vertices = new Vector3[numNewVerts]; Vector2[] uv = new Vector2[srcUv.Length > 0 ? numNewVerts : 0]; Vector2[] uv2 = new Vector2[srcUv2.Length > 0 ? numNewVerts : 0]; @@ -884,6 +888,7 @@ public static Mesh RemoveSubMeshes(Mesh srcMesh, List indices) // now create the extracted mesh Mesh newMesh = new Mesh(); + newMesh.indexFormat = srcMesh.indexFormat; Vector3[] vertices = new Vector3[numNewVerts]; Vector2[] uv = new Vector2[srcUv.Length > 0 ? numNewVerts : 0]; Vector2[] uv2 = new Vector2[srcUv2.Length > 0 ? numNewVerts : 0]; @@ -1078,12 +1083,23 @@ public static GameObject Extract2PassHairMeshes(CharacterInfo info, GameObject p { bool hasHairMaterial = false; bool isFacialObject = FacialProfileMapper.MeshHasFacialBlendShapes(r.gameObject); + bool hasScalpMaterial = false; int subMeshCount = 0; + int hairMeshCount = 0; foreach (Material m in r.sharedMaterials) { subMeshCount++; if (m.shader.name.iContains(Pipeline.SHADER_HQ_HAIR)) + { hasHairMaterial = true; + hairMeshCount++; + } + else if (m.name.iContains("scalp_") || + m.name.iContains("_base_") || + m.name.iContains("_transparency")) + { + hasScalpMaterial = true; + } } if (hasHairMaterial) @@ -1129,7 +1145,7 @@ public static GameObject Extract2PassHairMeshes(CharacterInfo info, GameObject p // extract mesh into two new meshes, the old mesh without the extracted submesh // and just the extracted submesh - Mesh newMesh = ExtractSubMesh(oldMesh, index); + Mesh newMesh = ExtractSubMesh(oldMesh, index); // Save the mesh asset. Util.EnsureAssetsFolderExists(meshFolder); string meshPath = Path.Combine(meshFolder, oldObj.name + "_ExtractedHairMesh" + index.ToString() + ".mesh"); @@ -1232,6 +1248,14 @@ public static GameObject Extract2PassHairMeshes(CharacterInfo info, GameObject p oldSmr.sharedMaterials = sharedMaterials; } + // if the hair mesh has a scalp or base then what remains should be the scalp/base + // in HDRP ray tracing this should be set to not ray trace. + // but only if there is only the scalp material left: + if (hasScalpMaterial && oldSmr.sharedMaterials.Length == 1) + { + Pipeline.DisableRayTracing(oldSmr); + } + processCount++; } } diff --git a/Editor/Pipeline.cs b/Editor/Pipeline.cs index f3ba8a9..6d63bb8 100644 --- a/Editor/Pipeline.cs +++ b/Editor/Pipeline.cs @@ -40,7 +40,7 @@ public enum MaterialQuality { None, Default, High, Baked } public static class Pipeline { - public const string VERSION = "1.4.0"; + public const string VERSION = "1.4.1"; #if HDRP_10_5_0_OR_NEWER // version @@ -494,49 +494,40 @@ public static void AddDiffusionProfilesHDRP() SerializedProperty item; int index; + bool modified = false; + string[] profiles = new string[] { "RL_Skin_Profile", "RL_Teeth_Profile", "RL_Eye_Profile", "RL_SSS_Profile" }; - Object skinProfileAsset = Util.FindAsset("RL_Skin_Profile"); - Object teethProfileAsset = Util.FindAsset("RL_Teeth_Profile"); - Object eyeProfileAsset = Util.FindAsset("RL_Eye_Profile"); - - if (!skinProfileAsset || !teethProfileAsset || !eyeProfileAsset) return; - - bool addSkinProfile = true; - bool addTeethProfile = true; - bool addEyeProfile = true; - foreach (SerializedProperty p in list) - { - if (p.objectReferenceValue == skinProfileAsset) addSkinProfile = false; - if (p.objectReferenceValue == teethProfileAsset) addTeethProfile = false; - if (p.objectReferenceValue == eyeProfileAsset) addEyeProfile = false; - } - - if (addSkinProfile) + foreach (string profile in profiles) { - index = list.arraySize; - list.InsertArrayElementAtIndex(index); - item = list.GetArrayElementAtIndex(index); - item.objectReferenceValue = skinProfileAsset; - } + Object asset = Util.FindAsset(profile); + if (asset) + { + bool add = true; - if (addTeethProfile) - { - index = list.arraySize; - list.InsertArrayElementAtIndex(index); - item = list.GetArrayElementAtIndex(index); - item.objectReferenceValue = teethProfileAsset; - } + foreach (SerializedProperty p in list) + { + if (p.objectReferenceValue == asset) add = false; + } - if (addEyeProfile) - { - index = list.arraySize; - list.InsertArrayElementAtIndex(index); - item = list.GetArrayElementAtIndex(index); - item.objectReferenceValue = eyeProfileAsset; + if (add) + { + index = list.arraySize; + if (index < 15) + { + list.InsertArrayElementAtIndex(index); + item = list.GetArrayElementAtIndex(index); + item.objectReferenceValue = asset; + modified = true; + } + else + { + Debug.LogWarning("Maximum number of diffusion profiles reached! Unable to add profile: " + profile); + } + } + } } - if (addSkinProfile || addTeethProfile || addEyeProfile) - hdrp.ApplyModifiedProperties(); + if (modified) hdrp.ApplyModifiedProperties(); #endif } @@ -728,5 +719,12 @@ public static bool IsShaderFor(string shaderName, params MaterialType[] material return false; } + + public static void DisableRayTracing(SkinnedMeshRenderer smr) + { +#if HDRP_10_5_0_OR_NEWER + smr.rayTracingMode = UnityEngine.Experimental.Rendering.RayTracingMode.Off; +#endif + } } } diff --git a/Editor/Util.cs b/Editor/Util.cs index 77e727e..0382026 100644 --- a/Editor/Util.cs +++ b/Editor/Util.cs @@ -21,6 +21,7 @@ using UnityEngine; using UnityEditor; using Object = UnityEngine.Object; +using System.Linq; namespace Reallusion.Import { @@ -64,6 +65,11 @@ public static bool IsCC3Character(Object obj) public static bool IsCC3Character(string guid) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); + return IsCC3CharacterAtPath(assetPath); + } + + public static bool IsCC3CharacterAtPath(string assetPath) + { if (assetPath.iEndsWith(".fbx")) { string assetFolder = Path.GetDirectoryName(assetPath); @@ -87,7 +93,7 @@ public static bool IsCC3Character(string guid) } return false; - } + } public static Color LinearTosRGBOld(Color c) { @@ -188,20 +194,31 @@ public static string GetJsonGenerationString(string jsonPath) return ""; } + public struct CharacterSort + { + public string guid; + public string name; + } + public static List GetValidCharacterGUIDS() { - string[] guids = AssetDatabase.FindAssets("t:Model", new string[] { "Assets" }); - List results = new List(); + string[] guids = AssetDatabase.FindAssets("t:Model", new string[] { "Assets" }); + List results = new List(); foreach (string g in guids) { - if (IsCC3Character(g)) + string assetPath = AssetDatabase.GUIDToAssetPath(g); + if (IsCC3CharacterAtPath(assetPath)) { - results.Add(g); + string name = Path.GetFileNameWithoutExtension(assetPath); + results.Add(new CharacterSort() { guid = g, name = name }); } } + + List sortedGuids = new List(results.Count); + foreach (CharacterSort cs in results.OrderBy(o => o.name)) sortedGuids.Add(cs.guid); - return results; + return sortedGuids; } public static void ImportPaths(List paths) diff --git a/package.json b/package.json index 09d3deb..5248652 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.soupday.cc3_unity_tools", - "version": "1.4.0", + "version": "1.4.1", "displayName": "CC/iC Unity Tools 3D", "description": "Unity importer for Character Creator 3 & 4 and iClone 7 and 8.", "unity": "2019.4", From 668617d0b6d3bee1320815f6cfcbfa5f5e46dd59 Mon Sep 17 00:00:00 2001 From: soupday <79094830+soupday@users.noreply.github.com> Date: Thu, 1 Dec 2022 04:57:51 +0000 Subject: [PATCH 05/10] 1.4.1 - --- Editor/ImporterWindow.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Editor/ImporterWindow.cs b/Editor/ImporterWindow.cs index 58103c7..f5a4b60 100644 --- a/Editor/ImporterWindow.cs +++ b/Editor/ImporterWindow.cs @@ -718,9 +718,9 @@ private void OnGUIActionArea(Rect actionBlock) restoreHairAfterGUI = true; } } - else if (!contextCharacter.BuiltBasicMaterials && contextCharacter.HasColorEnabledHair()) + else //if (!contextCharacter.BuiltBasicMaterials && contextCharacter.HasColorEnabledHair()) { - //if (contextCharacter.BuiltBasicMaterials || !contextCharacter.HasColorEnabledHair()) GUI.enabled = false; + if (contextCharacter.BuiltBasicMaterials || !contextCharacter.HasColorEnabledHair()) GUI.enabled = false; if (GUILayout.Button(new GUIContent(iconActionBakeHair, "Bake hair materials, to preview the baked results of the 'Enable Color' in the hair materials."), GUILayout.Width(ACTION_BUTTON_SIZE), GUILayout.Height(ACTION_BUTTON_SIZE))) From 3fa3258bb69096498d203c42aaeb75e21058a70d Mon Sep 17 00:00:00 2001 From: Victor Soupday <79094830+soupday@users.noreply.github.com> Date: Thu, 1 Dec 2022 21:35:08 +0000 Subject: [PATCH 06/10] 1.4.1 ActorCore detection within bone lod exports. Single material actor build detection. --- .../RL_Template_Default_SingleMaterial_3D.mat | 2 +- ...L_Template_Default_SingleMaterial_3D_T.mat | 2 +- CHANGELOG.md | 3 + Editor/Importer.cs | 133 ++++++++++++------ Editor/ImporterWindow.cs | 9 +- Editor/Pipeline.cs | 12 +- Editor/RL.cs | 83 ++++++++++- 7 files changed, 192 insertions(+), 52 deletions(-) diff --git a/3D/Material Templates/RL_Template_Default_SingleMaterial_3D.mat b/3D/Material Templates/RL_Template_Default_SingleMaterial_3D.mat index b6dd904..dee6c86 100644 --- a/3D/Material Templates/RL_Template_Default_SingleMaterial_3D.mat +++ b/3D/Material Templates/RL_Template_Default_SingleMaterial_3D.mat @@ -77,7 +77,7 @@ Material: m_Offset: {x: 0, y: 0} m_Floats: - _BumpScale: 1 - - _Cutoff: 0.25 + - _Cutoff: 0.667 - _DetailNormalMapScale: 1 - _DstBlend: 0 - _GlossMapScale: 0.897 diff --git a/3D/Material Templates/Tessellation/RL_Template_Default_SingleMaterial_3D_T.mat b/3D/Material Templates/Tessellation/RL_Template_Default_SingleMaterial_3D_T.mat index c021c07..81b13b3 100644 --- a/3D/Material Templates/Tessellation/RL_Template_Default_SingleMaterial_3D_T.mat +++ b/3D/Material Templates/Tessellation/RL_Template_Default_SingleMaterial_3D_T.mat @@ -79,7 +79,7 @@ Material: m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} m_Floats: - - _AlphaClip: 0.5 + - _AlphaClip: 0.667 - _BumpScale: 1 - _Cutoff: 0.25 - _DetailNormalMapScale: 1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 41d9564..3c5a598 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ Changelog - Remembers last used lighting preset on character preview change. - Character icon list side bar can be dragged into a more compact list view. - Character list sorted alphabetically. +- When HDRP Ray tracing is enabled: + - The material build function will turn off ray tracing on the Scalp (when separeated), Eye Occlusion and Tearline meshes as it causes darkening artifacts on the underlying skin and eye surfaces. + - (Typically the scalp is only seperated from the hair materials when two-pass hair is enabled) ### v 1.4.0 - Import & Setup diff --git a/Editor/Importer.cs b/Editor/Importer.cs index 166dd35..9454461 100644 --- a/Editor/Importer.cs +++ b/Editor/Importer.cs @@ -65,6 +65,8 @@ public class Importer public const int FLAG_WRAP_CLAMP = 1024; public const float MAX_SMOOTHNESS = 0.897f; + public const float SPECULAR_SCALE = 0.5f; + public const float TRA_SPECULAR_SCALE = 0.2f; public static float MIPMAP_BIAS { @@ -375,10 +377,12 @@ private void ProcessObjectBuildPass(Renderer renderer) QuickJSON matJson = GetMatJson(obj, sourceName); // determine the material type, this dictates the shader and template material. - MaterialType materialType = GetMaterialType(obj, sharedMat, sourceName, matJson); + MaterialType materialType = GetMaterialType(obj, sharedMat, sourceName, matJson); Util.LogInfo(" Material name: " + sourceName + ", type:" + materialType.ToString()); + FixRayTracing(obj, sharedMat, materialType); + // re-use or create the material. Material mat = CreateRemapMaterial(materialType, sharedMat, sourceName); @@ -706,6 +710,27 @@ private Material CreateRemapMaterial(MaterialType materialType, Material sharedM return remapMaterial; } + private void FixRayTracing(GameObject obj, Material mat, MaterialType materialType) + { + SkinnedMeshRenderer smr = obj.GetComponent(); + + if (smr) + { + if (materialType == MaterialType.EyeOcclusion || + materialType == MaterialType.Tearline) + { + Pipeline.DisableRayTracing(smr); + } + else if (materialType == MaterialType.Scalp) + { + if (smr.sharedMaterials.Length == 1) + { + Pipeline.DisableRayTracing(smr); + } + } + } + } + private void ProcessTextures(GameObject obj, string sourceName, Material sharedMat, Material mat, MaterialType materialType, QuickJSON matJson) { @@ -1044,12 +1069,7 @@ private void ConnectDefaultMaterial(GameObject obj, string sourceName, Material if (RP != RenderPipeline.Builtin) mat.SetColorIf("_BaseColor", Util.LinearTosRGB(matJson.GetColorValue("Diffuse Color"))); else - mat.SetColorIf("_Color", Util.LinearTosRGB(matJson.GetColorValue("Diffuse Color"))); - - if (RP == RenderPipeline.HDRP) - mat.SetColorIf("_SpecularColor", 0.2f * Util.LinearTosRGB(matJson.GetColorValue("Specular Color"))); - else - mat.SetColorIf("_SpecColor", 0.2f * Util.LinearTosRGB(matJson.GetColorValue("Specular Color"))); + mat.SetColorIf("_Color", Util.LinearTosRGB(matJson.GetColorValue("Diffuse Color"))); // Emission if (matJson.PathExists("Textures/Glow/Texture Path")) @@ -1148,49 +1168,78 @@ private void ConnectDefaultMaterial(GameObject obj, string sourceName, Material } } - // Apply micro roughness & specular - if (matJson != null && matJson.PathExists("Custom Shader/Variable/Micro Roughness Scale")) + // Smoothness/Glossiness and Specular + if (matJson != null) { - float microRoughnessMod = 0.0f; - float specular = 0.5f; if (matJson.PathExists("Custom Shader/Variable/Micro Roughness Scale")) - microRoughnessMod = matJson.GetFloatValue("Custom Shader/Variable/Micro Roughness Scale"); - if (matJson.PathExists("Custom Shader/Variable/_Specular")) - specular = matJson.GetFloatValue("Custom Shader/Variable/_Specular"); - - if (RP == RenderPipeline.HDRP) { - float smoothness = Util.CombineSpecularToSmoothness(specular, mat.GetFloatIf("_Smoothness", 0.5f)); - float smoothnessMin = Util.CombineSpecularToSmoothness(specular, mat.GetFloatIf("_SmoothnessRemapMin", 0f)); - float smoothnessMax = Util.CombineSpecularToSmoothness(specular, mat.GetFloatIf("_SmoothnessRemapMax", MAX_SMOOTHNESS)); - mat.SetMinMaxRange("_SmoothnessRemap", smoothnessMin - microRoughnessMod, smoothnessMax - microRoughnessMod); - mat.SetFloatIf("_Smoothness", smoothness - microRoughnessMod); + Color specularColor = Color.white * SPECULAR_SCALE; + float microRoughnessMod = 0.0f; + float specular = 0.5f; + + if (matJson.PathExists("Custom Shader/Variable/Micro Roughness Scale")) + microRoughnessMod = matJson.GetFloatValue("Custom Shader/Variable/Micro Roughness Scale"); + if (matJson.PathExists("Custom Shader/Variable/_Specular")) + specular = matJson.GetFloatValue("Custom Shader/Variable/_Specular"); + if (matJson != null && matJson.PathExists("Specular Color")) + specularColor = SPECULAR_SCALE * Util.LinearTosRGB(matJson.GetColorValue("Specular Color")); + + if (RP == RenderPipeline.HDRP) + { + float smoothness = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, mat.GetFloatIf("_Smoothness", 0.5f)); + float smoothnessMin = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, mat.GetFloatIf("_SmoothnessRemapMin", 0f)); + float smoothnessMax = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, mat.GetFloatIf("_SmoothnessRemapMax", MAX_SMOOTHNESS)); + mat.SetMinMaxRange("_SmoothnessRemap", smoothnessMin - microRoughnessMod, smoothnessMax - microRoughnessMod); + mat.SetFloatIf("_Smoothness", smoothness - microRoughnessMod); + } + else if (RP == RenderPipeline.URP) + { + float smoothness = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, mat.GetFloatIf("_Smoothness", 0.5f)); + mat.SetFloatIf("_Smoothness", smoothness - microRoughnessMod); + } + else + { + float smoothness = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, mat.GetFloatIf("_GlossMapScale", 0.5f)); + mat.SetFloatIf("_GlossMapScale", smoothness - microRoughnessMod); + } } - else if (RP == RenderPipeline.URP) + else if (jsonMaterialType.iEquals("Tra")) { - float smoothness = Util.CombineSpecularToSmoothness(specular, mat.GetFloatIf("_Smoothness", 0.5f)); - mat.SetFloatIf("_Smoothness", smoothness - microRoughnessMod); + float glossiness = 0.5f; + float specular = 1f; + Color specularColor = Color.white * TRA_SPECULAR_SCALE; + + if (matJson.PathExists("Glossiness")) + glossiness = matJson.GetFloatValue("Glossiness"); + if (matJson.PathExists("Specular")) + specular = matJson.GetFloatValue("Specular"); + if (matJson.PathExists("Specular Color")) + specularColor = TRA_SPECULAR_SCALE * Util.LinearTosRGB(matJson.GetColorValue("Specular Color")); + + glossiness = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, glossiness); + mat.SetFloatIf("_Smoothness", glossiness); + mat.SetFloatIf("_GlossMapScale", glossiness); + mat.SetFloatIf("_Glossiness", glossiness); + mat.SetMinMaxRange("_SmoothnessRemap", 0f, glossiness); + + if (RP == RenderPipeline.HDRP) + mat.SetColorIf("_SpecularColor", specularColor); + else + mat.SetColorIf("_SpecColor", specularColor); } else { - float smoothness = Util.CombineSpecularToSmoothness(specular, mat.GetFloatIf("_GlossMapScale", 0.5f)); - mat.SetFloatIf("_GlossMapScale", smoothness - microRoughnessMod); - } - } + Color specularColor = Color.white * SPECULAR_SCALE; - if (jsonMaterialType.iEquals("Tra")) - { - float glossiness = 0.5f; - float specular = 1f; - Color specularColor = Color.white; - if (matJson != null && matJson.PathExists("Glossiness")) glossiness = matJson.GetFloatValue("Glossiness"); - if (matJson != null && matJson.PathExists("Specular")) specular = matJson.GetFloatValue("Specular"); - if (matJson != null && matJson.PathExists("Specular Color")) specularColor = Util.LinearTosRGB(matJson.GetColorValue("Specular Color")); - glossiness = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, glossiness); - mat.SetFloatIf("_Smoothness", glossiness); - mat.SetFloatIf("_GlossMapScale", glossiness); - mat.SetFloatIf("_Glossiness", glossiness); - mat.SetMinMaxRange("_SmoothnessRemap", 0f, glossiness); + if (matJson.PathExists("Specular Color")) + specularColor = SPECULAR_SCALE * Util.LinearTosRGB(matJson.GetColorValue("Specular Color")); + + float specSmoothness = Util.CombineSpecularToSmoothness(specularColor.grayscale, MAX_SMOOTHNESS); + mat.SetMinMaxRange("_SmoothnessRemap", 0f, specSmoothness); + mat.SetFloatIf("_Smoothness", specSmoothness); + mat.SetFloatIf("_Smoothness", specSmoothness); + mat.SetFloatIf("_GlossMapScale", specSmoothness); + } } } @@ -1872,6 +1921,8 @@ private void ConnectHQEyeOcclusionMaterial(GameObject obj, string sourceName, Ma obj.transform.localScale.y + obj.transform.localScale.z) / 3.0f; mat.SetFloatIf("_ExpandScale", 1.0f / modelScale); + + } private void ConnectHQTearlineMaterial(GameObject obj, string sourceName, Material sharedMat, Material mat, diff --git a/Editor/ImporterWindow.cs b/Editor/ImporterWindow.cs index f5a4b60..82de981 100644 --- a/Editor/ImporterWindow.cs +++ b/Editor/ImporterWindow.cs @@ -25,10 +25,6 @@ using UnityEngine.SceneManagement; using UnityEditor.SceneManagement; using Object = UnityEngine.Object; -using UnityEditor.Experimental.GraphView; -using UnityEngine.EventSystems; -using UnityEngine.UIElements; -using System.Runtime.Remoting.Messaging; namespace Reallusion.Import { @@ -72,7 +68,7 @@ public enum ImporterWindowMode { Build, Bake, Settings } // additions for draggable width icon area const float DRAG_BAR_WIDTH = 2f; - const float DRAG_HANDLE_PADDING = 8f; + const float DRAG_HANDLE_PADDING = 4f; const float ICON_WIDTH_MIN = 100f; const float ICON_WIDTH_DETAIL = 140f; const float ICON_SIZE_SMALL = 25f; @@ -1322,7 +1318,8 @@ public static void ResetOptions() private void OnGUIDragBarArea(Rect dragBar) { - Rect dragHandle = new Rect(dragBar.x - DRAG_HANDLE_PADDING, dragBar.y, 2 * DRAG_HANDLE_PADDING, dragBar.height); + //Rect dragHandle = new Rect(dragBar.x - DRAG_HANDLE_PADDING, dragBar.y, 2 * DRAG_HANDLE_PADDING, dragBar.height); + Rect dragHandle = new Rect(dragBar.x, dragBar.y, DRAG_BAR_WIDTH + DRAG_HANDLE_PADDING, dragBar.height); EditorGUIUtility.AddCursorRect(dragHandle, MouseCursor.ResizeHorizontal); HandleMouseDrag(dragHandle); diff --git a/Editor/Pipeline.cs b/Editor/Pipeline.cs index 6d63bb8..7a74b5d 100644 --- a/Editor/Pipeline.cs +++ b/Editor/Pipeline.cs @@ -559,6 +559,13 @@ public static string GetQualityMaterialName(string sourceName, MaterialType mate if (info.Generation == BaseGeneration.ActorCore) return MATERIAL_DEFAULT_SINGLE_MATERIAL; + if (info.Generation == BaseGeneration.ActorBuild) + { + Material singleMaterial = RL.GetActorBuildSingleMaterial(info.Fbx); + if (singleMaterial && singleMaterial.name == sourceName) + return MATERIAL_DEFAULT_SINGLE_MATERIAL; + } + if (quality == MaterialQuality.High) // option overrides for high quality materials { if (info.RefractiveEyes) @@ -723,7 +730,10 @@ public static bool IsShaderFor(string shaderName, params MaterialType[] material public static void DisableRayTracing(SkinnedMeshRenderer smr) { #if HDRP_10_5_0_OR_NEWER - smr.rayTracingMode = UnityEngine.Experimental.Rendering.RayTracingMode.Off; + if (SystemInfo.supportsRayTracing) + { + smr.rayTracingMode = UnityEngine.Experimental.Rendering.RayTracingMode.Off; + } #endif } } diff --git a/Editor/RL.cs b/Editor/RL.cs index fea6d8a..da52db4 100644 --- a/Editor/RL.cs +++ b/Editor/RL.cs @@ -67,7 +67,7 @@ public static BaseGeneration GetCharacterGeneration(GameObject fbx, string gener else { if (fbx) - { + { Transform[] children = fbx.transform.GetComponentsInChildren(true); foreach (Transform child in children) { @@ -80,7 +80,11 @@ public static BaseGeneration GetCharacterGeneration(GameObject fbx, string gener if (objectName.iContains("RL_BoneRoot")) { if (child.Find("CC_Base_Hip")) - return BaseGeneration.G3; + { + Material acMat = GetActorCoreSingleMaterial(fbx); + if (acMat) return BaseGeneration.ActorCore; + else return BaseGeneration.G3; + } } } @@ -737,5 +741,80 @@ public static bool IsHairMesh(SkinnedMeshRenderer smr) return false; } + + public static Material GetActorCoreSingleMaterial(GameObject fbx) + { + if (fbx) + { + Material actorCoreMaterial = null; + Transform[] transforms = fbx.GetComponentsInChildren(); + foreach (Transform t in transforms) + { + Renderer r = t.gameObject.GetComponent(); + if (r) + { + if (r.sharedMaterials.Length == 1) + { + if (actorCoreMaterial && actorCoreMaterial != r.sharedMaterials[0]) + return null; + + actorCoreMaterial = r.sharedMaterials[0]; + } + else + { + return null; + } + } + + } + + return actorCoreMaterial; + } + + return null; + } + + public static Material GetActorBuildSingleMaterial(GameObject fbx) + { + if (fbx) + { + bool singleMaterial = true; + Material actorBuildMaterial = null; + Transform[] transforms = fbx.GetComponentsInChildren(); + foreach (Transform t in transforms) + { + switch (t.name) + { + // for a single material actorbuild these should all have the same material + case "CC_Game_Body": + case "CC_Game_Tongue": + case "CC_Base_Eye": + case "CC_Base_Teeth": + case "CC_Base_Tongue": + case "CC_Base_Body": + Renderer r = t.gameObject.GetComponent(); + if (r) + { + if (r.sharedMaterials.Length == 1) + { + if (actorBuildMaterial && actorBuildMaterial != r.sharedMaterials[0]) + singleMaterial = false; + + actorBuildMaterial = r.sharedMaterials[0]; + } + else + { + singleMaterial = false; + } + } + break; + } + } + + if (singleMaterial) return actorBuildMaterial; + } + + return null; + } } } \ No newline at end of file From 8e3aa927cc00d453c391973e317329a3c3eb094e Mon Sep 17 00:00:00 2001 From: soupday <79094830+soupday@users.noreply.github.com> Date: Fri, 2 Dec 2022 04:37:47 +0000 Subject: [PATCH 07/10] 1.4.1 Remembers select linked in character tree view. Bake Hair function now only bakes the 'Enable Color' properties into the diffuse map. (Doesn't bake the entire material as before) GUID remap facility added to CharacterInfo. --- Editor/CharacterInfo.cs | 142 ++++++++++++- Editor/Compute/RLBakeShader.compute | 26 +++ Editor/ComputeBake.cs | 315 +++++++++++++++++++++++----- Editor/Importer.cs | 56 +---- Editor/ImporterWindow.cs | 24 ++- Editor/PreviewScene.cs | 2 +- 6 files changed, 454 insertions(+), 111 deletions(-) diff --git a/Editor/CharacterInfo.cs b/Editor/CharacterInfo.cs index 6537558..50b68e6 100644 --- a/Editor/CharacterInfo.cs +++ b/Editor/CharacterInfo.cs @@ -19,6 +19,7 @@ using System.IO; using UnityEditor; using UnityEngine; +using System.Collections.Generic; namespace Reallusion.Import { @@ -54,6 +55,86 @@ public enum RigOverride { None = 0, Generic, Humanoid } private bool useTessellation = false; private GameObject prefabAsset; + public struct GUIDRemap + { + public string from; + public string to; + + public GUIDRemap(string from, string to) + { + this.from = from; + this.to = to; + } + + public GUIDRemap(Object from, Object to) + { + this.from = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(from)); + this.to = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(to)); + } + } + + private List guidRemaps; + + public void AddGUIDRemap(Object from, Object to) + { + guidRemaps.Add(new GUIDRemap(from, to)); + } + + public Object GetGUIDRemapFrom(Object to) + { + string guidTo = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(to)); + + foreach (GUIDRemap gr in guidRemaps) + { + if (gr.to == guidTo) + { + string path = AssetDatabase.GUIDToAssetPath(gr.from); + if (!string.IsNullOrEmpty(path)) return AssetDatabase.LoadAssetAtPath(path); + else return null; + } + } + + return null; + } + + public Object GetGUIDRemapTo(Object from) + { + string guidFrom = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(from)); + + foreach (GUIDRemap gr in guidRemaps) + { + if (gr.from == guidFrom) + { + string path = AssetDatabase.GUIDToAssetPath(gr.to); + if (!string.IsNullOrEmpty(path)) return AssetDatabase.LoadAssetAtPath(path); + else return null; + } + } + + return null; + } + + public void RemoveGUIDRemap(Object from, Object to) + { + string guidTo = ""; + string guidFrom = ""; + if (to) guidTo = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(to)); + if (from) guidFrom = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(from)); + for (int i = 0; i < guidRemaps.Count; i++) + { + GUIDRemap gr = guidRemaps[i]; + if (gr.from == guidFrom || gr.to == guidTo) + { + guidRemaps.RemoveAt(i--); + } + } + } + + public void CleanGUIDRemaps() + { + RemoveGUIDRemap(null, null); + } + public ProcessingType BuildType { get { return logType; } set { logType = value; } } public MaterialQuality BuildQuality { @@ -138,6 +219,7 @@ public CharacterInfo(string guid) infoFilepath = Path.Combine(folder, name + "_ImportInfo.txt"); jsonFilepath = Path.Combine(folder, name + ".json"); if (path.iContains("_lod")) isLOD = true; + guidRemaps = new List(); if (File.Exists(infoFilepath)) Read(); @@ -148,6 +230,7 @@ public CharacterInfo(string guid) public void ApplySettings() { FixCharSettings(); + CleanGUIDRemaps(); builtLogType = logType; builtQualEyes = qualEyes; @@ -253,6 +336,51 @@ public QuickJSON CharacterJsonData } } + public QuickJSON MeshJsonData + { + get + { + string jsonPath = name + "/Object/" + name + "/Meshes"; + if (JsonData.PathExists(jsonPath)) + return JsonData.GetObjectAtPath(jsonPath); + return null; + } + } + + public QuickJSON GetMatJson(GameObject obj, string sourceName) + { + QuickJSON jsonMeshData = MeshJsonData; + QuickJSON matJson = null; + string objName = obj.name; + string jsonPath = ""; + if (jsonMeshData != null) + { + jsonPath = objName + "/Materials/" + sourceName; + if (jsonMeshData.PathExists(jsonPath)) + { + matJson = jsonMeshData.GetObjectAtPath(jsonPath); + } + else + { + // there is a bug where a space in name causes the name to be truncated on export from CC3/4 + if (objName.Contains(" ")) + { + Util.LogWarn("Object name " + objName + " contains a space, this can cause the materials to setup incorrectly."); + string[] split = objName.Split(' '); + objName = split[0]; + jsonPath = objName + "/Materials/" + sourceName; + if (jsonMeshData.PathExists(jsonPath)) + { + matJson = jsonMeshData.GetObjectAtPath(jsonPath); + } + } + } + } + if (matJson == null) Util.LogError("Unable to find json material data: " + jsonPath); + + return matJson; + } + public QuickJSON PhysicsJsonData { get @@ -366,9 +494,10 @@ public bool CanHaveHighQualityMaterials public void Read() { TextAsset infoAsset = AssetDatabase.LoadAssetAtPath(infoFilepath); - + guidRemaps.Clear(); string[] lineEndings = new string[] { "\r\n", "\r", "\n" }; char[] propertySplit = new char[] { '=' }; + char[] guidSplit = new char[] { '|' }; string[] lines = infoAsset.text.Split(lineEndings, System.StringSplitOptions.None); string property = ""; string value = ""; @@ -433,6 +562,13 @@ public void Read() case "rigOverride": UnknownRigType = (RigOverride)System.Enum.Parse(typeof(RigOverride), value); break; + case "GUIDRemap": + string[] guids = value.Split(guidSplit, System.StringSplitOptions.None); + if (guids.Length == 2) + { + guidRemaps.Add(new GUIDRemap(guids[0], guids[1])); + } + break; } } ApplySettings(); @@ -455,6 +591,10 @@ public void Write() writer.WriteLine("animationSetup=" + (animationSetup ? "true" : "false")); writer.WriteLine("animationRetargeted=" + animationRetargeted.ToString()); writer.WriteLine("rigOverride=" + UnknownRigType.ToString()); + foreach (GUIDRemap gr in guidRemaps) + { + writer.WriteLine("GUIDRemap=" + gr.from + "|" + gr.to); + } writer.Close(); AssetDatabase.ImportAsset(infoFilepath); } diff --git a/Editor/Compute/RLBakeShader.compute b/Editor/Compute/RLBakeShader.compute index 2d81980..e0a9e35 100644 --- a/Editor/Compute/RLBakeShader.compute +++ b/Editor/Compute/RLBakeShader.compute @@ -46,6 +46,7 @@ #pragma kernel RLCorneaThickness #pragma kernel RLCorneaSubsurfaceMask #pragma kernel RLHairColoredDiffuse +#pragma kernel RLHairColoredDiffuseOnly #pragma kernel RLHairDiffuse #pragma kernel RLHairMask #pragma kernel RLHairMetallicGloss @@ -1341,6 +1342,31 @@ void RLHairColoredDiffuse(uint3 id : SV_DispatchThreadID) Result[id.xy] = color; } +[numthreads(1, 1, 1)] +void RLHairColoredDiffuseOnly(uint3 id : SV_DispatchThreadID) +{ + float2 uv = GetUV(id.xy); + + float4 diffuse = SAMPLE(Diffuse, uv); + float4 rootMap = SAMPLE(Root, uv); + float4 idMap = SAMPLE(ID, uv); + + float alpha = pow(saturate((diffuse.a / alphaRemap)), alphaPower); + + float4 color = RootEndBlend(diffuse, rootMap.g); + color = HighlightBlend(color, idMap.g, rootMap.g, highlightAColor, highlightADistribution, + highlightAStrength, highlightAOverlapEnd, highlightAOverlapInvert); + color = HighlightBlend(color, idMap.g, rootMap.g, highlightBColor, highlightBDistribution, + highlightBStrength, highlightBOverlapEnd, highlightBOverlapInvert); + + color = color * diffuseStrength; + + color = LinearTosRGB(color); + color.a = alpha; + + Result[id.xy] = color; +} + [numthreads(1, 1, 1)] void RLHairDiffuse(uint3 id : SV_DispatchThreadID) { diff --git a/Editor/ComputeBake.cs b/Editor/ComputeBake.cs index 9481728..7670e25 100644 --- a/Editor/ComputeBake.cs +++ b/Editor/ComputeBake.cs @@ -62,7 +62,7 @@ public class ComputeBake private bool PARALLAX_EYES => characterInfo.ParallaxEyes; private bool BASIC_EYES => characterInfo.BasicEyes; - public ComputeBake(UnityEngine.Object character, CharacterInfo info) + public ComputeBake(UnityEngine.Object character, CharacterInfo info, string textureFolderOverride = null) { fbx = (GameObject)character; fbxPath = AssetDatabase.GetAssetPath(fbx); @@ -72,7 +72,8 @@ public ComputeBake(UnityEngine.Object character, CharacterInfo info) fbxFolder = Path.GetDirectoryName(fbxPath); bakeFolder = Util.CreateFolder(fbxFolder, BAKE_FOLDER); characterFolder = Util.CreateFolder(bakeFolder, characterName); - texturesFolder = Util.CreateFolder(characterFolder, TEXTURES_FOLDER); + texturesFolder = Util.CreateFolder(characterFolder, + string.IsNullOrEmpty(textureFolderOverride) ? TEXTURES_FOLDER : textureFolderOverride); materialsFolder = Util.CreateFolder(characterFolder, MATERIALS_FOLDER); string parentSourceMaterialsFolder = Util.CreateFolder(fbxFolder, MATERIALS_FOLDER); sourceMaterialsFolder = Util.CreateFolder(parentSourceMaterialsFolder, characterName); @@ -286,18 +287,17 @@ public GameObject BakeHQ() return null; } - public GameObject BakeHQHair() + public GameObject BakeHQHairDiffuse() { if (Util.IsCC3Character(fbx) && prefab) { - if (!CopyToClone(true)) return null; + if (!CopyToClone()) return null; - BakeMaterials(true); + BakeHairDiffuseTextures(); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); - PrefabUtility.ApplyPrefabInstance(clone, InteractionMode.UserAction); GameObject.DestroyImmediate(clone); return prefab; @@ -310,12 +310,13 @@ public GameObject RestoreHQHair() { if (Util.IsCC3Character(fbx) && prefab) { - if (!CopyToClone(true)) return null; + if (!CopyToClone()) return null; + + RestoreHairDiffuseTextures(); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); - - PrefabUtility.ApplyPrefabInstance(clone, InteractionMode.UserAction); + GameObject.DestroyImmediate(clone); return prefab; @@ -324,7 +325,7 @@ public GameObject RestoreHQHair() return null; } - public void BakeMaterials(bool hairOnly = false) + public void BakeMaterials() { Renderer[] renderers = clone.GetComponentsInChildren(); List processed = new List(renderers.Length); @@ -346,48 +347,216 @@ public void BakeMaterials(bool hairOnly = false) Material firstPass = null; Material secondPass = null; - if (!hairOnly) - { - if (shaderName.iContains(Pipeline.SHADER_HQ_SKIN)) - bakedMaterial = BakeSkinMaterial(sharedMat, sourceName); + if (shaderName.iContains(Pipeline.SHADER_HQ_SKIN)) + bakedMaterial = BakeSkinMaterial(sharedMat, sourceName); - else if (shaderName.iContains(Pipeline.SHADER_HQ_TEETH)) - bakedMaterial = BakeTeethMaterial(sharedMat, sourceName); + else if (shaderName.iContains(Pipeline.SHADER_HQ_TEETH)) + bakedMaterial = BakeTeethMaterial(sharedMat, sourceName); - else if (shaderName.iContains(Pipeline.SHADER_HQ_TONGUE)) - bakedMaterial = BakeTongueMaterial(sharedMat, sourceName); + else if (shaderName.iContains(Pipeline.SHADER_HQ_TONGUE)) + bakedMaterial = BakeTongueMaterial(sharedMat, sourceName); - else if (shaderName.iContains(Pipeline.SHADER_HQ_CORNEA) || - shaderName.iContains(Pipeline.SHADER_HQ_CORNEA_PARALLAX) || - shaderName.iContains(Pipeline.SHADER_HQ_CORNEA_REFRACTIVE) || - shaderName.iContains(Pipeline.SHADER_HQ_EYE_REFRACTIVE)) - bakedMaterial = BakeEyeMaterial(sharedMat, sourceName); + else if (shaderName.iContains(Pipeline.SHADER_HQ_CORNEA) || + shaderName.iContains(Pipeline.SHADER_HQ_CORNEA_PARALLAX) || + shaderName.iContains(Pipeline.SHADER_HQ_CORNEA_REFRACTIVE) || + shaderName.iContains(Pipeline.SHADER_HQ_EYE_REFRACTIVE)) + bakedMaterial = BakeEyeMaterial(sharedMat, sourceName); - else if (shaderName.iContains(Pipeline.SHADER_HQ_EYE_OCCLUSION)) - bakedMaterial = BakeEyeOcclusionMaterial(sharedMat, sourceName); - } + else if (shaderName.iContains(Pipeline.SHADER_HQ_EYE_OCCLUSION)) + bakedMaterial = BakeEyeOcclusionMaterial(sharedMat, sourceName); if (shaderName.iContains(Pipeline.SHADER_HQ_HAIR) || shaderName.iContains(Pipeline.SHADER_HQ_HAIR_1ST_PASS) || shaderName.iContains(Pipeline.SHADER_HQ_HAIR_COVERAGE)) + { + if (sourceName.iEndsWith("_2nd_Pass")) continue; + + bakedMaterial = BakeHairMaterial(sharedMat, sourceName, out firstPass, out secondPass); + + if (firstPass && secondPass) + { + ReplaceMaterial(sharedMat, firstPass); + // Get the 2nd pass shared material + foreach (Material secondPassMat in renderer.sharedMaterials) + { + if (secondPassMat != sharedMat && secondPassMat.name.iEndsWith("_2nd_Pass")) + { + ReplaceMaterial(secondPassMat, secondPass); + } + } + } + else if (bakedMaterial) + { + ReplaceMaterial(sharedMat, bakedMaterial); + } + } + } + } + } + } - bakedMaterial = BakeHairMaterial(sharedMat, sourceName, out firstPass, out secondPass); + public void BakeHairDiffuseTextures() + { + Renderer[] renderers = clone.GetComponentsInChildren(); + List processed = new List(renderers.Length); - if (firstPass && secondPass) + foreach (Renderer renderer in renderers) + { + if (renderer) + { + foreach (Material sharedMat in renderer.sharedMaterials) + { + // don't process duplicates... + if (processed.Contains(sharedMat)) continue; + processed.Add(sharedMat); + + // in case any of the materials have been renamed after a previous import, get the source name. + string sourceName = Util.GetSourceMaterialName(fbxPath, sharedMat); + string shaderName = Util.GetShaderName(sharedMat); + + if (shaderName.iContains(Pipeline.SHADER_HQ_HAIR) || + shaderName.iContains(Pipeline.SHADER_HQ_HAIR_1ST_PASS) || + shaderName.iContains(Pipeline.SHADER_HQ_HAIR_COVERAGE)) { - ReplaceMaterial(sharedMat, firstPass); - // Get the 2nd pass shared material - foreach (Material secondPassMat in renderer.sharedMaterials) + if (sourceName.iEndsWith("_2nd_Pass")) continue; + + if (sharedMat.GetFloatIf("BOOLEAN_ENABLECOLOR") > 0f) { - if (secondPassMat != sharedMat && secondPassMat.name.iEndsWith("_2nd_Pass")) + Texture2D sourceMap = (Texture2D)sharedMat.GetTextureIf("_DiffuseMap"); + // bake diffuse map + BakeHairDiffuseOnly(sharedMat, sourceName, out Texture2D bakedMap); + // set baked diffuse map + sharedMat.SetTextureIf("_DiffuseMap", bakedMap); + // turn off enable color + sharedMat.SetFloatIf("BOOLEAN_ENABLECOLOR", 0f); + sharedMat.DisableKeyword("BOOLEAN_ENABLECOLOR_ON"); + Pipeline.ResetMaterial(sharedMat); + // add the texture switch to the character info + characterInfo.AddGUIDRemap(sourceMap, bakedMap); + + if (shaderName.iContains(Pipeline.SHADER_HQ_HAIR_1ST_PASS)) { - ReplaceMaterial(secondPassMat, secondPass); + // replace the diffuse map on the source material (non multi-pass version) + Material sourceMat = GetSourceHairMaterial(sharedMat); + if (sourceMat) + { + // set baked diffuse map + sourceMat.SetTextureIf("_DiffuseMap", bakedMap); + // turn off enable color + sourceMat.SetFloatIf("BOOLEAN_ENABLECOLOR", 0f); + sourceMat.DisableKeyword("BOOLEAN_ENABLECOLOR_ON"); + Pipeline.ResetMaterial(sourceMat); + } + + // Get the 2nd pass shared material + foreach (Material secondPassMat in renderer.sharedMaterials) + { + if (secondPassMat != sharedMat && secondPassMat.name.iEndsWith("_2nd_Pass")) + { + // set baked diffuse map + secondPassMat.SetTextureIf("_DiffuseMap", bakedMap); + // turn off enable color + secondPassMat.SetFloatIf("BOOLEAN_ENABLECOLOR", 0f); + secondPassMat.DisableKeyword("BOOLEAN_ENABLECOLOR_ON"); + Pipeline.ResetMaterial(secondPassMat); + } + } } } } - else if (bakedMaterial) + } + } + } + } + + private Material GetSourceHairMaterial(Material mat) + { + string materialName = mat.name; + string[] folders = new string[] { sourceMaterialsFolder }; + + if (materialName.iContains("_1st_Pass")) + { + materialName = materialName.Substring(0, materialName.IndexOf("_1st_Pass")); + return Util.FindMaterial(materialName, folders); + } + else if (materialName.iContains("_2nd_Pass")) + { + materialName = materialName.Substring(0, materialName.IndexOf("_2nd_Pass")); + return Util.FindMaterial(materialName, folders); + } + else + { + return null; + } + } + + public void RestoreHairDiffuseTextures() + { + Renderer[] renderers = clone.GetComponentsInChildren(); + List processed = new List(renderers.Length); + + foreach (Renderer renderer in renderers) + { + if (renderer) + { + foreach (Material sharedMat in renderer.sharedMaterials) + { + // don't process duplicates... + if (processed.Contains(sharedMat)) continue; + processed.Add(sharedMat); + + // in case any of the materials have been renamed after a previous import, get the source name. + string sourceName = Util.GetSourceMaterialName(fbxPath, sharedMat); + string shaderName = Util.GetShaderName(sharedMat); + + if (shaderName.iContains(Pipeline.SHADER_HQ_HAIR) || + shaderName.iContains(Pipeline.SHADER_HQ_HAIR_1ST_PASS) || + shaderName.iContains(Pipeline.SHADER_HQ_HAIR_COVERAGE)) { - ReplaceMaterial(sharedMat, bakedMaterial); + if (sourceName.iEndsWith("_2nd_Pass")) continue; + + Texture2D bakedMap = (Texture2D)sharedMat.GetTextureIf("_DiffuseMap"); + Texture2D sourceMap = (Texture2D)characterInfo.GetGUIDRemapFrom(bakedMap); + if (sourceMap) + { + // restore source diffuse map + sharedMat.SetTextureIf("_DiffuseMap", sourceMap); + // turn on enable color + sharedMat.SetFloatIf("BOOLEAN_ENABLECOLOR", 1f); + sharedMat.EnableKeyword("BOOLEAN_ENABLECOLOR_ON"); + Pipeline.ResetMaterial(sharedMat); + // remove the texture switch info + characterInfo.RemoveGUIDRemap(sourceMap, bakedMap); + + if (shaderName.iContains(Pipeline.SHADER_HQ_HAIR_1ST_PASS)) + { + // restore the diffuse map on the source material (non multi-pass version) + Material sourceMat = GetSourceHairMaterial(sharedMat); + if (sourceMat) + { + // set source diffuse map + sourceMat.SetTextureIf("_DiffuseMap", sourceMap); + // turn on enable color + sourceMat.SetFloatIf("BOOLEAN_ENABLECOLOR", 1f); + sourceMat.EnableKeyword("BOOLEAN_ENABLECOLOR_ON"); + Pipeline.ResetMaterial(sourceMat); + } + + // Get the 2nd pass shared material + foreach (Material secondPassMat in renderer.sharedMaterials) + { + if (secondPassMat != sharedMat && secondPassMat.name.iEndsWith("_2nd_Pass")) + { + // restore source diffuse map + secondPassMat.SetTextureIf("_DiffuseMap", sourceMap); + // turn on enable color + secondPassMat.SetFloatIf("BOOLEAN_ENABLECOLOR", 1f); + secondPassMat.EnableKeyword("BOOLEAN_ENABLECOLOR_ON"); + Pipeline.ResetMaterial(secondPassMat); + } + } + } + } } } } @@ -412,26 +581,13 @@ private void ReplaceMaterial(Material from, Material to) } } - public bool CopyToClone(bool hairOnly = false) + public bool CopyToClone() { - if (!hairOnly) - { - // don't link the prefab as a variant to the original prefabs as updating the original causes the variants to be reset. - if (prefab) - clone = GameObject.Instantiate(prefab); - else - clone = GameObject.Instantiate(fbx); - } + // don't link the prefab as a variant to the original prefabs as updating the original causes the variants to be reset. + if (prefab) + clone = GameObject.Instantiate(prefab); else - { - if (prefab) - clone = (GameObject)PrefabUtility.InstantiatePrefab(prefab); - else - clone = null; - } - - // put any HQ materials back if replaced by baked materials... - if (clone) RestoreHQMaterials(clone); + clone = GameObject.Instantiate(fbx); return clone != null; } @@ -1496,6 +1652,51 @@ private Material BakeHairMaterial(Material mat, string sourceName, out Material } } + private void BakeHairDiffuseOnly(Material mat, string sourceName, out Texture2D bakedBaseMap) + { + Texture2D diffuse = GetMaterialTexture(mat, "_DiffuseMap"); + Texture2D id = GetMaterialTexture(mat, "_IDMap"); + Texture2D root = GetMaterialTexture(mat, "_RootMap"); + float diffuseStrength = mat.GetFloatIf("_DiffuseStrength"); + float baseColorStrength = mat.GetFloatIf("_BaseColorStrength"); + float globalStrength = mat.GetFloatIf("_GlobalStrength"); + float rootColorStrength = mat.GetFloatIf("_RootColorStrength"); + float endColorStrength = mat.GetFloatIf("_EndColorStrength"); + float invertRootMap = mat.GetFloatIf("_InvertRootMap"); + float highlightBlend = mat.GetFloatIf("_HighlightBlend", 1.0f); + float highlightAStrength = mat.GetFloatIf("_HighlightAStrength"); + float highlightAOverlapEnd = mat.GetFloatIf("_HighlightAOverlapEnd"); + float highlightAOverlapInvert = mat.GetFloatIf("_HighlightAOverlapInvert"); + float highlightBStrength = mat.GetFloatIf("_HighlightBStrength"); + float highlightBOverlapEnd = mat.GetFloatIf("_HighlightBOverlapEnd"); + float highlightBOverlapInvert = mat.GetFloatIf("_HighlightBOverlapInvert"); + Vector4 highlightADistribution = mat.GetVectorIf("_HighlightADistribution"); + Vector4 highlightBDistribution = mat.GetVectorIf("_HighlightBDistribution"); + Color rootColor = mat.GetColorIf("_RootColor", Color.black); + Color endColor = mat.GetColorIf("_EndColor", Color.white); + Color highlightAColor = mat.GetColorIf("_HighlightAColor", Color.white); + Color highlightBColor = mat.GetColorIf("_HighlightBColor", Color.white); + bool enableColor = mat.GetFloatIf("BOOLEAN_ENABLECOLOR") > 0f; + + if (enableColor) + { + bakedBaseMap = BakeHairDiffuseMap(diffuse, null, id, root, null, + 1f, 1f, 1f, 1f, 0f, + rootColor, rootColorStrength, endColor, endColorStrength, globalStrength, + invertRootMap, baseColorStrength, highlightBlend, + highlightAColor, highlightADistribution, highlightAOverlapEnd, + highlightAOverlapInvert, highlightAStrength, + highlightBColor, highlightBDistribution, highlightBOverlapEnd, + highlightBOverlapInvert, highlightBStrength, + 0f, Color.white, 0f, + sourceName + "_BaseMap", "RLHairColoredDiffuseOnly"); + } + else + { + bakedBaseMap = diffuse; + } + } + private Material BakeEyeOcclusionMaterial(Material mat, string sourceName) { float occlusionStrength = mat.GetFloatIf("_OcclusionStrength"); @@ -2623,7 +2824,7 @@ private Texture2D BakeHairDiffuseMap(Texture2D diffuse, Texture2D blend, Texture Color highlightBColor, Vector4 highlightBDistribution, float highlightBOverlapEnd, float highlightBOverlapInvert, float highlightBStrength, float blendStrength, Color vertexBaseColor, float vertexColorStrength, - string name) + string name, string kernelName = "RLHairColoredDiffuse") { Vector2Int maxSize = GetMaxSize(diffuse, id); ComputeBakeTexture bakeTarget = @@ -2641,7 +2842,7 @@ private Texture2D BakeHairDiffuseMap(Texture2D diffuse, Texture2D blend, Texture root = CheckMask(root); mask = CheckMask(mask); - int kernel = bakeShader.FindKernel("RLHairColoredDiffuse"); + int kernel = bakeShader.FindKernel(kernelName); bakeTarget.Create(bakeShader, kernel); bakeShader.SetTexture(kernel, "Diffuse", diffuse); bakeShader.SetTexture(kernel, "ColorBlend", blend); @@ -2684,7 +2885,7 @@ private Texture2D BakeHairDiffuseMap(Texture2D diffuse, Texture2D blend, Texture private Texture2D BakeHairDiffuseMap(Texture2D diffuse, Texture2D blend, Texture2D mask, float diffuseStrength, float alphaPower, float alphaRemap, float aoStrength, float aoOccludeAll, float blendStrength, Color vertexBaseColor, float vertexColorStrength, - string name) + string name, string kernelName = "RLHairDiffuse") { Vector2Int maxSize = GetMaxSize(diffuse); ComputeBakeTexture bakeTarget = @@ -2700,7 +2901,7 @@ private Texture2D BakeHairDiffuseMap(Texture2D diffuse, Texture2D blend, Texture blend = CheckMask(blend); mask = CheckMask(mask); - int kernel = bakeShader.FindKernel("RLHairDiffuse"); + int kernel = bakeShader.FindKernel(kernelName); bakeTarget.Create(bakeShader, kernel); bakeShader.SetTexture(kernel, "Diffuse", diffuse); bakeShader.SetTexture(kernel, "ColorBlend", blend); diff --git a/Editor/Importer.cs b/Editor/Importer.cs index 9454461..d602381 100644 --- a/Editor/Importer.cs +++ b/Editor/Importer.cs @@ -26,8 +26,7 @@ namespace Reallusion.Import public class Importer { private readonly GameObject fbx; - private readonly QuickJSON jsonData; - private readonly QuickJSON jsonMeshData; + private readonly QuickJSON jsonData; private readonly QuickJSON jsonPhysicsData; private readonly string fbxPath; private readonly string fbxFolder; @@ -173,15 +172,9 @@ public Importer(CharacterInfo info) Util.LogInfo("Using material folder: " + materialsFolder); // fetch the character json export data. - jsonData = info.JsonData; - string jsonPath = characterName + "/Object/" + characterName + "/Meshes"; - jsonMeshData = null; - if (jsonData.PathExists(jsonPath)) - jsonMeshData = jsonData.GetObjectAtPath(jsonPath); - else - Util.LogError("Unable to find Json mesh data: " + jsonPath); - - jsonPath = characterName + "/Object/" + characterName + "/Physics"; + jsonData = info.JsonData; + if (info.MeshJsonData == null) Util.LogError("Unable to find Json mesh data!"); + jsonPhysicsData = info.PhysicsJsonData; if (jsonPhysicsData == null) Util.LogWarn("Unable to find Json physics data!"); @@ -374,7 +367,7 @@ private void ProcessObjectBuildPass(Renderer renderer) { // fetch the json parent for this material. // the json data for the material contains custom shader names, parameters and texture paths. - QuickJSON matJson = GetMatJson(obj, sourceName); + QuickJSON matJson = characterInfo.GetMatJson(obj, sourceName); // determine the material type, this dictates the shader and template material. MaterialType materialType = GetMaterialType(obj, sharedMat, sourceName, matJson); @@ -427,7 +420,7 @@ private void ProcessObjectPrepass(Renderer renderer) string sourceName = Util.GetSourceMaterialName(fbxPath, sharedMat); if (!processedBuildMaterials.Contains(sourceName)) { - QuickJSON matJson = GetMatJson(obj, sourceName); + QuickJSON matJson = characterInfo.GetMatJson(obj, sourceName); MaterialType materialType = GetMaterialType(obj, sharedMat, sourceName, matJson); if (matJson != null) @@ -479,7 +472,7 @@ private void ProcessObjectBakePass(Renderer renderer) string sourceName = Util.GetSourceMaterialName(fbxPath, sharedMat); if (!processedBuildMaterials.Contains(sourceName)) { - QuickJSON matJson = GetMatJson(obj, sourceName); + QuickJSON matJson = characterInfo.GetMatJson(obj, sourceName); MaterialType materialType = GetMaterialType(obj, sharedMat, sourceName, matJson); if (matJson != null) @@ -507,40 +500,7 @@ private void ProcessObjectBakePass(Renderer renderer) } } } - } - - private QuickJSON GetMatJson(GameObject obj, string sourceName) - { - QuickJSON matJson = null; - string objName = obj.name; - string jsonPath = ""; - if (jsonMeshData != null) - { - jsonPath = objName + "/Materials/" + sourceName; - if (jsonMeshData.PathExists(jsonPath)) - { - matJson = jsonMeshData.GetObjectAtPath(jsonPath); - } - else - { - // there is a bug where a space in name causes the name to be truncated on export from CC3/4 - if (objName.Contains(" ")) - { - Util.LogWarn("Object name " + objName + " contains a space, this can cause the materials to setup incorrectly."); - string[] split = objName.Split(' '); - objName = split[0]; - jsonPath = objName + "/Materials/" + sourceName; - if (jsonMeshData.PathExists(jsonPath)) - { - matJson = jsonMeshData.GetObjectAtPath(jsonPath); - } - } - } - } - if (matJson == null) Util.LogError("Unable to find json material data: " + jsonPath); - - return matJson; - } + } private MaterialType GetMaterialType(GameObject obj, Material mat, string sourceName, QuickJSON matJson) { diff --git a/Editor/ImporterWindow.cs b/Editor/ImporterWindow.cs index 82de981..a8196ca 100644 --- a/Editor/ImporterWindow.cs +++ b/Editor/ImporterWindow.cs @@ -135,6 +135,21 @@ public static float ICON_AREA_WIDTH } } + public static bool SELECT_LINKED + { + get + { + if (EditorPrefs.HasKey("RL_Importer_SelectLinked")) + return EditorPrefs.GetBool("RL_Importer_SelectLinked"); + return true; + } + + set + { + EditorPrefs.SetBool("RL_Importer_SelectLinked", value); + } + } + public static void StoreBackScene() { Scene currentScene = SceneManager.GetActiveScene(); @@ -899,7 +914,8 @@ private void OnGUITreeViewArea(Rect treeviewBlock) GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); - characterTreeView.selectLinked = GUILayout.Toggle(characterTreeView.selectLinked, "Select Linked"); + SELECT_LINKED = GUILayout.Toggle(SELECT_LINKED, "Select Linked"); + characterTreeView.selectLinked = SELECT_LINKED; GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); @@ -1210,8 +1226,8 @@ private void BakeCharacterHair() WindowManager.HideAnimationPlayer(true); - ComputeBake baker = new ComputeBake(contextCharacter.Fbx, contextCharacter); - GameObject bakedAsset = baker.BakeHQHair(); + ComputeBake baker = new ComputeBake(contextCharacter.Fbx, contextCharacter, "Hair"); + baker.BakeHQHairDiffuse(); contextCharacter.tempHairBake = true; contextCharacter.Write(); @@ -1226,7 +1242,7 @@ private void RestoreCharacterHair() WindowManager.HideAnimationPlayer(true); - ComputeBake baker = new ComputeBake(contextCharacter.Fbx, contextCharacter); + ComputeBake baker = new ComputeBake(contextCharacter.Fbx, contextCharacter, "Hair"); GameObject bakedAsset = baker.RestoreHQHair(); contextCharacter.tempHairBake = false; diff --git a/Editor/PreviewScene.cs b/Editor/PreviewScene.cs index 485205f..00227c5 100644 --- a/Editor/PreviewScene.cs +++ b/Editor/PreviewScene.cs @@ -267,7 +267,7 @@ public void PostProcessingAndLighting() ppl.volumeTrigger = camera.transform; LayerMask everything = ~0; ppl.volumeLayer = everything; - ppl.antialiasingMode = PostProcessLayer.Antialiasing.SubpixelMorphologicalAntialiasing; + ppl.antialiasingMode = PostProcessLayer.Antialiasing.TemporalAntialiasing; ppv.isGlobal = true; ppv.profile = volume; #endif From 8b6f8c0147ecec901948442d71ebc0e289f664fb Mon Sep 17 00:00:00 2001 From: soupday <79094830+soupday@users.noreply.github.com> Date: Fri, 2 Dec 2022 04:56:13 +0000 Subject: [PATCH 08/10] 1.4.1 - --- Editor/Compute/RLBakeShader.compute | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Editor/Compute/RLBakeShader.compute b/Editor/Compute/RLBakeShader.compute index e0a9e35..9512c2f 100644 --- a/Editor/Compute/RLBakeShader.compute +++ b/Editor/Compute/RLBakeShader.compute @@ -1351,15 +1351,13 @@ void RLHairColoredDiffuseOnly(uint3 id : SV_DispatchThreadID) float4 rootMap = SAMPLE(Root, uv); float4 idMap = SAMPLE(ID, uv); - float alpha = pow(saturate((diffuse.a / alphaRemap)), alphaPower); + float alpha = diffuse.a; float4 color = RootEndBlend(diffuse, rootMap.g); color = HighlightBlend(color, idMap.g, rootMap.g, highlightAColor, highlightADistribution, highlightAStrength, highlightAOverlapEnd, highlightAOverlapInvert); color = HighlightBlend(color, idMap.g, rootMap.g, highlightBColor, highlightBDistribution, - highlightBStrength, highlightBOverlapEnd, highlightBOverlapInvert); - - color = color * diffuseStrength; + highlightBStrength, highlightBOverlapEnd, highlightBOverlapInvert); color = LinearTosRGB(color); color.a = alpha; From de3ab5fb635b1f65bc063bda7fa652a94d90702a Mon Sep 17 00:00:00 2001 From: soupday <79094830+soupday@users.noreply.github.com> Date: Fri, 2 Dec 2022 05:31:58 +0000 Subject: [PATCH 09/10] 1.4.1 Changelog --- CHANGELOG.md | 4 +++- Editor/Importer.cs | 35 +++++++++-------------------------- Editor/ImporterWindow.cs | 4 ++-- 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c5a598..59ab29d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ Changelog - Character list sorted alphabetically. - When HDRP Ray tracing is enabled: - The material build function will turn off ray tracing on the Scalp (when separeated), Eye Occlusion and Tearline meshes as it causes darkening artifacts on the underlying skin and eye surfaces. - - (Typically the scalp is only seperated from the hair materials when two-pass hair is enabled) + - (Typically the scalp is only separated from the hair materials when two-pass hair is enabled) +- Bake Hair function now only bakes the result of the 'Enable Color' properties into the diffuse maps of the hair materials. Press again to revert to original diffuse maps. +- Improved ActorCore and ActorBuild single material detection. ### v 1.4.0 - Import & Setup diff --git a/Editor/Importer.cs b/Editor/Importer.cs index d602381..5bf6273 100644 --- a/Editor/Importer.cs +++ b/Editor/Importer.cs @@ -63,8 +63,7 @@ public class Importer public const int FLAG_HAIR_ID = 64; public const int FLAG_WRAP_CLAMP = 1024; - public const float MAX_SMOOTHNESS = 0.897f; - public const float SPECULAR_SCALE = 0.5f; + public const float MAX_SMOOTHNESS = 0.897f; public const float TRA_SPECULAR_SCALE = 0.2f; public static float MIPMAP_BIAS @@ -1132,34 +1131,31 @@ private void ConnectDefaultMaterial(GameObject obj, string sourceName, Material if (matJson != null) { if (matJson.PathExists("Custom Shader/Variable/Micro Roughness Scale")) - { - Color specularColor = Color.white * SPECULAR_SCALE; + { float microRoughnessMod = 0.0f; float specular = 0.5f; if (matJson.PathExists("Custom Shader/Variable/Micro Roughness Scale")) microRoughnessMod = matJson.GetFloatValue("Custom Shader/Variable/Micro Roughness Scale"); if (matJson.PathExists("Custom Shader/Variable/_Specular")) - specular = matJson.GetFloatValue("Custom Shader/Variable/_Specular"); - if (matJson != null && matJson.PathExists("Specular Color")) - specularColor = SPECULAR_SCALE * Util.LinearTosRGB(matJson.GetColorValue("Specular Color")); + specular = matJson.GetFloatValue("Custom Shader/Variable/_Specular"); if (RP == RenderPipeline.HDRP) { - float smoothness = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, mat.GetFloatIf("_Smoothness", 0.5f)); - float smoothnessMin = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, mat.GetFloatIf("_SmoothnessRemapMin", 0f)); - float smoothnessMax = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, mat.GetFloatIf("_SmoothnessRemapMax", MAX_SMOOTHNESS)); + float smoothness = Util.CombineSpecularToSmoothness(specular, mat.GetFloatIf("_Smoothness", 0.5f)); + float smoothnessMin = Util.CombineSpecularToSmoothness(specular, mat.GetFloatIf("_SmoothnessRemapMin", 0f)); + float smoothnessMax = Util.CombineSpecularToSmoothness(specular, mat.GetFloatIf("_SmoothnessRemapMax", MAX_SMOOTHNESS)); mat.SetMinMaxRange("_SmoothnessRemap", smoothnessMin - microRoughnessMod, smoothnessMax - microRoughnessMod); mat.SetFloatIf("_Smoothness", smoothness - microRoughnessMod); } else if (RP == RenderPipeline.URP) { - float smoothness = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, mat.GetFloatIf("_Smoothness", 0.5f)); + float smoothness = Util.CombineSpecularToSmoothness(specular, mat.GetFloatIf("_Smoothness", 0.5f)); mat.SetFloatIf("_Smoothness", smoothness - microRoughnessMod); } else { - float smoothness = Util.CombineSpecularToSmoothness(specularColor.grayscale * specular, mat.GetFloatIf("_GlossMapScale", 0.5f)); + float smoothness = Util.CombineSpecularToSmoothness(specular, mat.GetFloatIf("_GlossMapScale", 0.5f)); mat.SetFloatIf("_GlossMapScale", smoothness - microRoughnessMod); } } @@ -1186,20 +1182,7 @@ private void ConnectDefaultMaterial(GameObject obj, string sourceName, Material mat.SetColorIf("_SpecularColor", specularColor); else mat.SetColorIf("_SpecColor", specularColor); - } - else - { - Color specularColor = Color.white * SPECULAR_SCALE; - - if (matJson.PathExists("Specular Color")) - specularColor = SPECULAR_SCALE * Util.LinearTosRGB(matJson.GetColorValue("Specular Color")); - - float specSmoothness = Util.CombineSpecularToSmoothness(specularColor.grayscale, MAX_SMOOTHNESS); - mat.SetMinMaxRange("_SmoothnessRemap", 0f, specSmoothness); - mat.SetFloatIf("_Smoothness", specSmoothness); - mat.SetFloatIf("_Smoothness", specSmoothness); - mat.SetFloatIf("_GlossMapScale", specSmoothness); - } + } } } diff --git a/Editor/ImporterWindow.cs b/Editor/ImporterWindow.cs index a8196ca..9913880 100644 --- a/Editor/ImporterWindow.cs +++ b/Editor/ImporterWindow.cs @@ -723,7 +723,7 @@ private void OnGUIActionArea(Rect actionBlock) if (contextCharacter.tempHairBake) { - if (GUILayout.Button(new GUIContent(iconActionBakeHairOn, "Restore original hair materials."), + if (GUILayout.Button(new GUIContent(iconActionBakeHairOn, "Restore original hair diffuse textures."), GUILayout.Width(ACTION_BUTTON_SIZE), GUILayout.Height(ACTION_BUTTON_SIZE))) { restoreHairAfterGUI = true; @@ -733,7 +733,7 @@ private void OnGUIActionArea(Rect actionBlock) { if (contextCharacter.BuiltBasicMaterials || !contextCharacter.HasColorEnabledHair()) GUI.enabled = false; - if (GUILayout.Button(new GUIContent(iconActionBakeHair, "Bake hair materials, to preview the baked results of the 'Enable Color' in the hair materials."), + if (GUILayout.Button(new GUIContent(iconActionBakeHair, "Bake hair diffuse textures, to preview the baked results of the 'Enable Color' in the hair materials."), GUILayout.Width(ACTION_BUTTON_SIZE), GUILayout.Height(ACTION_BUTTON_SIZE))) { bakeHairAfterGUI = true; From 37948f60085fec7d0166c22050f28d3c2b85d38b Mon Sep 17 00:00:00 2001 From: soupday <79094830+soupday@users.noreply.github.com> Date: Fri, 2 Dec 2022 06:00:52 +0000 Subject: [PATCH 10/10] 1.4.1 Fixed import of characters with _Motion in the name. --- Editor/RL.cs | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/Editor/RL.cs b/Editor/RL.cs index da52db4..044796e 100644 --- a/Editor/RL.cs +++ b/Editor/RL.cs @@ -532,24 +532,15 @@ public static void ApplyAnimatorController(CharacterInfo info, AnimatorControlle } public static GameObject CreatePrefabFromFbx(CharacterInfo info, GameObject fbx, out GameObject sceneInstance) - { - bool noMotion = !info.name.iContains("_Motion"); - sceneInstance = null; - - if (noMotion) + { + if (info.path.iContains("_lod") && CountLODs(fbx) > 1) { - // Set the Prefab - if (info.path.iContains("_lod") && CountLODs(fbx) > 1) - { - return CreateOneLODPrefabFromModel(info, fbx, "", out sceneInstance); - } - else - { - return CreatePrefabFromModel(info, fbx, out sceneInstance); - } + return CreateOneLODPrefabFromModel(info, fbx, "", out sceneInstance); + } + else + { + return CreatePrefabFromModel(info, fbx, out sceneInstance); } - - return null; } ///