1343 lines
56 KiB
C#
1343 lines
56 KiB
C#
|
using UnityEditor;
|
|||
|
|
|||
|
using System.Collections.Generic;
|
|||
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using UnityEngine;
|
|||
|
using System.IO;
|
|||
|
using System.Runtime.InteropServices;
|
|||
|
|
|||
|
namespace Daz3D
|
|||
|
{
|
|||
|
|
|||
|
[UnityEditor.AssetImporters.ScriptedImporter(1, "dtu", 0x7FFFFFFF)]
|
|||
|
public class Daz3DDTUImporter : UnityEditor.AssetImporters.ScriptedImporter
|
|||
|
{
|
|||
|
public static bool AutoImportDTUChanges = true;
|
|||
|
public static bool GenerateUnityPrefab = true;
|
|||
|
public static bool ReplaceSceneInstances = true;
|
|||
|
public static bool AutomateMecanimAvatarMappings = true;
|
|||
|
public static bool ReplaceMaterials = true;
|
|||
|
public static bool EnableDForceSupport = false;
|
|||
|
public static bool UseNewShaders = false;
|
|||
|
public static void ResetOptions()
|
|||
|
{
|
|||
|
AutoImportDTUChanges = true;
|
|||
|
GenerateUnityPrefab = true;
|
|||
|
ReplaceSceneInstances = true;
|
|||
|
AutomateMecanimAvatarMappings = true;
|
|||
|
ReplaceMaterials = true;
|
|||
|
EnableDForceSupport = false;
|
|||
|
UseNewShaders = false;
|
|||
|
}
|
|||
|
|
|||
|
[Serializable]
|
|||
|
public class ImportEventRecord
|
|||
|
{
|
|||
|
public DateTime Timestamp = DateTime.Now;
|
|||
|
public struct Token
|
|||
|
{
|
|||
|
public string Text;
|
|||
|
public UnityEngine.Object Selectable;
|
|||
|
public bool EndLine;
|
|||
|
}
|
|||
|
|
|||
|
public List<Token> Tokens = new List<Token>();
|
|||
|
|
|||
|
public bool Unfold = true;
|
|||
|
|
|||
|
internal void AddToken(string str, UnityEngine.Object obj = null, bool endline = false)
|
|||
|
{
|
|||
|
Tokens.Add(new Token() { Text = str, Selectable = obj, EndLine = endline });
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public static Queue<ImportEventRecord> EventQueue = new Queue<ImportEventRecord>();
|
|||
|
private static Dictionary<string, Material> s_StandardMaterialCollection = new Dictionary<string, Material>();
|
|||
|
private static MaterialMap _map = null;
|
|||
|
// DB (2021-05-25): dforceImport
|
|||
|
private static DForceMaterialMap _dforceMap = null;
|
|||
|
private const bool ENDLINE = true;
|
|||
|
|
|||
|
public static void EmptyEventQueue()
|
|||
|
{
|
|||
|
EventQueue = new Queue<ImportEventRecord>();
|
|||
|
}
|
|||
|
|
|||
|
public enum DazFigurePlatform
|
|||
|
{
|
|||
|
Genesis8,
|
|||
|
Genesis3,
|
|||
|
Genesis2,
|
|||
|
Victoria,
|
|||
|
Genesis,
|
|||
|
Michael,
|
|||
|
TheFreak,
|
|||
|
Victoria4,
|
|||
|
Victoria4Elite,
|
|||
|
Michael4,
|
|||
|
Michael4Elite,
|
|||
|
Stephanie4,
|
|||
|
Aiko4
|
|||
|
}
|
|||
|
|
|||
|
public static void FoldAll()
|
|||
|
{
|
|||
|
foreach (var record in EventQueue)
|
|||
|
record.Unfold = false;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Method called by Unity Editor when ImportAsset event occurs.
|
|||
|
/// This will probably be the first DTU Brudge code which is executed
|
|||
|
/// when the DTU Bridge is first installed into Unity.
|
|||
|
/// </summary>
|
|||
|
public override void OnImportAsset(UnityEditor.AssetImporters.AssetImportContext ctx)
|
|||
|
{
|
|||
|
if (AutoImportDTUChanges)
|
|||
|
{
|
|||
|
var dtuPath = ctx.assetPath;
|
|||
|
var fbxPath = dtuPath.Replace(".dtu", ".fbx");
|
|||
|
|
|||
|
Import(dtuPath, fbxPath);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[MenuItem("Daz3D/Create Unity Prefab from selected DTU", false, 101)]
|
|||
|
public static void MenuItemConvert()
|
|||
|
{
|
|||
|
var activeObject = Selection.activeObject;
|
|||
|
var dtuPath = AssetDatabase.GetAssetPath(activeObject);
|
|||
|
var fbxPath = dtuPath.Replace(".dtu", ".fbx");
|
|||
|
|
|||
|
Import(dtuPath, fbxPath);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
[MenuItem("Daz3D/Create Unity Prefab from selected DTU", true)]
|
|||
|
[MenuItem("Daz3D/Extract materials from selected DTU", true)]
|
|||
|
[MenuItem("Assets/Daz3D/Create Unity Prefab", true)]
|
|||
|
[MenuItem("Assets/Daz3D/Extract materials", true)]
|
|||
|
public static bool ValidateDTUSelected()
|
|||
|
{
|
|||
|
var obj = Selection.activeObject;
|
|||
|
|
|||
|
// Return false if no transform is selected.
|
|||
|
if (obj == null)
|
|||
|
return false;
|
|||
|
|
|||
|
return (AssetDatabase.GetAssetPath(obj).ToLower().EndsWith(".dtu"));
|
|||
|
}
|
|||
|
|
|||
|
public class MaterialMap
|
|||
|
{
|
|||
|
public MaterialMap(string path)
|
|||
|
{
|
|||
|
Path = path;
|
|||
|
}
|
|||
|
|
|||
|
public void AddMaterial(UnityEngine.Material material)
|
|||
|
{
|
|||
|
if (material && !Map.ContainsKey(material.name))
|
|||
|
Map.Add(material.name, material);
|
|||
|
}
|
|||
|
public string Path { get; set; }
|
|||
|
public Dictionary<string, UnityEngine.Material> Map = new Dictionary<string, UnityEngine.Material>();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public class DForceMaterial
|
|||
|
{
|
|||
|
public DForceMaterial(DTUMaterial dtuMat)
|
|||
|
{
|
|||
|
name = dtuMat.MaterialName;
|
|||
|
dtuMaterial = dtuMat;
|
|||
|
}
|
|||
|
|
|||
|
public string name;
|
|||
|
public DTUMaterial dtuMaterial;
|
|||
|
|
|||
|
/*
|
|||
|
public static bool operator ==(Object x, Object y);
|
|||
|
public static bool operator !=(Object x, Object y);
|
|||
|
public static implicit operator bool(Object exists);
|
|||
|
*/
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
public class DForceMaterialMap
|
|||
|
{
|
|||
|
public DForceMaterialMap(string path)
|
|||
|
{
|
|||
|
Path = path;
|
|||
|
}
|
|||
|
|
|||
|
public void AddMaterial(DForceMaterial dforceMat)
|
|||
|
{
|
|||
|
if (dforceMat == null)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
if (!Map.ContainsKey(dforceMat.name))
|
|||
|
Map.Add(dforceMat.name, dforceMat);
|
|||
|
}
|
|||
|
public string Path { get; set; }
|
|||
|
public Dictionary<string, DForceMaterial> Map = new Dictionary<string, DForceMaterial>();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public static void Import(string dtuPath, string fbxPath)
|
|||
|
{
|
|||
|
DazCoroutine.StartCoroutine(ImportRoutine(dtuPath, fbxPath));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public static bool IsRenderPipelineDetected()
|
|||
|
{
|
|||
|
#if !USING_HDRP && !USING_URP && !USING_BUILTIN
|
|||
|
ImportEventRecord record = new ImportEventRecord();
|
|||
|
EventQueue.Enqueue(record);
|
|||
|
record.AddToken("DTU Bridge must autodetect a RenderPipeline in order to continue.\nThis will involve updating Symbol Definitions and will trigger \nUnity Editor to recompile all scripts.");
|
|||
|
|
|||
|
return false;
|
|||
|
#else
|
|||
|
return true;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
private static IEnumerator ImportRoutine(string dtuPath, string fbxPath)
|
|||
|
{
|
|||
|
//DEBUG
|
|||
|
//Debug.LogError("dtuPath = [" + dtuPath + "] " + dtuPath.Length);
|
|||
|
|
|||
|
Daz3DBridge.ShowWindow();
|
|||
|
|
|||
|
Daz3DBridge.CurrentToolbarMode = Daz3DBridge.ToolbarMode.History; //force into history mode during import
|
|||
|
|
|||
|
Daz3DBridge.Progress = .03f;
|
|||
|
yield return new WaitForEndOfFrame();
|
|||
|
|
|||
|
if (IsRenderPipelineDetected() == false)
|
|||
|
{
|
|||
|
// DB: Write path of asset to be imported in temporary file,
|
|||
|
// this will be restored and continued after global script recompilation takes place.
|
|||
|
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(dtuPath);
|
|||
|
System.IO.File.WriteAllBytes("Assets/Daz3D/Resources/dtu_toload.txt", buffer);
|
|||
|
|
|||
|
yield return new WaitForEndOfFrame();
|
|||
|
|
|||
|
DetectRenderPipeline.RunOnce();
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
_map = new MaterialMap(dtuPath);
|
|||
|
_dforceMap = new DForceMaterialMap(dtuPath);
|
|||
|
|
|||
|
while (!IrayShadersReady())
|
|||
|
yield return new WaitForEndOfFrame();
|
|||
|
|
|||
|
var dtu = new DTU();
|
|||
|
var routine = ImportDTURoutine(dtuPath, (d => dtu = d), .8f);
|
|||
|
while (routine.MoveNext())
|
|||
|
yield return new WaitForEndOfFrame();
|
|||
|
|
|||
|
if (dtu.AssetType == "Animation")
|
|||
|
{
|
|||
|
Daz3DBridge.Progress = 0;
|
|||
|
_map = null;
|
|||
|
_dforceMap = null;
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
//ImportDTU(dtuPath);
|
|||
|
if (dtu.AssetType == null)
|
|||
|
{
|
|||
|
Daz3DBridge.Progress = 0;
|
|||
|
_map = null;
|
|||
|
_dforceMap = null;
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
DazFigurePlatform platform = DiscoverFigurePlatform(dtu);
|
|||
|
|
|||
|
Daz3DBridge.Progress = .9f;
|
|||
|
yield return new WaitForEndOfFrame();
|
|||
|
|
|||
|
if (GenerateUnityPrefab)
|
|||
|
GeneratePrefabFromFBX(fbxPath, platform);
|
|||
|
|
|||
|
Daz3DBridge.Progress = 1f;
|
|||
|
yield return new WaitForEndOfFrame();
|
|||
|
|
|||
|
_map = null;
|
|||
|
_dforceMap = null;
|
|||
|
|
|||
|
Daz3DBridge.Progress = 0;
|
|||
|
|
|||
|
// DB 2021-09-02: Show DTUImport complete dialog
|
|||
|
EditorUtility.DisplayDialog("DTU Bridge Import", "Import Completed for " + dtuPath, "OK");
|
|||
|
|
|||
|
Daz3DBridge.AddDiffusionProfilePrompt();
|
|||
|
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
private static DazFigurePlatform DiscoverFigurePlatform(DTU dtu)
|
|||
|
{
|
|||
|
var token = dtu.AssetID.ToLower();
|
|||
|
|
|||
|
foreach(DazFigurePlatform dfp in Enum.GetValues(typeof (DazFigurePlatform)))
|
|||
|
{
|
|||
|
if (token.Contains(dfp.ToString().ToLower()))
|
|||
|
return dfp;
|
|||
|
}
|
|||
|
|
|||
|
return DazFigurePlatform.Genesis8;//default
|
|||
|
}
|
|||
|
|
|||
|
private static bool IrayShadersReady()
|
|||
|
{
|
|||
|
|
|||
|
#if USING_HDRP || USING_URP || USING_BUILTIN
|
|||
|
if (
|
|||
|
Shader.Find(DTU_Constants.shaderNameMetal) == null ||
|
|||
|
Shader.Find(DTU_Constants.shaderNameSpecular) == null ||
|
|||
|
Shader.Find(DTU_Constants.shaderNameIraySkin) == null ||
|
|||
|
Shader.Find(DTU_Constants.shaderNameHair) == null ||
|
|||
|
Shader.Find(DTU_Constants.shaderNameWet) == null ||
|
|||
|
Shader.Find(DTU_Constants.shaderNameInvisible) == null
|
|||
|
) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
#else
|
|||
|
return false;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
//// unused blocking method
|
|||
|
//public static void ImportDTU(string path)
|
|||
|
//{
|
|||
|
// Debug.Log("ImportDTU for " + path);
|
|||
|
|
|||
|
// FoldAll();
|
|||
|
|
|||
|
// ImportEventRecord record = new ImportEventRecord();
|
|||
|
// EventQueue.Enqueue(record);
|
|||
|
|
|||
|
// var dtu = DTUConverter.ParseDTUFile(path);
|
|||
|
|
|||
|
// var dtuObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);
|
|||
|
|
|||
|
// // DB (2021-05-15): skip anim DTU
|
|||
|
// if (dtu.AssetType == "Animation")
|
|||
|
// {
|
|||
|
// record.AddToken("Skipping prefab creation for animation DTU file: " + path);
|
|||
|
// return;
|
|||
|
// }
|
|||
|
|
|||
|
// record.AddToken("Imported DTU file: " + path);
|
|||
|
// record.AddToken(dtuObject.name, dtuObject, ENDLINE);
|
|||
|
|
|||
|
// //UnityEngine.Debug.Log("DTU: " + dtu.AssetName + " contains: " + dtu.Materials.Count + " materials");
|
|||
|
|
|||
|
// record.AddToken("Generated materials: ");
|
|||
|
// foreach (var dtuMat in dtu.Materials)
|
|||
|
// {
|
|||
|
// var material = dtu.ConvertToUnity(dtuMat);
|
|||
|
// _map.AddMaterial(material);
|
|||
|
|
|||
|
// // DB (2021-05-25): DForce import
|
|||
|
// if (dtu.IsDTUMaterialDForceEnabled(dtuMat))
|
|||
|
// {
|
|||
|
// _dforceMap.AddMaterial(new DForceMaterial(dtuMat));
|
|||
|
// }
|
|||
|
|
|||
|
// record.AddToken(material.name, material);
|
|||
|
// }
|
|||
|
// record.AddToken(" based on DTU file.", null, ENDLINE);
|
|||
|
|
|||
|
|
|||
|
// Daz3DBridge bridge = EditorWindow.GetWindow(typeof(Daz3DBridge)) as Daz3DBridge;
|
|||
|
// if (bridge == null)
|
|||
|
// {
|
|||
|
// var consoleType = Type.GetType("ConsoleWindow,UnityEditor.dll");
|
|||
|
// bridge = EditorWindow.CreateWindow<Daz3DBridge>(new[] { consoleType });
|
|||
|
// }
|
|||
|
|
|||
|
// bridge?.Focus();
|
|||
|
|
|||
|
// //just a safeguard to keep the history data at a managable size (100 records)
|
|||
|
// while (EventQueue.Count > 100)
|
|||
|
// {
|
|||
|
// EventQueue.Dequeue();
|
|||
|
// }
|
|||
|
|
|||
|
//}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
public static IEnumerator ImportDTURoutine(string path, Action<DTU> dtuOut, float progressLimit)
|
|||
|
{
|
|||
|
Debug.Log("ImportDTU for " + path);
|
|||
|
|
|||
|
FoldAll();
|
|||
|
|
|||
|
ImportEventRecord record = new ImportEventRecord();
|
|||
|
EventQueue.Enqueue(record);
|
|||
|
|
|||
|
var dtu = DTUConverter.ParseDTUFile(path);
|
|||
|
|
|||
|
// DB (2021-05-15): skip DTU import if animation
|
|||
|
if (dtu.AssetType == "Animation")
|
|||
|
{
|
|||
|
record.AddToken("Skipping prefab creation for animation DTU file: " + path);
|
|||
|
Daz3DBridge.Progress = 0;
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
dtuOut(dtu);
|
|||
|
|
|||
|
var dtuObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);
|
|||
|
|
|||
|
record.AddToken("Imported DTU file: " + path);
|
|||
|
record.AddToken(dtuObject.name, dtuObject, ENDLINE);
|
|||
|
|
|||
|
//UnityEngine.Debug.Log("DTU: " + dtu.AssetName + " contains: " + dtu.Materials.Count + " materials");
|
|||
|
|
|||
|
|
|||
|
record.AddToken("Generated materials: ");
|
|||
|
float progressIncrement = (progressLimit - Daz3DBridge.Progress) / dtu.Materials.Count;
|
|||
|
|
|||
|
for (int i = 0; i < dtu.Materials.Count; i++)
|
|||
|
{
|
|||
|
var dtuMat = dtu.Materials[i];
|
|||
|
var material = dtu.ConvertToUnity(dtuMat);
|
|||
|
_map.AddMaterial(material);
|
|||
|
|
|||
|
// DB (2021-05-25): DForce import
|
|||
|
if (dtu.IsDTUMaterialDForceEnabled(dtuMat))
|
|||
|
{
|
|||
|
_dforceMap.AddMaterial(new DForceMaterial(dtuMat));
|
|||
|
}
|
|||
|
|
|||
|
record.AddToken(material.name, material);
|
|||
|
|
|||
|
Daz3DBridge.Progress = Mathf.MoveTowards(Daz3DBridge.Progress, progressLimit, progressIncrement);
|
|||
|
|
|||
|
yield return new WaitForEndOfFrame();
|
|||
|
|
|||
|
}
|
|||
|
record.AddToken(" based on DTU file.", null, ENDLINE);
|
|||
|
|
|||
|
|
|||
|
Daz3DBridge bridge = EditorWindow.GetWindow(typeof(Daz3DBridge)) as Daz3DBridge;
|
|||
|
if (bridge == null)
|
|||
|
{
|
|||
|
var consoleType = Type.GetType("ConsoleWindow,UnityEditor.dll");
|
|||
|
bridge = EditorWindow.CreateWindow<Daz3DBridge>(new[] { consoleType });
|
|||
|
}
|
|||
|
|
|||
|
bridge?.Focus();
|
|||
|
|
|||
|
//just a safeguard to keep the history data at a managable size (100 records)
|
|||
|
while (EventQueue.Count > 100)
|
|||
|
{
|
|||
|
EventQueue.Dequeue();
|
|||
|
}
|
|||
|
|
|||
|
yield break;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
enum MaterialID //these positions map to the bitflags in the compiled HDRP lit shader
|
|||
|
{
|
|||
|
SSS = 0,
|
|||
|
Standard = 1,
|
|||
|
Anisotropy = 2,
|
|||
|
Iridescence = 3,
|
|||
|
SpecularColor = 4,
|
|||
|
Translucent = 5
|
|||
|
}
|
|||
|
|
|||
|
private enum StandardMaterialType
|
|||
|
{
|
|||
|
Arms,
|
|||
|
Cornea,
|
|||
|
Ears,
|
|||
|
Eyelashes,
|
|||
|
EyeMoisture_1,
|
|||
|
EyeMoisture,
|
|||
|
EyeSocket,
|
|||
|
Face,
|
|||
|
Fingernails,
|
|||
|
Irises,
|
|||
|
Legs,
|
|||
|
Lips,
|
|||
|
Mouth,
|
|||
|
Pupils,
|
|||
|
Sclera,
|
|||
|
Teeth,
|
|||
|
Toenails,
|
|||
|
Torso
|
|||
|
}
|
|||
|
|
|||
|
public static void GeneratePrefabFromFBX(string fbxPath, DazFigurePlatform platform)
|
|||
|
{
|
|||
|
var fbxPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(fbxPath);
|
|||
|
|
|||
|
if (fbxPrefab == null)
|
|||
|
{
|
|||
|
Debug.LogWarning("no FBX model prefab found at " + fbxPath);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (PrefabUtility.GetPrefabAssetType(fbxPrefab) != PrefabAssetType.Model)
|
|||
|
{
|
|||
|
Debug.LogWarning(fbxPath + " is not a model prefab ");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
System.Reflection.MethodInfo resetPose = null;
|
|||
|
System.Reflection.MethodInfo xferPose = null;
|
|||
|
|
|||
|
var avatarInstance = Instantiate(fbxPrefab);
|
|||
|
avatarInstance.name = "AvatarInstance";
|
|||
|
|
|||
|
if (AutomateMecanimAvatarMappings)
|
|||
|
{
|
|||
|
var record = new ImportEventRecord();
|
|||
|
|
|||
|
ModelImporter importer = GetAtPath(fbxPath) as ModelImporter;
|
|||
|
if (importer)
|
|||
|
{
|
|||
|
var description = importer.humanDescription;
|
|||
|
DescribeHumanJointsForFigure(ref description, platform);
|
|||
|
|
|||
|
importer.humanDescription = description;
|
|||
|
importer.avatarSetup = ModelImporterAvatarSetup.CreateFromThisModel;
|
|||
|
|
|||
|
// Genesis 8 is modeled in A-pose, so we correct to T-pose before configuring avatar joints
|
|||
|
//using Unity's internal MakePoseValid method, which does a perfect job
|
|||
|
if (platform == DazFigurePlatform.Genesis8 && false)
|
|||
|
{
|
|||
|
//use reflection to access AvatarSetupTool;
|
|||
|
var setupToolType = Type.GetType("UnityEditor.AvatarSetupTool,UnityEditor.dll");
|
|||
|
var boneWrapperType = Type.GetType("UnityEditor.AvatarSetupTool+BoneWrapper,UnityEditor.dll");
|
|||
|
|
|||
|
if (boneWrapperType != null && setupToolType != null)
|
|||
|
{
|
|||
|
var existingMappings = new Dictionary<string, string>();
|
|||
|
var human = description.human;
|
|||
|
|
|||
|
for (var i = 0; i < human.Length; ++i)
|
|||
|
existingMappings[human[i].humanName] = human[i].boneName;
|
|||
|
|
|||
|
var getModelBones = setupToolType.GetMethod("GetModelBones");
|
|||
|
var getHumanBones = setupToolType.GetMethod("GetHumanBones", new[] { typeof(Dictionary<string, string>), typeof(Dictionary<Transform, bool>) });
|
|||
|
var makePoseValid = setupToolType.GetMethod("MakePoseValid");
|
|||
|
resetPose = setupToolType.GetMethod("CopyPose");
|
|||
|
xferPose = setupToolType.GetMethod("TransferPoseToDescription");
|
|||
|
|
|||
|
if (getModelBones != null && getHumanBones != null && makePoseValid != null)
|
|||
|
{
|
|||
|
record.AddToken("Corrected Avatar Setup T-pose for Genesis8 figure: ", null);
|
|||
|
record.AddToken(fbxPrefab.name, fbxPrefab, ENDLINE);
|
|||
|
|
|||
|
var modelBones = (Dictionary<Transform, bool>)getModelBones.Invoke(null, new object[] { avatarInstance.transform, false, null });
|
|||
|
var humanBones = (ICollection<object>)getHumanBones.Invoke(null, new object[] { existingMappings, modelBones });
|
|||
|
|
|||
|
// a little dance to populate array of Unity's internal BoneWrapper type
|
|||
|
var humanBonesArray = new object[humanBones.Count];
|
|||
|
humanBones.CopyTo(humanBonesArray, 0);
|
|||
|
Array destinationArray = Array.CreateInstance(boneWrapperType, humanBones.Count);
|
|||
|
Array.Copy(humanBonesArray, destinationArray, humanBones.Count);
|
|||
|
|
|||
|
//This mutates the transforms (modelBones) via Bonewrapper class
|
|||
|
makePoseValid.Invoke(null, new[] { destinationArray });
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
AssetDatabase.WriteImportSettingsIfDirty(fbxPath);
|
|||
|
AssetDatabase.ImportAsset(fbxPath, ImportAssetOptions.ForceUpdate);
|
|||
|
|
|||
|
|
|||
|
// i think this might unT-pose the gen8 skeleton instance
|
|||
|
if (resetPose != null && xferPose != null)
|
|||
|
{
|
|||
|
SerializedObject modelImporterObj = new SerializedObject(importer);
|
|||
|
var skeleton = modelImporterObj?.FindProperty("m_HumanDescription.m_Skeleton");
|
|||
|
|
|||
|
if (skeleton != null)
|
|||
|
{
|
|||
|
resetPose.Invoke(null, new object[] { avatarInstance, fbxPrefab });
|
|||
|
//xferPose.Invoke(null, new object[] { skeleton, avatarInstance.transform });
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DestroyImmediate(avatarInstance);
|
|||
|
|
|||
|
record.AddToken("Automated Mecanim avatar setup for " + fbxPrefab.name + ": ");
|
|||
|
|
|||
|
//a little dance to get the avatar just reimported
|
|||
|
var allAvatars = Resources.FindObjectsOfTypeAll(typeof(Avatar));
|
|||
|
var avatar = Array.Find(allAvatars, element => element.name.StartsWith(fbxPrefab.name));
|
|||
|
if (avatar)
|
|||
|
record.AddToken(avatar.name, avatar, ENDLINE);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Debug.LogWarning("Could not acquire importer for " + fbxPath + " ...could not automatically configure humanoid avatar.");
|
|||
|
record.AddToken("Could not acquire importer for " + fbxPath + " ...could not automatically configure humanoid avatar.", null, ENDLINE);
|
|||
|
}
|
|||
|
|
|||
|
EventQueue.Enqueue(record);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//remap the materials
|
|||
|
var workingInstance = Instantiate(fbxPrefab);
|
|||
|
workingInstance.name = "Daz3d_" + fbxPrefab.name;
|
|||
|
|
|||
|
var renderers = workingInstance.GetComponentsInChildren<Renderer>();
|
|||
|
if (renderers?.Length == 0)
|
|||
|
{
|
|||
|
Debug.LogWarning("no renderers found for material remapping");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
var modelPath = AssetDatabase.GetAssetPath(fbxPrefab);
|
|||
|
|
|||
|
if (ReplaceMaterials)
|
|||
|
{
|
|||
|
foreach (var renderer in renderers)
|
|||
|
{
|
|||
|
var dict = new Dictionary<Material, Material>();
|
|||
|
|
|||
|
if (renderer.name.ToLower().Contains("eyelashes"))
|
|||
|
renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
|||
|
// DB (2021-05-07): SANITY CHECK
|
|||
|
if (renderer.sharedMaterials == null)
|
|||
|
{
|
|||
|
Debug.LogError("DB (2021-05-07), ERROR: GeneratePrefabFromFBX(): sharedMaterials is null!");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
foreach (var keyMat in renderer.sharedMaterials)
|
|||
|
{
|
|||
|
// DB (2021-05-07): SANITY CHECK
|
|||
|
if (keyMat == null)
|
|||
|
{
|
|||
|
Debug.LogError("DB (2021-05-07), ERROR: keyMat is NULL");
|
|||
|
continue;
|
|||
|
}
|
|||
|
var key = keyMat.name;
|
|||
|
|
|||
|
key = Daz3D.Utilities.ScrubKey(key);
|
|||
|
|
|||
|
Material nuMat = null;
|
|||
|
|
|||
|
if (_map != null && _map.Map.ContainsKey(key))
|
|||
|
{
|
|||
|
nuMat = _map.Map[key];// the preferred uber/iRay based material generated by the DTUConverter
|
|||
|
|
|||
|
// DB (2021-05-25): dForce import
|
|||
|
if (_dforceMap.Map.ContainsKey(key))
|
|||
|
{
|
|||
|
if (EnableDForceSupport)
|
|||
|
ImportDforceToPrefab(key, renderer, workingInstance, keyMat);
|
|||
|
|
|||
|
//DForceMaterial dforceMat = _dforceMap.Map[key];
|
|||
|
//GameObject parent = renderer.gameObject;
|
|||
|
//SkinnedMeshRenderer skinned = parent.GetComponent<SkinnedMeshRenderer>();
|
|||
|
//Cloth cloth;
|
|||
|
|
|||
|
//// add Unity Cloth Physics component to gameobject parent of the renderer
|
|||
|
//if (parent.GetComponent<Cloth>() == null)
|
|||
|
//{
|
|||
|
// cloth = parent.AddComponent<Cloth>();
|
|||
|
// // assign values from dtuMat
|
|||
|
// cloth.stretchingStiffness = dforceMat.dtuMaterial.Get("Stretch Stiffness").Float;
|
|||
|
// cloth.bendingStiffness = dforceMat.dtuMaterial.Get("Bend Stiffness").Float;
|
|||
|
// cloth.damping = dforceMat.dtuMaterial.Get("Damping").Float;
|
|||
|
// cloth.friction = dforceMat.dtuMaterial.Get("Friction").Float;
|
|||
|
|
|||
|
// // fix SkinnedMeshRenderer boundaries bug
|
|||
|
// skinned.updateWhenOffscreen = true;
|
|||
|
|
|||
|
// // Add G8F cloth collision rig
|
|||
|
// var searchResult = workingInstance.transform.Find("Cloth Collision Rig");
|
|||
|
// GameObject collision_instance = (searchResult != null) ? searchResult.gameObject : null;
|
|||
|
// if (collision_instance == null)
|
|||
|
// {
|
|||
|
// GameObject collision_prefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Daz3D/Resources/G8F Collision Rig.prefab");
|
|||
|
// collision_instance = Instantiate<GameObject>(collision_prefab);
|
|||
|
// collision_instance.name = "Cloth Collision Rig";
|
|||
|
// collision_instance.transform.parent = workingInstance.transform;
|
|||
|
// // merge cloth collision rig to figure root bone
|
|||
|
// collision_instance.GetComponent<ClothCollisionAssigner>().mergeRig(skinned.rootBone);
|
|||
|
// }
|
|||
|
// ClothCollisionAssigner.ClothConfig clothConfig = new ClothCollisionAssigner.ClothConfig();
|
|||
|
// clothConfig.m_ClothToManage = cloth;
|
|||
|
// clothConfig.m_UpperBody = true;
|
|||
|
// clothConfig.m_LowerBody = true;
|
|||
|
// collision_instance.GetComponent<ClothCollisionAssigner>().addClothConfig(clothConfig);
|
|||
|
|
|||
|
//}
|
|||
|
//else
|
|||
|
//{
|
|||
|
// cloth = parent.GetComponent<Cloth>();
|
|||
|
//}
|
|||
|
|
|||
|
//// add clothtools to gameobject parent of renderer
|
|||
|
//ClothTools clothTools;
|
|||
|
//if (parent.GetComponent<ClothTools>() == null)
|
|||
|
//{
|
|||
|
// clothTools = parent.AddComponent<ClothTools>();
|
|||
|
// clothTools.GenerateLookupTables();
|
|||
|
//}
|
|||
|
//else
|
|||
|
//{
|
|||
|
// clothTools = parent.GetComponent<ClothTools>();
|
|||
|
//}
|
|||
|
|
|||
|
//int matIndex = Array.IndexOf(skinned.sharedMaterials, keyMat);
|
|||
|
//// get vertex list for this material's submesh
|
|||
|
//if (matIndex >= 0)
|
|||
|
//{
|
|||
|
// float simulation_strength;
|
|||
|
// //// map the materical's submesh's vertices to the correct "Dynamics Strength"
|
|||
|
// simulation_strength = dforceMat.dtuMaterial.Get("Dynamics Strength").Float;
|
|||
|
// Debug.Log("DEBUG INFO: simulation strength: " + simulation_strength);
|
|||
|
// //// DEBUG line to map simulation strength to material index
|
|||
|
// //simulation_strength = matIndex;
|
|||
|
|
|||
|
// //// Tiered scaling function
|
|||
|
// float adjusted_simulation_strength;
|
|||
|
// //float strength_max = 1.0f;
|
|||
|
// //float strength_min = 0.0f;
|
|||
|
// float strength_scale_threshold = 0.5f;
|
|||
|
// if (simulation_strength <= strength_scale_threshold)
|
|||
|
// {
|
|||
|
// //// stronger compression of values below threshold
|
|||
|
// float scale = 0.075f;
|
|||
|
// float offset = 0.2f;
|
|||
|
// adjusted_simulation_strength = (simulation_strength - offset) * scale;
|
|||
|
// }
|
|||
|
// else
|
|||
|
// {
|
|||
|
// float offset = (strength_scale_threshold - 0.2f) * 0.075f; // offset = (threshold - previous tier's offset) * previous teir's scale
|
|||
|
// float scale = 0.2f;
|
|||
|
// adjusted_simulation_strength = (simulation_strength - offset) / (1 - offset); // apply offset, then normalize to 1.0
|
|||
|
// adjusted_simulation_strength *= scale;
|
|||
|
// }
|
|||
|
// //// clamp to 0.0f to 0.2f
|
|||
|
// float coeff_min = 0.0f;
|
|||
|
// float coeff_max = 0.2f;
|
|||
|
// adjusted_simulation_strength = (adjusted_simulation_strength > coeff_min) ? adjusted_simulation_strength : coeff_min;
|
|||
|
// adjusted_simulation_strength = (adjusted_simulation_strength < coeff_max) ? adjusted_simulation_strength : coeff_max;
|
|||
|
// //// Debug line for no scaling
|
|||
|
// //adjusted_simulation_strength = simulation_strength;
|
|||
|
|
|||
|
// clothTools.SetSubMeshWeights(matIndex, adjusted_simulation_strength);
|
|||
|
|
|||
|
//}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else if (s_StandardMaterialCollection.ContainsKey(key))
|
|||
|
{
|
|||
|
nuMat = new Material(s_StandardMaterialCollection[key]);
|
|||
|
//FixupStandardBasedMaterial(ref nuMat, fbxPrefab, keyMat.name, data);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
var shader = Shader.Find("HDRP/Lit");
|
|||
|
|
|||
|
if (shader == null)
|
|||
|
{
|
|||
|
Debug.LogWarning("couldn't find HDRP/Lit shader");
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
nuMat = new Material(shader);
|
|||
|
nuMat.CopyPropertiesFromMaterial(keyMat);
|
|||
|
|
|||
|
// just copy the textures, colors and scalars that are appropriate given the base material type
|
|||
|
//DazMaterialPropertiesInfo info = new DazMaterialPropertiesInfo();
|
|||
|
//CustomizeMaterial(ref nuMat, info);
|
|||
|
|
|||
|
var matPath = Path.GetDirectoryName(modelPath);
|
|||
|
matPath = Path.Combine(matPath, fbxPrefab.name + "Daz3D_Materials");
|
|||
|
matPath = AssetDatabase.GenerateUniqueAssetPath(matPath);
|
|||
|
|
|||
|
if (!Directory.Exists(matPath))
|
|||
|
Directory.CreateDirectory(matPath);
|
|||
|
|
|||
|
//Debug.Log("obj path " + path);
|
|||
|
AssetDatabase.CreateAsset(nuMat, matPath + "/Daz3D_" + keyMat.name + ".mat");
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
dict.Add(keyMat, nuMat);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//remap the meshes in the fbx prefab to the value materials in dict
|
|||
|
var count = renderer.sharedMaterials.Length;
|
|||
|
var copy = new Material[count]; //makes a copy
|
|||
|
for (int i = 0; i < count; i++)
|
|||
|
{
|
|||
|
var key = renderer.sharedMaterials[i];
|
|||
|
// DB (2021-05-07): SANITY CHECK
|
|||
|
if (key == null || !dict.ContainsKey(key))
|
|||
|
{
|
|||
|
Debug.LogError("DB (2021-05-07), ERROR: GeneratePrefabFromFBX(): sharedMaterials[" + i + "] (" + renderer.sharedMaterials + ") returned invalid key.");
|
|||
|
if (key != null)
|
|||
|
Debug.LogError(" part 2: key==" + key);
|
|||
|
else
|
|||
|
Debug.LogError(" part 2: key==null");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Debug.Log("remapping: " + renderer.sharedMaterials[i].name + " to " + dict[key].name);
|
|||
|
copy[i] = dict[key];//fill copy
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
renderer.sharedMaterials = copy;//overwrite sharedMaterials, because set indexer assigns to a copy
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//write the prefab to the asset database
|
|||
|
// Make sure the file name is unique, in case an existing Prefab has the same name.
|
|||
|
var nuPrefabPathPath = Path.GetDirectoryName(modelPath);
|
|||
|
nuPrefabPathPath = Path.Combine(nuPrefabPathPath, fbxPrefab.name + "_Prefab");
|
|||
|
nuPrefabPathPath = AssetDatabase.GenerateUniqueAssetPath(nuPrefabPathPath);
|
|||
|
if (!Directory.Exists(nuPrefabPathPath))
|
|||
|
Directory.CreateDirectory(nuPrefabPathPath);
|
|||
|
|
|||
|
nuPrefabPathPath += "/Daz3D_" + fbxPrefab.name + ".prefab";
|
|||
|
|
|||
|
// For future refreshment
|
|||
|
var component = workingInstance.AddComponent<Daz3DInstance>();
|
|||
|
component.SourceFBX = fbxPrefab;
|
|||
|
|
|||
|
// Create the new Prefab.
|
|||
|
var prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(workingInstance, nuPrefabPathPath, InteractionMode.AutomatedAction);
|
|||
|
Selection.activeGameObject = prefab;
|
|||
|
|
|||
|
//now, seek other instance(s) in the scene having been sourced from this fbx asset
|
|||
|
var otherInstances = FindObjectsOfType<Daz3DInstance>();
|
|||
|
int foundCount = 0;
|
|||
|
|
|||
|
var resultingInstance = workingInstance;
|
|||
|
|
|||
|
if (ReplaceSceneInstances)
|
|||
|
{
|
|||
|
foreach (var otherInstance in otherInstances)
|
|||
|
{
|
|||
|
if (otherInstance == component)//ignore this working instance
|
|||
|
continue;
|
|||
|
if (otherInstance.SourceFBX != fbxPrefab)//ignore instances of other assets
|
|||
|
continue;
|
|||
|
|
|||
|
|
|||
|
//for any found that flag ReplaceOnImport, delete that instance and replace with a copy of
|
|||
|
//this one, at their respective transforms
|
|||
|
if (otherInstance.ReplaceOnImport)
|
|||
|
{
|
|||
|
foundCount++;
|
|||
|
var xform = otherInstance.transform;
|
|||
|
var replacementInstance = PrefabUtility.InstantiatePrefab(prefab, xform.parent) as GameObject;
|
|||
|
replacementInstance.transform.position = xform.position;
|
|||
|
replacementInstance.transform.rotation = xform.rotation;
|
|||
|
//var replacementInstance = Instantiate(prefab, xform.position, xform.rotation, xform.parent);
|
|||
|
//PrefabUtility.RevertPrefabInstance(replacementInstance, InteractionMode.AutomatedAction);
|
|||
|
DestroyImmediate(otherInstance.gameObject);
|
|||
|
resultingInstance = replacementInstance;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//if no prior instances found, then don't destroy this instance
|
|||
|
//since it appears to be the first one to arrive
|
|||
|
if (foundCount > 0)
|
|||
|
DestroyImmediate(workingInstance);
|
|||
|
|
|||
|
|
|||
|
ImportEventRecord pfbRecord = new ImportEventRecord();
|
|||
|
pfbRecord.AddToken("Created Unity Prefab: ");
|
|||
|
pfbRecord.AddToken(prefab.name, prefab);
|
|||
|
pfbRecord.AddToken(" and an instance in the scene: ");
|
|||
|
pfbRecord.AddToken(resultingInstance.name, resultingInstance, ENDLINE);
|
|||
|
EventQueue.Enqueue(pfbRecord);
|
|||
|
|
|||
|
//highlight/select the object in the scene view
|
|||
|
Selection.activeGameObject = resultingInstance;
|
|||
|
}
|
|||
|
|
|||
|
private static void ImportDforceToPrefab(string key, Renderer renderer, GameObject workingInstance, Material keyMat)
|
|||
|
{
|
|||
|
DForceMaterial dforceMat = _dforceMap.Map[key];
|
|||
|
GameObject parent = renderer.gameObject;
|
|||
|
SkinnedMeshRenderer skinned = parent.GetComponent<SkinnedMeshRenderer>();
|
|||
|
Cloth cloth;
|
|||
|
|
|||
|
string valueLower = key.ToLower();
|
|||
|
string assetNameLower = parent.name.ToLower();
|
|||
|
string matNameLower = keyMat.name.ToLower();
|
|||
|
if (
|
|||
|
valueLower.Contains("hair") || assetNameLower.EndsWith("hair") || matNameLower.Contains("hair")
|
|||
|
|| valueLower.Contains("moustache") || assetNameLower.EndsWith("moustache") || matNameLower.Contains("moustache")
|
|||
|
|| valueLower.Contains("beard") || assetNameLower.EndsWith("beard") || matNameLower.Contains("beard")
|
|||
|
)
|
|||
|
{
|
|||
|
// TODO: implement dForce hair support
|
|||
|
Debug.LogWarning("Unofficial DTU: ImportDforceToPrefab() dForce hair is currently not supported: " + parent.name);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (skinned == null)
|
|||
|
{
|
|||
|
// TODO: check if regular mesh renderer and upgrade if appropriate
|
|||
|
Debug.LogWarning("Unofficial DTU: ImportDforceToPrefab() gameojbect unsupported: it does not have a skinned mesh renderer: " + parent.name);
|
|||
|
return;
|
|||
|
}
|
|||
|
else if (skinned.sharedMesh.vertexCount > 40000)
|
|||
|
{
|
|||
|
int numverts = skinned.sharedMesh.vertexCount;
|
|||
|
Debug.LogWarning("Unofficial DTU: ImportDforceToPrefab() gameojbect unsupported: too many vertices: " + parent.name + " (" + numverts.ToString() + ")");
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// add Unity Cloth Physics component to gameobject parent of the renderer
|
|||
|
if (parent.GetComponent<Cloth>() == null)
|
|||
|
{
|
|||
|
cloth = parent.AddComponent<Cloth>();
|
|||
|
// assign values from dtuMat
|
|||
|
cloth.stretchingStiffness = dforceMat.dtuMaterial.Get("Stretch Stiffness").Float;
|
|||
|
cloth.bendingStiffness = dforceMat.dtuMaterial.Get("Bend Stiffness").Float;
|
|||
|
cloth.damping = dforceMat.dtuMaterial.Get("Damping").Float;
|
|||
|
cloth.friction = dforceMat.dtuMaterial.Get("Friction").Float;
|
|||
|
|
|||
|
// fix SkinnedMeshRenderer boundaries bug
|
|||
|
skinned.updateWhenOffscreen = true;
|
|||
|
|
|||
|
// Add G8F cloth collision rig
|
|||
|
var searchResult = workingInstance.transform.Find("Cloth Collision Rig");
|
|||
|
GameObject collision_instance = (searchResult != null) ? searchResult.gameObject : null;
|
|||
|
if (collision_instance == null)
|
|||
|
{
|
|||
|
GameObject collision_prefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Daz3D/Resources/G8F Collision Rig.prefab");
|
|||
|
collision_instance = Instantiate<GameObject>(collision_prefab);
|
|||
|
collision_instance.name = "Cloth Collision Rig";
|
|||
|
collision_instance.transform.parent = workingInstance.transform;
|
|||
|
// merge cloth collision rig to figure root bone
|
|||
|
collision_instance.GetComponent<ClothCollisionAssigner>().mergeRig(skinned.rootBone);
|
|||
|
}
|
|||
|
ClothCollisionAssigner.ClothConfig clothConfig = new ClothCollisionAssigner.ClothConfig();
|
|||
|
clothConfig.m_ClothToManage = cloth;
|
|||
|
clothConfig.m_UpperBody = true;
|
|||
|
clothConfig.m_LowerBody = true;
|
|||
|
collision_instance.GetComponent<ClothCollisionAssigner>().addClothConfig(clothConfig);
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
cloth = parent.GetComponent<Cloth>();
|
|||
|
}
|
|||
|
|
|||
|
// add clothtools to gameobject parent of renderer
|
|||
|
ClothTools clothTools;
|
|||
|
if (parent.GetComponent<ClothTools>() == null)
|
|||
|
{
|
|||
|
clothTools = parent.AddComponent<ClothTools>();
|
|||
|
clothTools.GenerateLookupTables();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
clothTools = parent.GetComponent<ClothTools>();
|
|||
|
}
|
|||
|
|
|||
|
int matIndex = Array.IndexOf(skinned.sharedMaterials, keyMat);
|
|||
|
// get vertex list for this material's submesh
|
|||
|
if (matIndex >= 0)
|
|||
|
{
|
|||
|
float simulation_strength;
|
|||
|
//// map the materical's submesh's vertices to the correct "Dynamics Strength"
|
|||
|
simulation_strength = dforceMat.dtuMaterial.Get("Dynamics Strength").Float;
|
|||
|
Debug.Log("DEBUG INFO: simulation strength: " + simulation_strength);
|
|||
|
//// DEBUG line to map simulation strength to material index
|
|||
|
//simulation_strength = matIndex;
|
|||
|
|
|||
|
//// Tiered scaling function
|
|||
|
float adjusted_simulation_strength;
|
|||
|
//float strength_max = 1.0f;
|
|||
|
//float strength_min = 0.0f;
|
|||
|
float strength_scale_threshold = 0.5f;
|
|||
|
if (simulation_strength <= strength_scale_threshold)
|
|||
|
{
|
|||
|
//// stronger compression of values below threshold
|
|||
|
float scale = 0.075f;
|
|||
|
float offset = 0.2f;
|
|||
|
adjusted_simulation_strength = (simulation_strength - offset) * scale;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
float offset = (strength_scale_threshold - 0.2f) * 0.075f; // offset = (threshold - previous tier's offset) * previous teir's scale
|
|||
|
float scale = 0.2f;
|
|||
|
adjusted_simulation_strength = (simulation_strength - offset) / (1 - offset); // apply offset, then normalize to 1.0
|
|||
|
adjusted_simulation_strength *= scale;
|
|||
|
}
|
|||
|
//// clamp to 0.0f to 0.2f
|
|||
|
float coeff_min = 0.0f;
|
|||
|
float coeff_max = 0.2f;
|
|||
|
adjusted_simulation_strength = (adjusted_simulation_strength > coeff_min) ? adjusted_simulation_strength : coeff_min;
|
|||
|
adjusted_simulation_strength = (adjusted_simulation_strength < coeff_max) ? adjusted_simulation_strength : coeff_max;
|
|||
|
//// Debug line for no scaling
|
|||
|
//adjusted_simulation_strength = simulation_strength;
|
|||
|
|
|||
|
clothTools.SetSubMeshWeights(matIndex, adjusted_simulation_strength);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private static void DescribeHumanJointsForFigure(ref HumanDescription description, DazFigurePlatform figure)
|
|||
|
{
|
|||
|
var map = GetJointMapForFigure(figure);
|
|||
|
|
|||
|
HumanBone[] humanBones = new HumanBone[HumanTrait.BoneName.Length];
|
|||
|
int mapIdx = 0;
|
|||
|
|
|||
|
foreach (var humanBoneName in HumanTrait.BoneName)
|
|||
|
{
|
|||
|
if (map.ContainsKey(humanBoneName))
|
|||
|
{
|
|||
|
HumanBone humanBone = new HumanBone();
|
|||
|
humanBone.humanName = humanBoneName;
|
|||
|
humanBone.boneName = map[humanBoneName];
|
|||
|
humanBone.limit.useDefaultValues = true; //todo get limits from dtu?
|
|||
|
humanBones[mapIdx++] = humanBone;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
description.human = humanBones;
|
|||
|
}
|
|||
|
|
|||
|
private static Dictionary<string, string> GetJointMapForFigure(DazFigurePlatform figure)
|
|||
|
{
|
|||
|
Dictionary<string, string> map = new Dictionary<string, string>();
|
|||
|
|
|||
|
switch (figure)
|
|||
|
{
|
|||
|
case DazFigurePlatform.Genesis8:
|
|||
|
case DazFigurePlatform.Genesis3:
|
|||
|
ConfigureGenesisMapStandard(map);
|
|||
|
break;
|
|||
|
|
|||
|
case DazFigurePlatform.Genesis2:
|
|||
|
ConfigureGenesisMapStandard(map);//todo account for Gen2 variances
|
|||
|
break;
|
|||
|
|
|||
|
case DazFigurePlatform.Victoria:
|
|||
|
case DazFigurePlatform.Genesis:
|
|||
|
case DazFigurePlatform.Michael:
|
|||
|
case DazFigurePlatform.TheFreak:
|
|||
|
case DazFigurePlatform.Victoria4:
|
|||
|
case DazFigurePlatform.Victoria4Elite:
|
|||
|
case DazFigurePlatform.Michael4:
|
|||
|
case DazFigurePlatform.Michael4Elite:
|
|||
|
case DazFigurePlatform.Stephanie4:
|
|||
|
case DazFigurePlatform.Aiko4:
|
|||
|
default:
|
|||
|
//do nothing, let unity's excellent guesser handle it
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return map;
|
|||
|
}
|
|||
|
|
|||
|
private static void ConfigureGenesisMapStandard(Dictionary<string, string> map)
|
|||
|
{
|
|||
|
//note: Genesis 3 finger bones have "Carpal#" parents
|
|||
|
|
|||
|
//Body/Body (Gen8)
|
|||
|
map["Hips"] = "hip";
|
|||
|
map["Spine"] = "abdomenUpper";
|
|||
|
map["Chest"] = "chestLower";
|
|||
|
map["UpperChest"] = "chestUpper";
|
|||
|
|
|||
|
//Body/Left Arm (Gen8)
|
|||
|
map["LeftShoulder"] = "lCollar";
|
|||
|
map["LeftUpperArm"] = "lShldrBend";
|
|||
|
map["LeftLowerArm"] = "lForearmBend";
|
|||
|
map["LeftHand"] = "lHand";
|
|||
|
|
|||
|
//Body/Right Arm (Gen8)
|
|||
|
map["RightShoulder"] = "rCollar";
|
|||
|
map["RightUpperArm"] = "rShldrBend";
|
|||
|
map["RightLowerArm"] = "rForearmBend";
|
|||
|
map["RightHand"] = "rHand";
|
|||
|
|
|||
|
//Body/Left Leg (Gen8)
|
|||
|
map["LeftUpperLeg"] = "lThighBend";
|
|||
|
map["LeftLowerLeg"] = "lShin";
|
|||
|
map["LeftFoot"] = "lFoot";
|
|||
|
map["LeftToes"] = "lToe";
|
|||
|
|
|||
|
//Body/Right Leg (Gen8)
|
|||
|
map["RightUpperLeg"] = "rThighBend";
|
|||
|
map["RightLowerLeg"] = "rShin";
|
|||
|
map["RightFoot"] = "rFoot";
|
|||
|
map["RightToes"] = "rToe";
|
|||
|
|
|||
|
//Head (Gen8)
|
|||
|
map["Neck"] = "neckLower";
|
|||
|
map["Head"] = "head";
|
|||
|
map["LeftEye"] = "lEye";
|
|||
|
map["RightEye"] = "rEye";
|
|||
|
map["Jaw"] = "lowerJaw";
|
|||
|
|
|||
|
//Left Hand (Gen8)
|
|||
|
map["Left Thumb Proximal"] = "lThumb1";
|
|||
|
map["Left Thumb Intermediate"] = "lThumb2";
|
|||
|
map["Left Thumb Distal"] = "lThumb3";
|
|||
|
map["Left Index Proximal"] = "lIndex1";
|
|||
|
map["Left Index Intermediate"] = "lIndex2";
|
|||
|
map["Left Index Distal"] = "lIndex3";
|
|||
|
map["Left Middle Proximal"] = "lMid1";
|
|||
|
map["Left Middle Intermediate"] = "lMid2";
|
|||
|
map["Left Middle Distal"] = "lMid3";
|
|||
|
map["Left Ring Proximal"] = "lRing1";
|
|||
|
map["Left Ring Intermediate"] = "lRing2";
|
|||
|
map["Left Ring Distal"] = "lRing3";
|
|||
|
map["Left Little Proximal"] = "lPinky1";
|
|||
|
map["Left Little Intermediate"] = "lPinky2";
|
|||
|
map["Left Little Distal"] = "lPinky3";
|
|||
|
|
|||
|
//Right Hand (Gen8)
|
|||
|
map["Right Thumb Proximal"] = "rThumb1";
|
|||
|
map["Right Thumb Intermediate"] = "rThumb2";
|
|||
|
map["Right Thumb Distal"] = "rThumb3";
|
|||
|
map["Right Index Proximal"] = "rIndex1";
|
|||
|
map["Right Index Intermediate"] = "rIndex2";
|
|||
|
map["Right Index Distal"] = "rIndex3";
|
|||
|
map["Right Middle Proximal"] = "rMid1";
|
|||
|
map["Right Middle Intermediate"] = "rMid2";
|
|||
|
map["Right Middle Distal"] = "rMid3";
|
|||
|
map["Right Ring Proximal"] = "rRing1";
|
|||
|
map["Right Ring Intermediate"] = "rRing2";
|
|||
|
map["Right Ring Distal"] = "rRing3";
|
|||
|
map["Right Little Proximal"] = "rPinky1";
|
|||
|
map["Right Little Intermediate"] = "rPinky2";
|
|||
|
map["Right Little Distal"] = "rPinky3";
|
|||
|
}
|
|||
|
|
|||
|
private void FixupStandardBasedMaterial(ref Material nuMat, GameObject fbxPrefab, string key/*, DTUData data*/)
|
|||
|
{
|
|||
|
////todo need fixup missing textures from the json
|
|||
|
//Debug.LogWarning("dtuData has " + data.Materials.Count + " materials ");
|
|||
|
|
|||
|
//var modelPath = AssetDatabase.GetAssetPath(fbxPrefab);
|
|||
|
//var nuTexturePath = Path.GetDirectoryName(modelPath);
|
|||
|
//nuTexturePath = BuildUnityPath(nuTexturePath, fbxPrefab.name + "Textures___");
|
|||
|
//nuTexturePath = AssetDatabase.GenerateUniqueAssetPath(nuTexturePath);
|
|||
|
|
|||
|
////walk data until find a material named with key
|
|||
|
//foreach (var material in data.Materials)
|
|||
|
//{
|
|||
|
// if (material.MaterialName == key && false) //TODO hack to bypass unfinished fn
|
|||
|
// {
|
|||
|
// //walk properties and work on any with a texture path
|
|||
|
// foreach (var property in material.Properties)
|
|||
|
// {
|
|||
|
// if (!string.IsNullOrEmpty(property.Texture))
|
|||
|
// {
|
|||
|
// //and the daz folder has that texture
|
|||
|
// if (File.Exists(property.Texture))
|
|||
|
// {
|
|||
|
// //copy it into the local textures folder
|
|||
|
// if (!Directory.Exists(nuTexturePath))
|
|||
|
// Directory.CreateDirectory(nuTexturePath);
|
|||
|
|
|||
|
// var nuTextureName = BuildUnityPath(nuTexturePath, Path.GetFileName(property.Texture));
|
|||
|
|
|||
|
// //TODO-----------------------------
|
|||
|
// //todo some diffuse maps are jpg with no alpha channel,
|
|||
|
// //instead use the FBX's embedded/collected texture which already has alpha channel,
|
|||
|
// //test whether that material already has a valid diffuse color texture
|
|||
|
// //if so, reimport that with the importer options below
|
|||
|
|
|||
|
// //copy the texture file from the daz folder to nuTexturePath
|
|||
|
// File.Copy(property.Texture, nuTextureName);
|
|||
|
|
|||
|
// TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(nuTextureName);
|
|||
|
// if (importer != null)
|
|||
|
// {
|
|||
|
// //todo twiddle other switches here, before the reimport happens only once
|
|||
|
// importer.alphaIsTransparency = KeyToTransparency(key);
|
|||
|
// importer.alphaSource = KeyToAlphaSource(key);
|
|||
|
// importer.convertToNormalmap = KeyToNormalMap(key);
|
|||
|
// importer.heightmapScale = KeyToHeightmapScale(key);
|
|||
|
// importer.normalmapFilter = KeyToNormalMapFilter(key);
|
|||
|
// importer.wrapMode = KeyToWrapMode(key);
|
|||
|
|
|||
|
// importer.SaveAndReimport();
|
|||
|
// }
|
|||
|
// else
|
|||
|
// {
|
|||
|
// Debug.LogWarning("texture " + nuTextureName + " is not a project asset.");
|
|||
|
// }
|
|||
|
// }
|
|||
|
// }
|
|||
|
// }
|
|||
|
// }
|
|||
|
//}
|
|||
|
}
|
|||
|
|
|||
|
private TextureImporterAlphaSource KeyToAlphaSource(string key)
|
|||
|
{
|
|||
|
throw new NotImplementedException();
|
|||
|
}
|
|||
|
|
|||
|
private TextureWrapMode KeyToWrapMode(string key)
|
|||
|
{
|
|||
|
throw new NotImplementedException();
|
|||
|
}
|
|||
|
|
|||
|
private TextureImporterNormalFilter KeyToNormalMapFilter(string key)
|
|||
|
{
|
|||
|
throw new NotImplementedException();
|
|||
|
}
|
|||
|
|
|||
|
private float KeyToHeightmapScale(string key)
|
|||
|
{
|
|||
|
throw new NotImplementedException();
|
|||
|
}
|
|||
|
|
|||
|
private bool KeyToNormalMap(string key)
|
|||
|
{
|
|||
|
throw new NotImplementedException();
|
|||
|
}
|
|||
|
|
|||
|
private bool KeyToTransparency(string key)
|
|||
|
{
|
|||
|
throw new NotImplementedException();
|
|||
|
}
|
|||
|
|
|||
|
//private void CustomizeMaterial(ref Material material, DazMaterialPropertiesInfo info)
|
|||
|
//{
|
|||
|
// material.SetColor("_BaseColor", info.BaseColor);
|
|||
|
// material.SetFloat("_SurfaceType", info.Transparent ? 1 : 0); //0 == opaque, 1 == transparent
|
|||
|
|
|||
|
// Texture mainTexture = material.mainTexture;
|
|||
|
// CustomizeTexture(ref mainTexture, info.Transparent);
|
|||
|
|
|||
|
// var normalMap = material.GetTexture("_NormalMap");
|
|||
|
// if (!IsValidNormalMap(normalMap))
|
|||
|
// material.SetTexture("_NormalMap", null);//nuke the invalid normal map, if its a mistake
|
|||
|
|
|||
|
|
|||
|
// material.SetFloat("_Metallic", info.Metallic);
|
|||
|
// material.SetFloat("_Smoothness", info.Smoothness);
|
|||
|
// material.SetInt("_MaterialID", (int)info.MaterialType);
|
|||
|
// material.SetFloat("_DoubleSidedEnable", info.DoubleSided ? 0 : 1);
|
|||
|
//}
|
|||
|
|
|||
|
|
|||
|
void CustomizeTexture(ref Texture texture, bool alphaIsTransparent)
|
|||
|
{
|
|||
|
if (texture != null)
|
|||
|
{
|
|||
|
var texPath = AssetDatabase.GetAssetPath(texture);
|
|||
|
TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(texPath);
|
|||
|
if (importer != null)
|
|||
|
{
|
|||
|
if (alphaIsTransparent && importer.DoesSourceTextureHaveAlpha())
|
|||
|
{
|
|||
|
importer.alphaIsTransparency = true;
|
|||
|
}
|
|||
|
|
|||
|
//todo twiddle other switches here, before the reimport happens only once
|
|||
|
importer.SaveAndReimport();
|
|||
|
}
|
|||
|
else
|
|||
|
Debug.LogWarning("texture " + texture.name + " is not a project asset.");
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
Debug.LogWarning("null texture");
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
bool IsValidNormalMap(Texture normalMap)
|
|||
|
{
|
|||
|
if (normalMap == null)
|
|||
|
return false;
|
|||
|
|
|||
|
var nmPath = AssetDatabase.GetAssetPath(normalMap);
|
|||
|
TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(nmPath);
|
|||
|
if (importer != null)
|
|||
|
{
|
|||
|
var settings = new TextureImporterSettings();
|
|||
|
importer.ReadTextureSettings(settings);
|
|||
|
return settings.textureType == TextureImporterType.NormalMap;
|
|||
|
}
|
|||
|
else
|
|||
|
Debug.LogWarning("texture " + normalMap.name + " is not a project asset.");
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Validated menu item.
|
|||
|
// Add a menu item named "Log Selected Transform Name" to MyMenu in the menu bar.
|
|||
|
// We use a second function to validate the menu item
|
|||
|
// so it will only be enabled if we have a transform selected.
|
|||
|
[MenuItem("Assets/Daz3D/Create Unity Prefab", false, 101)]
|
|||
|
static void DoStuffToSelectedDTU()
|
|||
|
{
|
|||
|
CreateDTUPrefab(Selection.activeObject);
|
|||
|
if (Selection.activeTransform)
|
|||
|
Debug.Log("Selected Transform is on " + Selection.activeTransform.gameObject.name + ".");
|
|||
|
}
|
|||
|
|
|||
|
//// Validate the menu item defined by the function above.
|
|||
|
//// The menu item will be disabled if this function returns false.
|
|||
|
//[MenuItem("Assets/Daz3D/Create Unity Prefab", true)]
|
|||
|
//static bool ValidateDTUSelected2()
|
|||
|
//{
|
|||
|
// return ValidateDTUSelected();
|
|||
|
//}
|
|||
|
|
|||
|
private static void CreateDTUPrefab(UnityEngine.Object activeObject)
|
|||
|
{
|
|||
|
if (activeObject)
|
|||
|
{
|
|||
|
var dtuPath = AssetDatabase.GetAssetPath(activeObject);
|
|||
|
var fbxPath = dtuPath.Replace(".dtu", ".fbx");
|
|||
|
|
|||
|
Import(dtuPath, fbxPath);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|