mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 22:10:32 +02:00
Merge pull request #258 from akamicah/update-unity-avatar-exporter
Update unity avatar exporter
This commit is contained in:
commit
4d782bc28b
4 changed files with 286 additions and 241 deletions
|
@ -2,10 +2,12 @@
|
|||
//
|
||||
// Created by David Back on 28 Nov 2018
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
// Copyright 2022 Overte e.V.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
|
@ -17,7 +19,7 @@ using System.Text.RegularExpressions;
|
|||
|
||||
class AvatarExporter : MonoBehaviour {
|
||||
// update version number for every PR that changes this file, also set updated version in README file
|
||||
static readonly string AVATAR_EXPORTER_VERSION = "0.4.1";
|
||||
static readonly string AVATAR_EXPORTER_VERSION = "0.5.0";
|
||||
|
||||
static readonly float HIPS_MIN_Y_PERCENT_OF_HEIGHT = 0.03f;
|
||||
static readonly float BELOW_GROUND_THRESHOLD_PERCENT_OF_HEIGHT = -0.15f;
|
||||
|
@ -61,7 +63,7 @@ class AvatarExporter : MonoBehaviour {
|
|||
"2017.4.15f1",
|
||||
};
|
||||
|
||||
static readonly Dictionary<string, string> HUMANOID_TO_HIFI_JOINT_NAME = new Dictionary<string, string> {
|
||||
static readonly Dictionary<string, string> HUMANOID_TO_OVERTE_JOINT_NAME = new Dictionary<string, string> {
|
||||
{"Chest", "Spine1"},
|
||||
{"Head", "Head"},
|
||||
{"Hips", "Hips"},
|
||||
|
@ -353,19 +355,19 @@ class AvatarExporter : MonoBehaviour {
|
|||
static GameObject avatarPreviewObject;
|
||||
static GameObject heightReferenceObject;
|
||||
|
||||
[MenuItem("High Fidelity/Export New Avatar")]
|
||||
[MenuItem("Overte/Export New Avatar")]
|
||||
static void ExportNewAvatar() {
|
||||
ExportSelectedAvatar(false);
|
||||
}
|
||||
|
||||
[MenuItem("High Fidelity/Update Existing Avatar")]
|
||||
[MenuItem("Overte/Update Existing Avatar")]
|
||||
static void UpdateAvatar() {
|
||||
ExportSelectedAvatar(true);
|
||||
}
|
||||
|
||||
[MenuItem("High Fidelity/About")]
|
||||
[MenuItem("Overte/About")]
|
||||
static void About() {
|
||||
EditorUtility.DisplayDialog("About", "High Fidelity, Inc.\nAvatar Exporter\nVersion " + AVATAR_EXPORTER_VERSION, "Ok");
|
||||
EditorUtility.DisplayDialog("About", "Avatar Exporter\nVersion " + AVATAR_EXPORTER_VERSION + "\nCopyright 2022 Overte e.V.\nCopyright 2018 High Fidelity, Inc.", "Ok");
|
||||
}
|
||||
|
||||
static void ExportSelectedAvatar(bool updateExistingAvatar) {
|
||||
|
@ -462,23 +464,23 @@ class AvatarExporter : MonoBehaviour {
|
|||
}
|
||||
|
||||
string documentsFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
|
||||
string hifiFolder = documentsFolder + "\\High Fidelity Projects";
|
||||
string overteFolder = documentsFolder + "/Overte Projects";
|
||||
if (updateExistingAvatar) { // Update Existing Avatar menu option
|
||||
// open update existing project popup window including project to update, scale, and warnings
|
||||
// default the initial file chooser location to HiFi projects folder in user documents folder
|
||||
// default the initial file chooser location to Overte Projects folder in user documents folder
|
||||
ExportProjectWindow window = ScriptableObject.CreateInstance<ExportProjectWindow>();
|
||||
string initialPath = Directory.Exists(hifiFolder) ? hifiFolder : documentsFolder;
|
||||
string initialPath = Directory.Exists(overteFolder) ? overteFolder : documentsFolder;
|
||||
window.Init(initialPath, warnings, updateExistingAvatar, avatarPreviewObject, OnUpdateExistingProject, OnExportWindowClose);
|
||||
} else { // Export New Avatar menu option
|
||||
// create High Fidelity Projects folder in user documents folder if it doesn't exist
|
||||
if (!Directory.Exists(hifiFolder)) {
|
||||
Directory.CreateDirectory(hifiFolder);
|
||||
// create Overte Projects folder in user documents folder if it doesn't exist
|
||||
if (!Directory.Exists(overteFolder)) {
|
||||
Directory.CreateDirectory(overteFolder);
|
||||
}
|
||||
|
||||
// open export new project popup window including project name, project location, scale, and warnings
|
||||
// default the initial project location path to the High Fidelity Projects folder above
|
||||
// default the initial project location path to the Overte Projects folder above
|
||||
ExportProjectWindow window = ScriptableObject.CreateInstance<ExportProjectWindow>();
|
||||
window.Init(hifiFolder, warnings, updateExistingAvatar, avatarPreviewObject, OnExportNewProject, OnExportWindowClose);
|
||||
window.Init(overteFolder, warnings, updateExistingAvatar, avatarPreviewObject, OnExportNewProject, OnExportWindowClose);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -505,7 +507,7 @@ class AvatarExporter : MonoBehaviour {
|
|||
return;
|
||||
}
|
||||
|
||||
string exportModelPath = Path.GetDirectoryName(exportFstPath) + "\\" + assetName + ".fbx";
|
||||
string exportModelPath = Path.GetDirectoryName(exportFstPath) + "/" + assetName + ".fbx";
|
||||
if (File.Exists(exportModelPath)) {
|
||||
// if the fbx in Unity Assets is newer than the fbx in the target export
|
||||
// folder or vice-versa then ask to replace the older fbx with the newer fbx
|
||||
|
@ -608,7 +610,7 @@ class AvatarExporter : MonoBehaviour {
|
|||
|
||||
// create empty Textures and Scripts folders in the project directory
|
||||
string texturesDirectory = GetTextureDirectory(projectDirectory);
|
||||
string scriptsDirectory = projectDirectory + "\\scripts";
|
||||
string scriptsDirectory = projectDirectory + "/scripts";
|
||||
Directory.CreateDirectory(texturesDirectory);
|
||||
Directory.CreateDirectory(scriptsDirectory);
|
||||
|
||||
|
@ -639,7 +641,7 @@ class AvatarExporter : MonoBehaviour {
|
|||
ClosePreviewScene();
|
||||
}
|
||||
|
||||
// The High Fidelity FBX Serializer omits the colon based prefixes. This will make the jointnames compatible.
|
||||
// The Overte FBX Serializer omits the colon based prefixes. This will make the jointnames compatible.
|
||||
static string removeTypeFromJointname(string jointName) {
|
||||
return jointName.Substring(jointName.IndexOf(':') + 1);
|
||||
}
|
||||
|
@ -659,8 +661,8 @@ class AvatarExporter : MonoBehaviour {
|
|||
// write out joint mappings to fst file
|
||||
foreach (var userBoneInfo in userBoneInfos) {
|
||||
if (userBoneInfo.Value.HasHumanMapping()) {
|
||||
string hifiJointName = HUMANOID_TO_HIFI_JOINT_NAME[userBoneInfo.Value.humanName];
|
||||
File.AppendAllText(exportFstPath, "jointMap = " + hifiJointName + " = " + removeTypeFromJointname(userBoneInfo.Key) + "\n");
|
||||
string overteJointName = HUMANOID_TO_OVERTE_JOINT_NAME[userBoneInfo.Value.humanName];
|
||||
File.AppendAllText(exportFstPath, "jointMap = " + overteJointName + " = " + removeTypeFromJointname(userBoneInfo.Key) + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -699,7 +701,7 @@ class AvatarExporter : MonoBehaviour {
|
|||
}
|
||||
}
|
||||
|
||||
// swap from left-handed (Unity) to right-handed (HiFi) coordinates and write out joint rotation offset to fst
|
||||
// swap from left-handed (Unity) to right-handed (Overte) coordinates and write out joint rotation offset to fst
|
||||
jointOffset = new Quaternion(-jointOffset.x, jointOffset.y, jointOffset.z, -jointOffset.w);
|
||||
File.AppendAllText(exportFstPath, "jointRotationOffset2 = " + removeTypeFromJointname(userBoneName) + " = (" + jointOffset.x + ", " +
|
||||
jointOffset.y + ", " + jointOffset.z + ", " + jointOffset.w + ")\n");
|
||||
|
@ -725,8 +727,10 @@ class AvatarExporter : MonoBehaviour {
|
|||
File.AppendAllText(exportFstPath, "materialMap = " + materialJson);
|
||||
}
|
||||
|
||||
if(SystemInfo.operatingSystemFamily == OperatingSystemFamily.Windows) {
|
||||
// open File Explorer to the project directory once finished
|
||||
System.Diagnostics.Process.Start("explorer.exe", "/select," + exportFstPath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -756,10 +760,10 @@ class AvatarExporter : MonoBehaviour {
|
|||
foreach (HumanBone bone in boneMap) {
|
||||
string humanName = bone.humanName;
|
||||
string userBoneName = bone.boneName;
|
||||
string hifiJointName;
|
||||
string overteJointName;
|
||||
if (userBoneInfos.ContainsKey(userBoneName)) {
|
||||
++userBoneInfos[userBoneName].mappingCount;
|
||||
if (HUMANOID_TO_HIFI_JOINT_NAME.TryGetValue(humanName, out hifiJointName)) {
|
||||
if (HUMANOID_TO_OVERTE_JOINT_NAME.TryGetValue(humanName, out overteJointName)) {
|
||||
userBoneInfos[userBoneName].humanName = humanName;
|
||||
humanoidToUserBoneMappings.Add(humanName, userBoneName);
|
||||
}
|
||||
|
@ -1135,8 +1139,8 @@ class AvatarExporter : MonoBehaviour {
|
|||
}
|
||||
|
||||
static string GetTextureDirectory(string basePath) {
|
||||
string textureDirectory = Path.GetDirectoryName(basePath) + "\\" + TEXTURES_DIRECTORY;
|
||||
textureDirectory = textureDirectory.Replace("\\\\", "\\");
|
||||
string textureDirectory = Path.GetDirectoryName(basePath) + "/" + TEXTURES_DIRECTORY;
|
||||
textureDirectory = textureDirectory.Replace("//", "/");
|
||||
return textureDirectory;
|
||||
}
|
||||
|
||||
|
@ -1166,7 +1170,7 @@ class AvatarExporter : MonoBehaviour {
|
|||
static bool CopyExternalTextures(string texturesDirectory) {
|
||||
// copy the found dependency textures from the local asset folder to the textures folder in the target export project
|
||||
foreach (var texture in textureDependencies) {
|
||||
string targetPath = texturesDirectory + "\\" + texture.Key;
|
||||
string targetPath = texturesDirectory + "/" + texture.Key;
|
||||
try {
|
||||
File.Copy(texture.Value, targetPath, true);
|
||||
} catch {
|
||||
|
@ -1474,7 +1478,7 @@ class ExportProjectWindow : EditorWindow {
|
|||
if (GUILayout.Button("Browse", buttonStyle)) {
|
||||
string result = "";
|
||||
if (updateExistingAvatar) {
|
||||
// open file explorer starting at hifi projects folder in user documents and select target fst to update
|
||||
// open file explorer starting at overte projects folder in user documents and select target fst to update
|
||||
string initialPath = string.IsNullOrEmpty(projectLocation) ? initialProjectLocation : projectLocation;
|
||||
result = EditorUtility.OpenFilePanel("Select .fst to update", initialPath, "fst");
|
||||
} else {
|
||||
|
@ -1482,7 +1486,7 @@ class ExportProjectWindow : EditorWindow {
|
|||
result = EditorUtility.OpenFolderPanel("Select export location", projectLocation, "");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(result)) { // file/folder selection not cancelled
|
||||
projectLocation = result.Replace('/', '\\');
|
||||
projectLocation = result.Replace('\\', '/');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1511,8 +1515,10 @@ class ExportProjectWindow : EditorWindow {
|
|||
GUILayout.Space(15);
|
||||
|
||||
// red error label text to display any file-related errors
|
||||
if(errorText != EMPTY_ERROR_TEXT) {
|
||||
GUILayout.Label("Error:", errorStyle);
|
||||
GUILayout.Label(errorText, errorStyle);
|
||||
}
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
|
@ -1561,7 +1567,7 @@ class ExportProjectWindow : EditorWindow {
|
|||
return true;
|
||||
}
|
||||
} else {
|
||||
projectDirectory = projectLocation + "\\" + projectName + "\\";
|
||||
projectDirectory = projectLocation + "/" + projectName + "/";
|
||||
if (projectName.Length > 0) {
|
||||
// new project must have a unique folder name since the folder will be created for it
|
||||
if (Directory.Exists(projectDirectory)) {
|
||||
|
@ -1571,12 +1577,20 @@ class ExportProjectWindow : EditorWindow {
|
|||
}
|
||||
}
|
||||
if (projectLocation.Length > 0) {
|
||||
// before clicking Export we can verify that the project location at least starts with a drive
|
||||
// Check to ensure provided path is absolute, not relative.
|
||||
if(SystemInfo.operatingSystemFamily == OperatingSystemFamily.Windows) {
|
||||
if (!Char.IsLetter(projectLocation[0]) || projectLocation.Length == 1 || projectLocation[1] != ':') {
|
||||
errorText = "Project location is invalid. Please choose a different project location.\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (projectLocation[0] != '/') {
|
||||
errorText = "Project location is invalid. Please choose a different project location.\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exporting) {
|
||||
// when exporting, project name and location must both be defined, and project location must
|
||||
// be valid and accessible (we attempt to create the project folder at this time to verify this)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
High Fidelity, Inc.
|
||||
Avatar Exporter
|
||||
Version 0.4.1
|
||||
Version 0.5.0
|
||||
Copyright 2018 High Fidelity, Inc.
|
||||
Copyright 2022 Overte e.V.
|
||||
|
||||
Note: It is recommended to use Unity versions between 2017.4.15f1 and 2018.2.12f1 for this Avatar Exporter.
|
||||
|
||||
|
@ -21,4 +22,4 @@ To update an existing avatar project:
|
|||
* WARNING *
|
||||
If you are using any external textures as part of your .fbx model, be sure they are copied into the textures folder that is created in the project folder after exporting a new avatar.
|
||||
|
||||
For further details including troubleshooting tips, see the full documentation at https://docs.highfidelity.com/create-and-explore/avatars/create-avatars/unity-extension
|
||||
For further details including troubleshooting tips, see the full documentation at https://docs.overte.org/create/avatars/find-avatars.html#overte-avatar-exporter-for-unity
|
||||
|
|
Binary file not shown.
30
tools/unity-avatar-exporter/packager.sh
Executable file
30
tools/unity-avatar-exporter/packager.sh
Executable file
|
@ -0,0 +1,30 @@
|
|||
#!/bin/bash
|
||||
|
||||
projectPath=$(dirname $0)
|
||||
|
||||
helpFunction()
|
||||
{
|
||||
echo ""
|
||||
echo "Usage: $0 -u <UnityPath> -p <ProjectPath>"
|
||||
echo -e "\t-u The path in which Unity exists"
|
||||
echo -e "\t-p The path to build the project files (Default: ${projectPath})"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
while getopts "u:p" opt
|
||||
do
|
||||
case "$opt" in
|
||||
u ) unityPath="$OPTARG" ;;
|
||||
p ) projectPath="$OPTARG" ;;
|
||||
? ) helpFunction ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$unityPath" ]
|
||||
then
|
||||
echo "Unity path was not provided";
|
||||
helpFunction
|
||||
fi
|
||||
|
||||
${unityPath}/Unity -quit -batchmode -projectPath ${projectPath} -exportPackage "Assets" "avatarExporter.unitypackage"
|
Loading…
Reference in a new issue