mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-06-16 10:08:47 +02:00
avatar exporter 0.3.4/0.3.5 changes to master
This commit is contained in:
parent
58146063db
commit
f9f2b6f8ac
9 changed files with 2296 additions and 257 deletions
|
@ -6,15 +6,18 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
using UnityEditor.SceneManagement;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
class AvatarExporter : MonoBehaviour {
|
class AvatarExporter : MonoBehaviour {
|
||||||
// update version number for every PR that changes this file, also set updated version in README file
|
// update version number for every PR that changes this file, also set updated version in README file
|
||||||
static readonly string AVATAR_EXPORTER_VERSION = "0.3.3";
|
static readonly string AVATAR_EXPORTER_VERSION = "0.3.5";
|
||||||
|
|
||||||
static readonly float HIPS_GROUND_MIN_Y = 0.01f;
|
static readonly float HIPS_GROUND_MIN_Y = 0.01f;
|
||||||
static readonly float HIPS_SPINE_CHEST_MIN_SEPARATION = 0.001f;
|
static readonly float HIPS_SPINE_CHEST_MIN_SEPARATION = 0.001f;
|
||||||
|
@ -22,6 +25,9 @@ class AvatarExporter : MonoBehaviour {
|
||||||
static readonly string EMPTY_WARNING_TEXT = "None";
|
static readonly string EMPTY_WARNING_TEXT = "None";
|
||||||
static readonly string TEXTURES_DIRECTORY = "textures";
|
static readonly string TEXTURES_DIRECTORY = "textures";
|
||||||
static readonly string DEFAULT_MATERIAL_NAME = "No Name";
|
static readonly string DEFAULT_MATERIAL_NAME = "No Name";
|
||||||
|
static readonly string HEIGHT_REFERENCE_PREFAB = "Assets/Editor/AvatarExporter/HeightReference.prefab";
|
||||||
|
static readonly Vector3 PREVIEW_CAMERA_PIVOT = new Vector3(0.0f, 1.755f, 0.0f);
|
||||||
|
static readonly Vector3 PREVIEW_CAMERA_DIRECTION = new Vector3(0.0f, 0.0f, -1.0f);
|
||||||
|
|
||||||
// TODO: use regex
|
// TODO: use regex
|
||||||
static readonly string[] RECOMMENDED_UNITY_VERSIONS = new string[] {
|
static readonly string[] RECOMMENDED_UNITY_VERSIONS = new string[] {
|
||||||
|
@ -298,18 +304,17 @@ class AvatarExporter : MonoBehaviour {
|
||||||
if (!string.IsNullOrEmpty(occlusionMap)) {
|
if (!string.IsNullOrEmpty(occlusionMap)) {
|
||||||
json += "\"occlusionMap\": \"" + occlusionMap + "\", ";
|
json += "\"occlusionMap\": \"" + occlusionMap + "\", ";
|
||||||
}
|
}
|
||||||
json += "\"emissive\": [" + emissive.r + ", " + emissive.g + ", " + emissive.b + "] ";
|
json += "\"emissive\": [" + emissive.r + ", " + emissive.g + ", " + emissive.b + "]";
|
||||||
if (!string.IsNullOrEmpty(emissiveMap)) {
|
if (!string.IsNullOrEmpty(emissiveMap)) {
|
||||||
json += "\", emissiveMap\": \"" + emissiveMap + "\"";
|
json += ", \"emissiveMap\": \"" + emissiveMap + "\"";
|
||||||
}
|
}
|
||||||
json += "} }";
|
json += " } }";
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static string assetPath = "";
|
static string assetPath = "";
|
||||||
static string assetName = "";
|
static string assetName = "";
|
||||||
|
|
||||||
static ModelImporter modelImporter;
|
static ModelImporter modelImporter;
|
||||||
static HumanDescription humanDescription;
|
static HumanDescription humanDescription;
|
||||||
|
|
||||||
|
@ -317,12 +322,23 @@ class AvatarExporter : MonoBehaviour {
|
||||||
static Dictionary<string, string> humanoidToUserBoneMappings = new Dictionary<string, string>();
|
static Dictionary<string, string> humanoidToUserBoneMappings = new Dictionary<string, string>();
|
||||||
static BoneTreeNode userBoneTree = new BoneTreeNode();
|
static BoneTreeNode userBoneTree = new BoneTreeNode();
|
||||||
static Dictionary<AvatarRule, string> failedAvatarRules = new Dictionary<AvatarRule, string>();
|
static Dictionary<AvatarRule, string> failedAvatarRules = new Dictionary<AvatarRule, string>();
|
||||||
|
static string warnings = "";
|
||||||
|
|
||||||
static Dictionary<string, string> textureDependencies = new Dictionary<string, string>();
|
static Dictionary<string, string> textureDependencies = new Dictionary<string, string>();
|
||||||
static Dictionary<string, string> materialMappings = new Dictionary<string, string>();
|
static Dictionary<string, string> materialMappings = new Dictionary<string, string>();
|
||||||
static Dictionary<string, MaterialData> materialDatas = new Dictionary<string, MaterialData>();
|
static Dictionary<string, MaterialData> materialDatas = new Dictionary<string, MaterialData>();
|
||||||
static List<string> materialAlternateStandardShader = new List<string>();
|
static List<string> alternateStandardShaderMaterials = new List<string>();
|
||||||
static Dictionary<string, string> materialUnsupportedShader = new Dictionary<string, string>();
|
static List<string> unsupportedShaderMaterials = new List<string>();
|
||||||
|
|
||||||
|
static Scene previewScene;
|
||||||
|
static string previousScene = "";
|
||||||
|
static Vector3 previousScenePivot = Vector3.zero;
|
||||||
|
static Quaternion previousSceneRotation = Quaternion.identity;
|
||||||
|
static float previousSceneSize = 0.0f;
|
||||||
|
static bool previousSceneOrthographic = false;
|
||||||
|
static UnityEngine.Object avatarResource;
|
||||||
|
static GameObject avatarPreviewObject;
|
||||||
|
static GameObject heightReferenceObject;
|
||||||
|
|
||||||
[MenuItem("High Fidelity/Export New Avatar")]
|
[MenuItem("High Fidelity/Export New Avatar")]
|
||||||
static void ExportNewAvatar() {
|
static void ExportNewAvatar() {
|
||||||
|
@ -339,8 +355,8 @@ class AvatarExporter : MonoBehaviour {
|
||||||
EditorUtility.DisplayDialog("About", "High Fidelity, Inc.\nAvatar Exporter\nVersion " + AVATAR_EXPORTER_VERSION, "Ok");
|
EditorUtility.DisplayDialog("About", "High Fidelity, Inc.\nAvatar Exporter\nVersion " + AVATAR_EXPORTER_VERSION, "Ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExportSelectedAvatar(bool updateAvatar) {
|
static void ExportSelectedAvatar(bool updateExistingAvatar) {
|
||||||
// ensure everything is saved to file before exporting
|
// ensure everything is saved to file before doing anything
|
||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
string[] guids = Selection.assetGUIDs;
|
string[] guids = Selection.assetGUIDs;
|
||||||
|
@ -365,6 +381,11 @@ class AvatarExporter : MonoBehaviour {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
avatarResource = AssetDatabase.LoadAssetAtPath(assetPath, typeof(UnityEngine.Object));
|
||||||
|
humanDescription = modelImporter.humanDescription;
|
||||||
|
|
||||||
|
string textureWarnings = SetTextureDependencies();
|
||||||
|
|
||||||
// if the rig is optimized we should de-optimize it during the export process
|
// if the rig is optimized we should de-optimize it during the export process
|
||||||
bool shouldDeoptimizeGameObjects = modelImporter.optimizeGameObjects;
|
bool shouldDeoptimizeGameObjects = modelImporter.optimizeGameObjects;
|
||||||
if (shouldDeoptimizeGameObjects) {
|
if (shouldDeoptimizeGameObjects) {
|
||||||
|
@ -372,27 +393,22 @@ class AvatarExporter : MonoBehaviour {
|
||||||
modelImporter.SaveAndReimport();
|
modelImporter.SaveAndReimport();
|
||||||
}
|
}
|
||||||
|
|
||||||
humanDescription = modelImporter.humanDescription;
|
|
||||||
string textureWarnings = SetTextureDependencies();
|
|
||||||
SetBoneAndMaterialInformation();
|
SetBoneAndMaterialInformation();
|
||||||
|
|
||||||
|
if (shouldDeoptimizeGameObjects) {
|
||||||
|
// switch back to optimized game object in case it was originally optimized
|
||||||
|
modelImporter.optimizeGameObjects = true;
|
||||||
|
modelImporter.SaveAndReimport();
|
||||||
|
}
|
||||||
|
|
||||||
// check if we should be substituting a bone for a missing UpperChest mapping
|
// check if we should be substituting a bone for a missing UpperChest mapping
|
||||||
AdjustUpperChestMapping();
|
AdjustUpperChestMapping();
|
||||||
|
|
||||||
// format resulting avatar rule failure strings
|
// format resulting avatar rule failure strings
|
||||||
// consider export-blocking avatar rules to be errors and show them in an error dialog,
|
// consider export-blocking avatar rules to be errors and show them in an error dialog,
|
||||||
// and also include any other avatar rule failures plus texture warnings as warnings in the dialog
|
// and also include any other avatar rule failures plus texture warnings as warnings in the dialog
|
||||||
if (shouldDeoptimizeGameObjects) {
|
|
||||||
// switch back to optimized game object in case it was originally optimized
|
|
||||||
modelImporter.optimizeGameObjects = true;
|
|
||||||
modelImporter.SaveAndReimport();
|
|
||||||
}
|
|
||||||
|
|
||||||
// format resulting bone rule failure strings
|
|
||||||
// consider export-blocking bone rules to be errors and show them in an error dialog,
|
|
||||||
// and also include any other bone rule failures plus texture warnings as warnings in the dialog
|
|
||||||
string boneErrors = "";
|
string boneErrors = "";
|
||||||
string warnings = "";
|
warnings = "";
|
||||||
foreach (var failedAvatarRule in failedAvatarRules) {
|
foreach (var failedAvatarRule in failedAvatarRules) {
|
||||||
if (Array.IndexOf(EXPORT_BLOCKING_AVATAR_RULES, failedAvatarRule.Key) >= 0) {
|
if (Array.IndexOf(EXPORT_BLOCKING_AVATAR_RULES, failedAvatarRule.Key) >= 0) {
|
||||||
boneErrors += failedAvatarRule.Value + "\n\n";
|
boneErrors += failedAvatarRule.Value + "\n\n";
|
||||||
|
@ -400,15 +416,16 @@ class AvatarExporter : MonoBehaviour {
|
||||||
warnings += failedAvatarRule.Value + "\n\n";
|
warnings += failedAvatarRule.Value + "\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (string materialName in materialAlternateStandardShader) {
|
|
||||||
warnings += "The material " + materialName + " is not using the recommended variation of the Standard shader. " +
|
// add material and texture warnings after bone-related warnings
|
||||||
"We recommend you change it to Standard (Roughness setup) shader for improved performance.\n\n";
|
AddMaterialWarnings();
|
||||||
}
|
|
||||||
foreach (var material in materialUnsupportedShader) {
|
|
||||||
warnings += "The material " + material.Key + " is using an unsupported shader " + material.Value +
|
|
||||||
". Please change it to a Standard shader type.\n\n";
|
|
||||||
}
|
|
||||||
warnings += textureWarnings;
|
warnings += textureWarnings;
|
||||||
|
|
||||||
|
// remove trailing newlines at the end of the warnings
|
||||||
|
if (!string.IsNullOrEmpty(warnings)) {
|
||||||
|
warnings = warnings.Substring(0, warnings.LastIndexOf("\n\n"));
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(boneErrors)) {
|
if (!string.IsNullOrEmpty(boneErrors)) {
|
||||||
// if there are both errors and warnings then warnings will be displayed with errors in the error dialog
|
// if there are both errors and warnings then warnings will be displayed with errors in the error dialog
|
||||||
if (!string.IsNullOrEmpty(warnings)) {
|
if (!string.IsNullOrEmpty(warnings)) {
|
||||||
|
@ -421,21 +438,42 @@ class AvatarExporter : MonoBehaviour {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string documentsFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
|
// since there are no errors we can now open the preview scene in place of the user's scene
|
||||||
string hifiFolder = documentsFolder + "\\High Fidelity Projects";
|
if (!OpenPreviewScene()) {
|
||||||
if (updateAvatar) { // Update Existing Avatar menu option
|
|
||||||
bool copyModelToExport = false;
|
|
||||||
string initialPath = Directory.Exists(hifiFolder) ? hifiFolder : documentsFolder;
|
|
||||||
|
|
||||||
// open file explorer defaulting to hifi projects folder in user documents to select target fst to update
|
|
||||||
string exportFstPath = EditorUtility.OpenFilePanel("Select .fst to update", initialPath, "fst");
|
|
||||||
if (exportFstPath.Length == 0) { // file selection cancelled
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
exportFstPath = exportFstPath.Replace('/', '\\');
|
|
||||||
|
// show None instead of blank warnings if there are no warnings in the export windows
|
||||||
|
if (string.IsNullOrEmpty(warnings)) {
|
||||||
|
warnings = EMPTY_WARNING_TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
string documentsFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
|
||||||
|
string hifiFolder = documentsFolder + "\\High Fidelity 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
|
||||||
|
ExportProjectWindow window = ScriptableObject.CreateInstance<ExportProjectWindow>();
|
||||||
|
string initialPath = Directory.Exists(hifiFolder) ? hifiFolder : 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
ExportProjectWindow window = ScriptableObject.CreateInstance<ExportProjectWindow>();
|
||||||
|
window.Init(hifiFolder, warnings, updateExistingAvatar, avatarPreviewObject, OnExportNewProject, OnExportWindowClose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OnUpdateExistingProject(string exportFstPath, string projectName, float scale) {
|
||||||
|
bool copyModelToExport = false;
|
||||||
|
|
||||||
// lookup the project name field from the fst file to update
|
// lookup the project name field from the fst file to update
|
||||||
string projectName = "";
|
projectName = "";
|
||||||
try {
|
try {
|
||||||
string[] lines = File.ReadAllLines(exportFstPath);
|
string[] lines = File.ReadAllLines(exportFstPath);
|
||||||
foreach (string line in lines) {
|
foreach (string line in lines) {
|
||||||
|
@ -532,7 +570,7 @@ class AvatarExporter : MonoBehaviour {
|
||||||
}
|
}
|
||||||
|
|
||||||
// write out a new fst file in place of the old file
|
// write out a new fst file in place of the old file
|
||||||
if (!WriteFST(exportFstPath, projectName)) {
|
if (!WriteFST(exportFstPath, projectName, scale)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,23 +586,9 @@ class AvatarExporter : MonoBehaviour {
|
||||||
successDialog += "\n\nWarnings:\n" + warnings;
|
successDialog += "\n\nWarnings:\n" + warnings;
|
||||||
}
|
}
|
||||||
EditorUtility.DisplayDialog("Success!", successDialog, "Ok");
|
EditorUtility.DisplayDialog("Success!", successDialog, "Ok");
|
||||||
} 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(warnings)) {
|
static void OnExportNewProject(string projectDirectory, string projectName, float scale) {
|
||||||
warnings = EMPTY_WARNING_TEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// open a popup window to enter new export project name and project location
|
|
||||||
ExportProjectWindow window = ScriptableObject.CreateInstance<ExportProjectWindow>();
|
|
||||||
window.Init(hifiFolder, warnings, OnExportProjectWindowClose);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void OnExportProjectWindowClose(string projectDirectory, string projectName, string warnings) {
|
|
||||||
// copy the fbx from the Unity Assets folder to the project directory
|
// copy the fbx from the Unity Assets folder to the project directory
|
||||||
string exportModelPath = projectDirectory + assetName + ".fbx";
|
string exportModelPath = projectDirectory + assetName + ".fbx";
|
||||||
File.Copy(assetPath, exportModelPath);
|
File.Copy(assetPath, exportModelPath);
|
||||||
|
@ -577,7 +601,7 @@ class AvatarExporter : MonoBehaviour {
|
||||||
|
|
||||||
// write out the avatar.fst file to the project directory
|
// write out the avatar.fst file to the project directory
|
||||||
string exportFstPath = projectDirectory + "avatar.fst";
|
string exportFstPath = projectDirectory + "avatar.fst";
|
||||||
if (!WriteFST(exportFstPath, projectName)) {
|
if (!WriteFST(exportFstPath, projectName, scale)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,16 +616,27 @@ class AvatarExporter : MonoBehaviour {
|
||||||
if (warnings != EMPTY_WARNING_TEXT) {
|
if (warnings != EMPTY_WARNING_TEXT) {
|
||||||
successDialog += "Warnings:\n" + warnings;
|
successDialog += "Warnings:\n" + warnings;
|
||||||
}
|
}
|
||||||
successDialog += "Note: If you are using any external textures with your model, " +
|
successDialog += "\n\nNote: If you are using any external textures with your model, " +
|
||||||
"please ensure those textures are copied to " + texturesDirectory;
|
"please ensure those textures are copied to " + texturesDirectory;
|
||||||
EditorUtility.DisplayDialog("Success!", successDialog, "Ok");
|
EditorUtility.DisplayDialog("Success!", successDialog, "Ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool WriteFST(string exportFstPath, string projectName) {
|
static void OnExportWindowClose() {
|
||||||
|
// close the preview avatar scene and go back to user's previous scene when export project windows close
|
||||||
|
ClosePreviewScene();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The High Fidelity FBX Serializer omits the colon based prefixes. This will make the jointnames compatible.
|
||||||
|
static string removeTypeFromJointname(string jointName) {
|
||||||
|
return jointName.Substring(jointName.IndexOf(':') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool WriteFST(string exportFstPath, string projectName, float scale) {
|
||||||
// write out core fields to top of fst file
|
// write out core fields to top of fst file
|
||||||
try {
|
try {
|
||||||
File.WriteAllText(exportFstPath, "name = " + projectName + "\ntype = body+head\nscale = 1\nfilename = " +
|
File.WriteAllText(exportFstPath, "exporterVersion = " + AVATAR_EXPORTER_VERSION + "\nname = " + projectName +
|
||||||
assetName + ".fbx\n" + "texdir = textures\n");
|
"\ntype = body+head\nscale = " + scale + "\nfilename = " + assetName +
|
||||||
|
".fbx\n" + "texdir = textures\n");
|
||||||
} catch {
|
} catch {
|
||||||
EditorUtility.DisplayDialog("Error", "Failed to write file " + exportFstPath +
|
EditorUtility.DisplayDialog("Error", "Failed to write file " + exportFstPath +
|
||||||
". Please check the location and try again.", "Ok");
|
". Please check the location and try again.", "Ok");
|
||||||
|
@ -612,7 +647,7 @@ class AvatarExporter : MonoBehaviour {
|
||||||
foreach (var userBoneInfo in userBoneInfos) {
|
foreach (var userBoneInfo in userBoneInfos) {
|
||||||
if (userBoneInfo.Value.HasHumanMapping()) {
|
if (userBoneInfo.Value.HasHumanMapping()) {
|
||||||
string hifiJointName = HUMANOID_TO_HIFI_JOINT_NAME[userBoneInfo.Value.humanName];
|
string hifiJointName = HUMANOID_TO_HIFI_JOINT_NAME[userBoneInfo.Value.humanName];
|
||||||
File.AppendAllText(exportFstPath, "jointMap = " + hifiJointName + " = " + userBoneInfo.Key + "\n");
|
File.AppendAllText(exportFstPath, "jointMap = " + hifiJointName + " = " + removeTypeFromJointname(userBoneInfo.Key) + "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,7 +688,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 (HiFi) coordinates and write out joint rotation offset to fst
|
||||||
jointOffset = new Quaternion(-jointOffset.x, jointOffset.y, jointOffset.z, -jointOffset.w);
|
jointOffset = new Quaternion(-jointOffset.x, jointOffset.y, jointOffset.z, -jointOffset.w);
|
||||||
File.AppendAllText(exportFstPath, "jointRotationOffset2 = " + userBoneName + " = (" + jointOffset.x + ", " +
|
File.AppendAllText(exportFstPath, "jointRotationOffset2 = " + removeTypeFromJointname(userBoneName) + " = (" + jointOffset.x + ", " +
|
||||||
jointOffset.y + ", " + jointOffset.z + ", " + jointOffset.w + ")\n");
|
jointOffset.y + ", " + jointOffset.z + ", " + jointOffset.w + ")\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,14 +725,13 @@ class AvatarExporter : MonoBehaviour {
|
||||||
userBoneTree = new BoneTreeNode();
|
userBoneTree = new BoneTreeNode();
|
||||||
|
|
||||||
materialDatas.Clear();
|
materialDatas.Clear();
|
||||||
materialAlternateStandardShader.Clear();
|
alternateStandardShaderMaterials.Clear();
|
||||||
materialUnsupportedShader.Clear();
|
unsupportedShaderMaterials.Clear();
|
||||||
|
|
||||||
SetMaterialMappings();
|
SetMaterialMappings();
|
||||||
|
|
||||||
// instantiate a game object of the user avatar to traverse the bone tree to gather
|
// instantiate a game object of the user avatar to traverse the bone tree to gather
|
||||||
// bone parents and positions as well as build a bone tree, then destroy it
|
// bone parents and positions as well as build a bone tree, then destroy it
|
||||||
UnityEngine.Object avatarResource = AssetDatabase.LoadAssetAtPath(assetPath, typeof(UnityEngine.Object));
|
|
||||||
GameObject assetGameObject = (GameObject)Instantiate(avatarResource);
|
GameObject assetGameObject = (GameObject)Instantiate(avatarResource);
|
||||||
TraverseUserBoneTree(assetGameObject.transform);
|
TraverseUserBoneTree(assetGameObject.transform);
|
||||||
DestroyImmediate(assetGameObject);
|
DestroyImmediate(assetGameObject);
|
||||||
|
@ -732,8 +766,8 @@ class AvatarExporter : MonoBehaviour {
|
||||||
bool light = gameObject.GetComponent<Light>() != null;
|
bool light = gameObject.GetComponent<Light>() != null;
|
||||||
bool camera = gameObject.GetComponent<Camera>() != null;
|
bool camera = gameObject.GetComponent<Camera>() != null;
|
||||||
|
|
||||||
// if this is a mesh and the model is using external materials then store its material data to be exported
|
// if this is a mesh then store its material data to be exported if the material is mapped to an fbx material name
|
||||||
if (mesh && modelImporter.materialLocation == ModelImporterMaterialLocation.External) {
|
if (mesh) {
|
||||||
Material[] materials = skinnedMeshRenderer != null ? skinnedMeshRenderer.sharedMaterials : meshRenderer.sharedMaterials;
|
Material[] materials = skinnedMeshRenderer != null ? skinnedMeshRenderer.sharedMaterials : meshRenderer.sharedMaterials;
|
||||||
StoreMaterialData(materials);
|
StoreMaterialData(materials);
|
||||||
} else if (!light && !camera) {
|
} else if (!light && !camera) {
|
||||||
|
@ -959,7 +993,8 @@ class AvatarExporter : MonoBehaviour {
|
||||||
string userBoneName = "";
|
string userBoneName = "";
|
||||||
// avatar rule fails if bone is not mapped in Humanoid
|
// avatar rule fails if bone is not mapped in Humanoid
|
||||||
if (!humanoidToUserBoneMappings.TryGetValue(humanBoneName, out userBoneName)) {
|
if (!humanoidToUserBoneMappings.TryGetValue(humanBoneName, out userBoneName)) {
|
||||||
failedAvatarRules.Add(avatarRule, "There is no " + humanBoneName + " bone mapped in Humanoid for the selected avatar.");
|
failedAvatarRules.Add(avatarRule, "There is no " + humanBoneName +
|
||||||
|
" bone mapped in Humanoid for the selected avatar.");
|
||||||
}
|
}
|
||||||
return userBoneName;
|
return userBoneName;
|
||||||
}
|
}
|
||||||
|
@ -1072,8 +1107,8 @@ class AvatarExporter : MonoBehaviour {
|
||||||
|
|
||||||
// don't store any material data for unsupported shader types
|
// don't store any material data for unsupported shader types
|
||||||
if (Array.IndexOf(SUPPORTED_SHADERS, shaderName) == -1) {
|
if (Array.IndexOf(SUPPORTED_SHADERS, shaderName) == -1) {
|
||||||
if (!materialUnsupportedShader.ContainsKey(materialName)) {
|
if (!unsupportedShaderMaterials.Contains(materialName)) {
|
||||||
materialUnsupportedShader.Add(materialName, shaderName);
|
unsupportedShaderMaterials.Add(materialName);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1100,18 +1135,19 @@ class AvatarExporter : MonoBehaviour {
|
||||||
// for non-roughness Standard shaders give a warning that is not the recommended Standard shader,
|
// for non-roughness Standard shaders give a warning that is not the recommended Standard shader,
|
||||||
// and invert smoothness for roughness
|
// and invert smoothness for roughness
|
||||||
if (shaderName == STANDARD_SHADER || shaderName == STANDARD_SPECULAR_SHADER) {
|
if (shaderName == STANDARD_SHADER || shaderName == STANDARD_SPECULAR_SHADER) {
|
||||||
if (!materialAlternateStandardShader.Contains(materialName)) {
|
if (!alternateStandardShaderMaterials.Contains(materialName)) {
|
||||||
materialAlternateStandardShader.Add(materialName);
|
alternateStandardShaderMaterials.Add(materialName);
|
||||||
}
|
}
|
||||||
materialData.roughness = 1.0f - materialData.roughness;
|
materialData.roughness = 1.0f - materialData.roughness;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remap the material name from the Unity material name to the fbx material name that it overrides
|
// store the material data under each fbx material name that it overrides from the material mapping
|
||||||
if (materialMappings.ContainsKey(materialName)) {
|
foreach (var materialMapping in materialMappings) {
|
||||||
materialName = materialMappings[materialName];
|
string fbxMaterialName = materialMapping.Key;
|
||||||
|
string unityMaterialName = materialMapping.Value;
|
||||||
|
if (unityMaterialName == materialName && !materialDatas.ContainsKey(fbxMaterialName)) {
|
||||||
|
materialDatas.Add(fbxMaterialName, materialData);
|
||||||
}
|
}
|
||||||
if (!materialDatas.ContainsKey(materialName)) {
|
|
||||||
materialDatas.Add(materialName, materialData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1136,20 +1172,110 @@ class AvatarExporter : MonoBehaviour {
|
||||||
static void SetMaterialMappings() {
|
static void SetMaterialMappings() {
|
||||||
materialMappings.Clear();
|
materialMappings.Clear();
|
||||||
|
|
||||||
// store the mappings from fbx material name to the Unity material name overriding it using external fbx mapping
|
// store the mappings from fbx material name to the Unity Material name that overrides it using external fbx mapping
|
||||||
var objectMap = modelImporter.GetExternalObjectMap();
|
var objectMap = modelImporter.GetExternalObjectMap();
|
||||||
foreach (var mapping in objectMap) {
|
foreach (var mapping in objectMap) {
|
||||||
var material = mapping.Value as UnityEngine.Material;
|
var material = mapping.Value as UnityEngine.Material;
|
||||||
if (material != null) {
|
if (material != null) {
|
||||||
materialMappings.Add(material.name, mapping.Key.name);
|
materialMappings.Add(mapping.Key.name, material.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AddMaterialWarnings() {
|
||||||
|
string alternateStandardShaders = "";
|
||||||
|
string unsupportedShaders = "";
|
||||||
|
// combine all material names for each material warning into a comma-separated string
|
||||||
|
foreach (string materialName in alternateStandardShaderMaterials) {
|
||||||
|
if (!string.IsNullOrEmpty(alternateStandardShaders)) {
|
||||||
|
alternateStandardShaders += ", ";
|
||||||
|
}
|
||||||
|
alternateStandardShaders += materialName;
|
||||||
|
}
|
||||||
|
foreach (string materialName in unsupportedShaderMaterials) {
|
||||||
|
if (!string.IsNullOrEmpty(unsupportedShaders)) {
|
||||||
|
unsupportedShaders += ", ";
|
||||||
|
}
|
||||||
|
unsupportedShaders += materialName;
|
||||||
|
}
|
||||||
|
if (alternateStandardShaderMaterials.Count > 1) {
|
||||||
|
warnings += "The materials " + alternateStandardShaders + " are not using the " +
|
||||||
|
"recommended variation of the Standard shader. We recommend you change " +
|
||||||
|
"them to Standard (Roughness setup) shader for improved performance.\n\n";
|
||||||
|
} else if (alternateStandardShaderMaterials.Count == 1) {
|
||||||
|
warnings += "The material " + alternateStandardShaders + " is not using the " +
|
||||||
|
"recommended variation of the Standard shader. We recommend you change " +
|
||||||
|
"it to Standard (Roughness setup) shader for improved performance.\n\n";
|
||||||
|
}
|
||||||
|
if (unsupportedShaderMaterials.Count > 1) {
|
||||||
|
warnings += "The materials " + unsupportedShaders + " are using an unsupported shader. " +
|
||||||
|
"Please change them to a Standard shader type.\n\n";
|
||||||
|
} else if (unsupportedShaderMaterials.Count == 1) {
|
||||||
|
warnings += "The material " + unsupportedShaders + " is using an unsupported shader. " +
|
||||||
|
"Please change it to a Standard shader type.\n\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool OpenPreviewScene() {
|
||||||
|
// see if the user wants to save their current scene before opening preview avatar scene in place of user's scene
|
||||||
|
if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store the user's current scene to re-open when done and open a new default scene in place of the user's scene
|
||||||
|
previousScene = EditorSceneManager.GetActiveScene().path;
|
||||||
|
previewScene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene);
|
||||||
|
|
||||||
|
// instantiate a game object to preview the avatar and a game object for the height reference prefab at 0, 0, 0
|
||||||
|
UnityEngine.Object heightReferenceResource = AssetDatabase.LoadAssetAtPath(HEIGHT_REFERENCE_PREFAB, typeof(UnityEngine.Object));
|
||||||
|
avatarPreviewObject = (GameObject)Instantiate(avatarResource, Vector3.zero, Quaternion.identity);
|
||||||
|
heightReferenceObject = (GameObject)Instantiate(heightReferenceResource, Vector3.zero, Quaternion.identity);
|
||||||
|
|
||||||
|
// store the camera pivot and rotation from the user's last scene to be restored later
|
||||||
|
// replace the camera pivot and rotation to point at the preview avatar object in the -Z direction (facing front of it)
|
||||||
|
var sceneView = SceneView.lastActiveSceneView;
|
||||||
|
if (sceneView != null) {
|
||||||
|
previousScenePivot = sceneView.pivot;
|
||||||
|
previousSceneRotation = sceneView.rotation;
|
||||||
|
previousSceneSize = sceneView.size;
|
||||||
|
previousSceneOrthographic = sceneView.orthographic;
|
||||||
|
sceneView.pivot = PREVIEW_CAMERA_PIVOT;
|
||||||
|
sceneView.rotation = Quaternion.LookRotation(PREVIEW_CAMERA_DIRECTION);
|
||||||
|
sceneView.orthographic = true;
|
||||||
|
sceneView.size = 5.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ClosePreviewScene() {
|
||||||
|
// destroy the avatar and height reference game objects closing the scene
|
||||||
|
DestroyImmediate(avatarPreviewObject);
|
||||||
|
DestroyImmediate(heightReferenceObject);
|
||||||
|
|
||||||
|
// re-open the scene the user had open before switching to the preview scene
|
||||||
|
if (!string.IsNullOrEmpty(previousScene)) {
|
||||||
|
EditorSceneManager.OpenScene(previousScene);
|
||||||
|
}
|
||||||
|
|
||||||
|
// close the preview scene and flag it to be removed
|
||||||
|
EditorSceneManager.CloseScene(previewScene, true);
|
||||||
|
|
||||||
|
// restore the camera pivot and rotation to the user's previous scene settings
|
||||||
|
var sceneView = SceneView.lastActiveSceneView;
|
||||||
|
if (sceneView != null) {
|
||||||
|
sceneView.pivot = previousScenePivot;
|
||||||
|
sceneView.rotation = previousSceneRotation;
|
||||||
|
sceneView.size = previousSceneSize;
|
||||||
|
sceneView.orthographic = previousSceneOrthographic;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExportProjectWindow : EditorWindow {
|
class ExportProjectWindow : EditorWindow {
|
||||||
const int WINDOW_WIDTH = 500;
|
const int WINDOW_WIDTH = 500;
|
||||||
const int WINDOW_HEIGHT = 460;
|
const int EXPORT_NEW_WINDOW_HEIGHT = 520;
|
||||||
|
const int UPDATE_EXISTING_WINDOW_HEIGHT = 465;
|
||||||
const int BUTTON_FONT_SIZE = 16;
|
const int BUTTON_FONT_SIZE = 16;
|
||||||
const int LABEL_FONT_SIZE = 16;
|
const int LABEL_FONT_SIZE = 16;
|
||||||
const int TEXT_FIELD_FONT_SIZE = 14;
|
const int TEXT_FIELD_FONT_SIZE = 14;
|
||||||
|
@ -1157,25 +1283,59 @@ class ExportProjectWindow : EditorWindow {
|
||||||
const int ERROR_FONT_SIZE = 12;
|
const int ERROR_FONT_SIZE = 12;
|
||||||
const int WARNING_SCROLL_HEIGHT = 170;
|
const int WARNING_SCROLL_HEIGHT = 170;
|
||||||
const string EMPTY_ERROR_TEXT = "None\n";
|
const string EMPTY_ERROR_TEXT = "None\n";
|
||||||
|
const int SLIDER_WIDTH = 340;
|
||||||
|
const int SCALE_TEXT_WIDTH = 60;
|
||||||
|
const float MIN_SCALE_SLIDER = 0.0f;
|
||||||
|
const float MAX_SCALE_SLIDER = 2.0f;
|
||||||
|
const int SLIDER_SCALE_EXPONENT = 10;
|
||||||
|
const float ACTUAL_SCALE_OFFSET = 1.0f;
|
||||||
|
const float DEFAULT_AVATAR_HEIGHT = 1.755f;
|
||||||
|
const float MAXIMUM_RECOMMENDED_HEIGHT = DEFAULT_AVATAR_HEIGHT * 1.5f;
|
||||||
|
const float MINIMUM_RECOMMENDED_HEIGHT = DEFAULT_AVATAR_HEIGHT * 0.25f;
|
||||||
|
readonly Color COLOR_YELLOW = Color.yellow; //new Color(0.9176f, 0.8274f, 0.0f);
|
||||||
|
readonly Color COLOR_BACKGROUND = new Color(0.5f, 0.5f, 0.5f);
|
||||||
|
|
||||||
|
GameObject avatarPreviewObject;
|
||||||
|
bool updateExistingAvatar = false;
|
||||||
string projectName = "";
|
string projectName = "";
|
||||||
string projectLocation = "";
|
string projectLocation = "";
|
||||||
|
string initialProjectLocation = "";
|
||||||
string projectDirectory = "";
|
string projectDirectory = "";
|
||||||
string errorText = EMPTY_ERROR_TEXT;
|
string errorText = EMPTY_ERROR_TEXT;
|
||||||
string warningText = "";
|
string warningText = "\n";
|
||||||
Vector2 warningScrollPosition = new Vector2(0, 0);
|
Vector2 warningScrollPosition = new Vector2(0, 0);
|
||||||
|
string scaleWarningText = "";
|
||||||
|
float sliderScale = 0.30103f;
|
||||||
|
|
||||||
public delegate void OnCloseDelegate(string projectDirectory, string projectName, string warnings);
|
public delegate void OnExportDelegate(string projectDirectory, string projectName, float scale);
|
||||||
|
OnExportDelegate onExportCallback;
|
||||||
|
|
||||||
|
public delegate void OnCloseDelegate();
|
||||||
OnCloseDelegate onCloseCallback;
|
OnCloseDelegate onCloseCallback;
|
||||||
|
|
||||||
public void Init(string initialPath, string warnings, OnCloseDelegate closeCallback) {
|
public void Init(string initialPath, string warnings, bool updateExisting, GameObject avatarObject,
|
||||||
minSize = new Vector2(WINDOW_WIDTH, WINDOW_HEIGHT);
|
OnExportDelegate exportCallback, OnCloseDelegate closeCallback) {
|
||||||
maxSize = new Vector2(WINDOW_WIDTH, WINDOW_HEIGHT);
|
updateExistingAvatar = updateExisting;
|
||||||
titleContent.text = "Export New Avatar";
|
float windowHeight = updateExistingAvatar ? UPDATE_EXISTING_WINDOW_HEIGHT : EXPORT_NEW_WINDOW_HEIGHT;
|
||||||
projectLocation = initialPath;
|
minSize = new Vector2(WINDOW_WIDTH, windowHeight);
|
||||||
|
maxSize = new Vector2(WINDOW_WIDTH, windowHeight);
|
||||||
|
avatarPreviewObject = avatarObject;
|
||||||
|
titleContent.text = updateExistingAvatar ? "Update Existing Avatar" : "Export New Avatar";
|
||||||
|
initialProjectLocation = initialPath;
|
||||||
|
projectLocation = updateExistingAvatar ? "" : initialProjectLocation;
|
||||||
warningText = warnings;
|
warningText = warnings;
|
||||||
|
onExportCallback = exportCallback;
|
||||||
onCloseCallback = closeCallback;
|
onCloseCallback = closeCallback;
|
||||||
|
|
||||||
ShowUtility();
|
ShowUtility();
|
||||||
|
|
||||||
|
// if the avatar's starting height is outside of the recommended ranges, auto-adjust the scale to default height
|
||||||
|
float height = GetAvatarHeight();
|
||||||
|
if (height < MINIMUM_RECOMMENDED_HEIGHT || height > MAXIMUM_RECOMMENDED_HEIGHT) {
|
||||||
|
float newScale = DEFAULT_AVATAR_HEIGHT / height;
|
||||||
|
SetAvatarScale(newScale);
|
||||||
|
scaleWarningText = "Avatar's scale automatically adjusted to be within the recommended range.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnGUI() {
|
void OnGUI() {
|
||||||
|
@ -1192,10 +1352,24 @@ class ExportProjectWindow : EditorWindow {
|
||||||
errorStyle.normal.textColor = Color.red;
|
errorStyle.normal.textColor = Color.red;
|
||||||
errorStyle.wordWrap = true;
|
errorStyle.wordWrap = true;
|
||||||
GUIStyle warningStyle = new GUIStyle(errorStyle);
|
GUIStyle warningStyle = new GUIStyle(errorStyle);
|
||||||
warningStyle.normal.textColor = Color.yellow;
|
warningStyle.normal.textColor = COLOR_YELLOW;
|
||||||
|
GUIStyle sliderStyle = new GUIStyle(GUI.skin.horizontalSlider);
|
||||||
|
sliderStyle.fixedWidth = SLIDER_WIDTH;
|
||||||
|
GUIStyle sliderThumbStyle = new GUIStyle(GUI.skin.horizontalSliderThumb);
|
||||||
|
|
||||||
|
// set the background for the window to a darker gray
|
||||||
|
Texture2D backgroundTexture = new Texture2D(1, 1, TextureFormat.RGBA32, false);
|
||||||
|
backgroundTexture.SetPixel(0, 0, COLOR_BACKGROUND);
|
||||||
|
backgroundTexture.Apply();
|
||||||
|
GUI.DrawTexture(new Rect(0, 0, maxSize.x, maxSize.y), backgroundTexture, ScaleMode.StretchToFill);
|
||||||
|
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(10);
|
||||||
|
|
||||||
|
if (updateExistingAvatar) {
|
||||||
|
// Project file to update label and input text field
|
||||||
|
GUILayout.Label("Project file to update:", labelStyle);
|
||||||
|
projectLocation = GUILayout.TextField(projectLocation, textStyle);
|
||||||
|
} else {
|
||||||
// Project name label and input text field
|
// Project name label and input text field
|
||||||
GUILayout.Label("Export project name:", labelStyle);
|
GUILayout.Label("Export project name:", labelStyle);
|
||||||
projectName = GUILayout.TextField(projectName, textStyle);
|
projectName = GUILayout.TextField(projectName, textStyle);
|
||||||
|
@ -1205,22 +1379,55 @@ class ExportProjectWindow : EditorWindow {
|
||||||
// Project location label and input text field
|
// Project location label and input text field
|
||||||
GUILayout.Label("Export project location:", labelStyle);
|
GUILayout.Label("Export project location:", labelStyle);
|
||||||
projectLocation = GUILayout.TextField(projectLocation, textStyle);
|
projectLocation = GUILayout.TextField(projectLocation, textStyle);
|
||||||
|
}
|
||||||
|
|
||||||
// Browse button to open folder explorer that starts at project location path and then updates project location
|
// Browse button to open file/folder explorer and set project location
|
||||||
if (GUILayout.Button("Browse", buttonStyle)) {
|
if (GUILayout.Button("Browse", buttonStyle)) {
|
||||||
string result = EditorUtility.OpenFolderPanel("Select export location", projectLocation, "");
|
string result = "";
|
||||||
if (result.Length > 0) { // folder selection not cancelled
|
if (updateExistingAvatar) {
|
||||||
|
// open file explorer starting at hifi 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 {
|
||||||
|
// open folder explorer starting at project location path and select folder to create project folder in
|
||||||
|
result = EditorUtility.OpenFolderPanel("Select export location", projectLocation, "");
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(result)) { // file/folder selection not cancelled
|
||||||
projectLocation = result.Replace('/', '\\');
|
projectLocation = result.Replace('/', '\\');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Red error label text to display any file-related errors
|
// warning if scale is above/below recommended range or if scale was auto-adjusted initially
|
||||||
|
GUILayout.Label(scaleWarningText, warningStyle);
|
||||||
|
|
||||||
|
// from left to right show scale label, scale slider itself, and scale value input with % value
|
||||||
|
// slider value itself is from 0.0 to 2.0, and actual scale is an exponent of it with an offset of 1
|
||||||
|
// displayed scale is the actual scale value with 2 decimal places, and changing the displayed
|
||||||
|
// scale via keyboard does the inverse calculation to get the slider value via logarithm
|
||||||
|
GUILayout.BeginHorizontal();
|
||||||
|
GUILayout.Label("Scale:", labelStyle);
|
||||||
|
sliderScale = GUILayout.HorizontalSlider(sliderScale, MIN_SCALE_SLIDER, MAX_SCALE_SLIDER, sliderStyle, sliderThumbStyle);
|
||||||
|
float actualScale = (Mathf.Pow(SLIDER_SCALE_EXPONENT, sliderScale) - ACTUAL_SCALE_OFFSET);
|
||||||
|
GUIStyle scaleInputStyle = new GUIStyle(textStyle);
|
||||||
|
scaleInputStyle.fixedWidth = SCALE_TEXT_WIDTH;
|
||||||
|
actualScale *= 100.0f; // convert to 100-based percentage for display purposes
|
||||||
|
string actualScaleStr = GUILayout.TextField(String.Format("{0:0.00}", actualScale), scaleInputStyle);
|
||||||
|
actualScaleStr = Regex.Replace(actualScaleStr, @"[^0-9.]", "");
|
||||||
|
actualScale = float.Parse(actualScaleStr);
|
||||||
|
actualScale /= 100.0f; // convert back to 1.0-based percentage
|
||||||
|
SetAvatarScale(actualScale);
|
||||||
|
GUILayout.Label("%", labelStyle);
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.Space(15);
|
||||||
|
|
||||||
|
// red error label text to display any file-related errors
|
||||||
GUILayout.Label("Error:", errorStyle);
|
GUILayout.Label("Error:", errorStyle);
|
||||||
GUILayout.Label(errorText, errorStyle);
|
GUILayout.Label(errorText, errorStyle);
|
||||||
|
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(10);
|
||||||
|
|
||||||
// Yellow warning label text to display scrollable list of any bone-related warnings
|
// yellow warning label text to display scrollable list of any bone-related warnings
|
||||||
GUILayout.Label("Warnings:", warningStyle);
|
GUILayout.Label("Warnings:", warningStyle);
|
||||||
warningScrollPosition = GUILayout.BeginScrollView(warningScrollPosition, GUILayout.Width(WINDOW_WIDTH),
|
warningScrollPosition = GUILayout.BeginScrollView(warningScrollPosition, GUILayout.Width(WINDOW_WIDTH),
|
||||||
GUILayout.Height(WARNING_SCROLL_HEIGHT));
|
GUILayout.Height(WARNING_SCROLL_HEIGHT));
|
||||||
|
@ -1229,30 +1436,43 @@ class ExportProjectWindow : EditorWindow {
|
||||||
|
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(10);
|
||||||
|
|
||||||
// Export button which will verify project folder can actually be created
|
// export button will verify target project folder can actually be created (or target fst file is valid)
|
||||||
// before closing popup window and calling back to initiate the export
|
// before closing popup window and calling back to initiate the export
|
||||||
bool export = false;
|
bool export = false;
|
||||||
if (GUILayout.Button("Export", buttonStyle)) {
|
if (GUILayout.Button("Export", buttonStyle)) {
|
||||||
export = true;
|
export = true;
|
||||||
if (!CheckForErrors(true)) {
|
if (!CheckForErrors(true)) {
|
||||||
Close();
|
Close();
|
||||||
onCloseCallback(projectDirectory, projectName, warningText);
|
onExportCallback(updateExistingAvatar ? projectLocation : projectDirectory, projectName, actualScale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel button just closes the popup window without callback
|
// cancel button closes the popup window triggering the close callback to close the preview scene
|
||||||
if (GUILayout.Button("Cancel", buttonStyle)) {
|
if (GUILayout.Button("Cancel", buttonStyle)) {
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// When either text field changes check for any errors if we didn't just check errors from clicking Export above
|
// when any value changes check for any errors and update scale warning if we are not exporting
|
||||||
if (GUI.changed && !export) {
|
if (GUI.changed && !export) {
|
||||||
CheckForErrors(false);
|
CheckForErrors(false);
|
||||||
|
UpdateScaleWarning();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckForErrors(bool exporting) {
|
bool CheckForErrors(bool exporting) {
|
||||||
errorText = EMPTY_ERROR_TEXT; // default to None if no errors found
|
errorText = EMPTY_ERROR_TEXT; // default to None if no errors found
|
||||||
|
if (updateExistingAvatar) {
|
||||||
|
// if any text is set in the project file to update field verify that the file actually exists
|
||||||
|
if (projectLocation.Length > 0) {
|
||||||
|
if (!File.Exists(projectLocation)) {
|
||||||
|
errorText = "Please select a valid project file to update.\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (exporting) {
|
||||||
|
errorText = "Please select a project file to update.\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
projectDirectory = projectLocation + "\\" + projectName + "\\";
|
projectDirectory = projectLocation + "\\" + projectName + "\\";
|
||||||
if (projectName.Length > 0) {
|
if (projectName.Length > 0) {
|
||||||
// new project must have a unique folder name since the folder will be created for it
|
// new project must have a unique folder name since the folder will be created for it
|
||||||
|
@ -1287,6 +1507,51 @@ class ExportProjectWindow : EditorWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateScaleWarning() {
|
||||||
|
// called on any input changes
|
||||||
|
float height = GetAvatarHeight();
|
||||||
|
if (height < MINIMUM_RECOMMENDED_HEIGHT) {
|
||||||
|
scaleWarningText = "The height of the avatar is below the recommended minimum.";
|
||||||
|
} else if (height > MAXIMUM_RECOMMENDED_HEIGHT) {
|
||||||
|
scaleWarningText = "The height of the avatar is above the recommended maximum.";
|
||||||
|
} else {
|
||||||
|
scaleWarningText = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetAvatarHeight() {
|
||||||
|
// height of an avatar model can be determined to be the max Y extents of the combined bounds for all its mesh renderers
|
||||||
|
Bounds bounds = new Bounds();
|
||||||
|
var meshRenderers = avatarPreviewObject.GetComponentsInChildren<MeshRenderer>();
|
||||||
|
var skinnedMeshRenderers = avatarPreviewObject.GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||||
|
foreach (var renderer in meshRenderers) {
|
||||||
|
bounds.Encapsulate(renderer.bounds);
|
||||||
|
}
|
||||||
|
foreach (var renderer in skinnedMeshRenderers) {
|
||||||
|
bounds.Encapsulate(renderer.bounds);
|
||||||
|
}
|
||||||
|
return bounds.max.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetAvatarScale(float actualScale) {
|
||||||
|
// set the new scale uniformly on the preview avatar's transform to show the resulting avatar size
|
||||||
|
avatarPreviewObject.transform.localScale = new Vector3(actualScale, actualScale, actualScale);
|
||||||
|
|
||||||
|
// adjust slider scale value to match the new actual scale value
|
||||||
|
sliderScale = GetSliderScaleFromActualScale(actualScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetSliderScaleFromActualScale(float actualScale) {
|
||||||
|
// since actual scale is an exponent of slider scale with an offset, do the logarithm operation to convert it back
|
||||||
|
return Mathf.Log(actualScale + ACTUAL_SCALE_OFFSET, SLIDER_SCALE_EXPONENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDestroy() {
|
||||||
|
onCloseCallback();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_Name: Average
|
||||||
|
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_ShaderKeywords:
|
||||||
|
m_LightmapFlags: 4
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses: []
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BumpMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailAlbedoMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailMask:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailNormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _EmissionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MainTex:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MetallicGlossMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _OcclusionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _ParallaxMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Floats:
|
||||||
|
- _BumpScale: 1
|
||||||
|
- _Cutoff: 0.5
|
||||||
|
- _DetailNormalMapScale: 1
|
||||||
|
- _DstBlend: 0
|
||||||
|
- _GlossMapScale: 1
|
||||||
|
- _Glossiness: 0.5
|
||||||
|
- _GlossyReflections: 1
|
||||||
|
- _Metallic: 0
|
||||||
|
- _Mode: 0
|
||||||
|
- _OcclusionStrength: 1
|
||||||
|
- _Parallax: 0.02
|
||||||
|
- _SmoothnessTextureChannel: 0
|
||||||
|
- _SpecularHighlights: 1
|
||||||
|
- _SrcBlend: 1
|
||||||
|
- _UVSec: 0
|
||||||
|
- _ZWrite: 1
|
||||||
|
m_Colors:
|
||||||
|
- _Color: {r: 0.53309965, g: 0.8773585, b: 0.27727836, a: 1}
|
||||||
|
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
|
@ -0,0 +1,76 @@
|
||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_Name: Floor
|
||||||
|
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_ShaderKeywords:
|
||||||
|
m_LightmapFlags: 4
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses: []
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BumpMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailAlbedoMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailMask:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailNormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _EmissionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MainTex:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MetallicGlossMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _OcclusionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _ParallaxMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Floats:
|
||||||
|
- _BumpScale: 1
|
||||||
|
- _Cutoff: 0.5
|
||||||
|
- _DetailNormalMapScale: 1
|
||||||
|
- _DstBlend: 0
|
||||||
|
- _GlossMapScale: 1
|
||||||
|
- _Glossiness: 0.5
|
||||||
|
- _GlossyReflections: 1
|
||||||
|
- _Metallic: 0
|
||||||
|
- _Mode: 0
|
||||||
|
- _OcclusionStrength: 1
|
||||||
|
- _Parallax: 0.02
|
||||||
|
- _SmoothnessTextureChannel: 0
|
||||||
|
- _SpecularHighlights: 1
|
||||||
|
- _SrcBlend: 1
|
||||||
|
- _UVSec: 0
|
||||||
|
- _ZWrite: 1
|
||||||
|
m_Colors:
|
||||||
|
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,76 @@
|
||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_Name: Line
|
||||||
|
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_ShaderKeywords:
|
||||||
|
m_LightmapFlags: 4
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses: []
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BumpMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailAlbedoMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailMask:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailNormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _EmissionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MainTex:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MetallicGlossMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _OcclusionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _ParallaxMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Floats:
|
||||||
|
- _BumpScale: 1
|
||||||
|
- _Cutoff: 0.5
|
||||||
|
- _DetailNormalMapScale: 1
|
||||||
|
- _DstBlend: 0
|
||||||
|
- _GlossMapScale: 1
|
||||||
|
- _Glossiness: 0.5
|
||||||
|
- _GlossyReflections: 1
|
||||||
|
- _Metallic: 0
|
||||||
|
- _Mode: 0
|
||||||
|
- _OcclusionStrength: 1
|
||||||
|
- _Parallax: 0.02
|
||||||
|
- _SmoothnessTextureChannel: 0
|
||||||
|
- _SpecularHighlights: 1
|
||||||
|
- _SrcBlend: 1
|
||||||
|
- _UVSec: 0
|
||||||
|
- _ZWrite: 1
|
||||||
|
m_Colors:
|
||||||
|
- _Color: {r: 0, g: 0, b: 0, a: 1}
|
||||||
|
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
|
@ -0,0 +1,76 @@
|
||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_Name: ShortOrTall
|
||||||
|
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_ShaderKeywords:
|
||||||
|
m_LightmapFlags: 4
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses: []
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BumpMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailAlbedoMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailMask:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailNormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _EmissionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MainTex:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MetallicGlossMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _OcclusionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _ParallaxMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Floats:
|
||||||
|
- _BumpScale: 1
|
||||||
|
- _Cutoff: 0.5
|
||||||
|
- _DetailNormalMapScale: 1
|
||||||
|
- _DstBlend: 0
|
||||||
|
- _GlossMapScale: 1
|
||||||
|
- _Glossiness: 0.5
|
||||||
|
- _GlossyReflections: 1
|
||||||
|
- _Metallic: 0
|
||||||
|
- _Mode: 0
|
||||||
|
- _OcclusionStrength: 1
|
||||||
|
- _Parallax: 0.02
|
||||||
|
- _SmoothnessTextureChannel: 0
|
||||||
|
- _SpecularHighlights: 1
|
||||||
|
- _SrcBlend: 1
|
||||||
|
- _UVSec: 0
|
||||||
|
- _ZWrite: 1
|
||||||
|
m_Colors:
|
||||||
|
- _Color: {r: 0.91758025, g: 0.9622642, b: 0.28595585, a: 1}
|
||||||
|
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
|
@ -0,0 +1,76 @@
|
||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInternal: {fileID: 0}
|
||||||
|
m_Name: TooShortOrTall
|
||||||
|
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_ShaderKeywords:
|
||||||
|
m_LightmapFlags: 4
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses: []
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BumpMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailAlbedoMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailMask:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailNormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _EmissionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MainTex:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MetallicGlossMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _OcclusionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _ParallaxMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Floats:
|
||||||
|
- _BumpScale: 1
|
||||||
|
- _Cutoff: 0.5
|
||||||
|
- _DetailNormalMapScale: 1
|
||||||
|
- _DstBlend: 0
|
||||||
|
- _GlossMapScale: 1
|
||||||
|
- _Glossiness: 0.5
|
||||||
|
- _GlossyReflections: 1
|
||||||
|
- _Metallic: 0
|
||||||
|
- _Mode: 0
|
||||||
|
- _OcclusionStrength: 1
|
||||||
|
- _Parallax: 0.02
|
||||||
|
- _SmoothnessTextureChannel: 0
|
||||||
|
- _SpecularHighlights: 1
|
||||||
|
- _SrcBlend: 1
|
||||||
|
- _UVSec: 0
|
||||||
|
- _ZWrite: 1
|
||||||
|
m_Colors:
|
||||||
|
- _Color: {r: 0.9056604, g: 0.19223925, b: 0.19223925, a: 1}
|
||||||
|
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
|
@ -1,6 +1,6 @@
|
||||||
High Fidelity, Inc.
|
High Fidelity, Inc.
|
||||||
Avatar Exporter
|
Avatar Exporter
|
||||||
Version 0.3.3
|
Version 0.3.5
|
||||||
|
|
||||||
Note: It is recommended to use Unity versions between 2017.4.17f1 and 2018.2.12f1 for this Avatar Exporter.
|
Note: It is recommended to use Unity versions between 2017.4.17f1 and 2018.2.12f1 for this Avatar Exporter.
|
||||||
|
|
||||||
|
@ -9,13 +9,14 @@ To create a new avatar project:
|
||||||
2. Select the .fbx avatar that you imported in step 1 in the Assets window, and in the Rig section of the Inspector window set the Animation Type to Humanoid and choose Apply.
|
2. Select the .fbx avatar that you imported in step 1 in the Assets window, and in the Rig section of the Inspector window set the Animation Type to Humanoid and choose Apply.
|
||||||
3. With the .fbx avatar still selected in the Assets window, choose High Fidelity menu > Export New Avatar.
|
3. With the .fbx avatar still selected in the Assets window, choose High Fidelity menu > Export New Avatar.
|
||||||
4. Select a name for your avatar project (this will be used to create a directory with that name), as well as the target location for your project folder.
|
4. Select a name for your avatar project (this will be used to create a directory with that name), as well as the target location for your project folder.
|
||||||
5. Once it is exported, your project directory will open in File Explorer.
|
5. If necessary, adjust the scale for your avatar so that it's height is within the recommended range.
|
||||||
|
6. Once it is exported, you will receive a successfully exported dialog with any warnings, and your project directory will open in File Explorer.
|
||||||
|
|
||||||
To update an existing avatar project:
|
To update an existing avatar project:
|
||||||
1. Select the existing .fbx avatar in the Assets window that you would like to re-export.
|
1. Select the existing .fbx avatar in the Assets window that you would like to re-export and choose High Fidelity menu > Update Existing Avatar
|
||||||
2. Choose High Fidelity menu > Update Existing Avatar and browse to the .fst file you would like to update.
|
2. Select the .fst project file that you wish to update.
|
||||||
3. If the .fbx file in your Unity Assets folder is newer than the existing .fbx file in your selected avatar project or vice-versa, you will be prompted if you wish to replace the older file with the newer file before performing the update.
|
3. If the .fbx file in your Unity Assets folder is newer than the existing .fbx file in your selected avatar project or vice-versa, you will be prompted if you wish to replace the older file with the newer file before performing the update.
|
||||||
4. Once it is updated, your project directory will open in File Explorer.
|
4. Once it is updated, you will receive a successfully exported dialog with any warnings, and your project directory will open in File Explorer.
|
||||||
|
|
||||||
* WARNING *
|
* 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.
|
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.
|
||||||
|
|
Binary file not shown.
Loading…
Reference in a new issue