mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-05-29 10:11:30 +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.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
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.3.3";
|
||||
static readonly string AVATAR_EXPORTER_VERSION = "0.3.5";
|
||||
|
||||
static readonly float HIPS_GROUND_MIN_Y = 0.01f;
|
||||
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 TEXTURES_DIRECTORY = "textures";
|
||||
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
|
||||
static readonly string[] RECOMMENDED_UNITY_VERSIONS = new string[] {
|
||||
|
@ -298,18 +304,17 @@ class AvatarExporter : MonoBehaviour {
|
|||
if (!string.IsNullOrEmpty(occlusionMap)) {
|
||||
json += "\"occlusionMap\": \"" + occlusionMap + "\", ";
|
||||
}
|
||||
json += "\"emissive\": [" + emissive.r + ", " + emissive.g + ", " + emissive.b + "] ";
|
||||
json += "\"emissive\": [" + emissive.r + ", " + emissive.g + ", " + emissive.b + "]";
|
||||
if (!string.IsNullOrEmpty(emissiveMap)) {
|
||||
json += "\", emissiveMap\": \"" + emissiveMap + "\"";
|
||||
json += ", \"emissiveMap\": \"" + emissiveMap + "\"";
|
||||
}
|
||||
json += "} }";
|
||||
json += " } }";
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
static string assetPath = "";
|
||||
static string assetName = "";
|
||||
|
||||
static ModelImporter modelImporter;
|
||||
static HumanDescription humanDescription;
|
||||
|
||||
|
@ -317,12 +322,23 @@ class AvatarExporter : MonoBehaviour {
|
|||
static Dictionary<string, string> humanoidToUserBoneMappings = new Dictionary<string, string>();
|
||||
static BoneTreeNode userBoneTree = new BoneTreeNode();
|
||||
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> materialMappings = new Dictionary<string, string>();
|
||||
static Dictionary<string, MaterialData> materialDatas = new Dictionary<string, MaterialData>();
|
||||
static List<string> materialAlternateStandardShader = new List<string>();
|
||||
static Dictionary<string, string> materialUnsupportedShader = new Dictionary<string, string>();
|
||||
static List<string> alternateStandardShaderMaterials = new List<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")]
|
||||
static void ExportNewAvatar() {
|
||||
|
@ -339,8 +355,8 @@ class AvatarExporter : MonoBehaviour {
|
|||
EditorUtility.DisplayDialog("About", "High Fidelity, Inc.\nAvatar Exporter\nVersion " + AVATAR_EXPORTER_VERSION, "Ok");
|
||||
}
|
||||
|
||||
static void ExportSelectedAvatar(bool updateAvatar) {
|
||||
// ensure everything is saved to file before exporting
|
||||
static void ExportSelectedAvatar(bool updateExistingAvatar) {
|
||||
// ensure everything is saved to file before doing anything
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
string[] guids = Selection.assetGUIDs;
|
||||
|
@ -365,6 +381,11 @@ class AvatarExporter : MonoBehaviour {
|
|||
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
|
||||
bool shouldDeoptimizeGameObjects = modelImporter.optimizeGameObjects;
|
||||
if (shouldDeoptimizeGameObjects) {
|
||||
|
@ -372,27 +393,22 @@ class AvatarExporter : MonoBehaviour {
|
|||
modelImporter.SaveAndReimport();
|
||||
}
|
||||
|
||||
humanDescription = modelImporter.humanDescription;
|
||||
string textureWarnings = SetTextureDependencies();
|
||||
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
|
||||
AdjustUpperChestMapping();
|
||||
|
||||
// format resulting avatar rule failure strings
|
||||
// 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
|
||||
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 warnings = "";
|
||||
warnings = "";
|
||||
foreach (var failedAvatarRule in failedAvatarRules) {
|
||||
if (Array.IndexOf(EXPORT_BLOCKING_AVATAR_RULES, failedAvatarRule.Key) >= 0) {
|
||||
boneErrors += failedAvatarRule.Value + "\n\n";
|
||||
|
@ -400,15 +416,16 @@ class AvatarExporter : MonoBehaviour {
|
|||
warnings += failedAvatarRule.Value + "\n\n";
|
||||
}
|
||||
}
|
||||
foreach (string materialName in materialAlternateStandardShader) {
|
||||
warnings += "The material " + materialName + " 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";
|
||||
}
|
||||
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";
|
||||
}
|
||||
|
||||
// add material and texture warnings after bone-related warnings
|
||||
AddMaterialWarnings();
|
||||
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 there are both errors and warnings then warnings will be displayed with errors in the error dialog
|
||||
if (!string.IsNullOrEmpty(warnings)) {
|
||||
|
@ -421,21 +438,42 @@ class AvatarExporter : MonoBehaviour {
|
|||
return;
|
||||
}
|
||||
|
||||
string documentsFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
|
||||
string hifiFolder = documentsFolder + "\\High Fidelity Projects";
|
||||
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
|
||||
// since there are no errors we can now open the preview scene in place of the user's scene
|
||||
if (!OpenPreviewScene()) {
|
||||
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
|
||||
string projectName = "";
|
||||
projectName = "";
|
||||
try {
|
||||
string[] lines = File.ReadAllLines(exportFstPath);
|
||||
foreach (string line in lines) {
|
||||
|
@ -532,7 +570,7 @@ class AvatarExporter : MonoBehaviour {
|
|||
}
|
||||
|
||||
// write out a new fst file in place of the old file
|
||||
if (!WriteFST(exportFstPath, projectName)) {
|
||||
if (!WriteFST(exportFstPath, projectName, scale)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -548,23 +586,9 @@ class AvatarExporter : MonoBehaviour {
|
|||
successDialog += "\n\nWarnings:\n" + warnings;
|
||||
}
|
||||
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)) {
|
||||
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) {
|
||||
static void OnExportNewProject(string projectDirectory, string projectName, float scale) {
|
||||
// copy the fbx from the Unity Assets folder to the project directory
|
||||
string exportModelPath = projectDirectory + assetName + ".fbx";
|
||||
File.Copy(assetPath, exportModelPath);
|
||||
|
@ -577,7 +601,7 @@ class AvatarExporter : MonoBehaviour {
|
|||
|
||||
// write out the avatar.fst file to the project directory
|
||||
string exportFstPath = projectDirectory + "avatar.fst";
|
||||
if (!WriteFST(exportFstPath, projectName)) {
|
||||
if (!WriteFST(exportFstPath, projectName, scale)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -592,16 +616,27 @@ class AvatarExporter : MonoBehaviour {
|
|||
if (warnings != EMPTY_WARNING_TEXT) {
|
||||
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;
|
||||
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
|
||||
try {
|
||||
File.WriteAllText(exportFstPath, "name = " + projectName + "\ntype = body+head\nscale = 1\nfilename = " +
|
||||
assetName + ".fbx\n" + "texdir = textures\n");
|
||||
File.WriteAllText(exportFstPath, "exporterVersion = " + AVATAR_EXPORTER_VERSION + "\nname = " + projectName +
|
||||
"\ntype = body+head\nscale = " + scale + "\nfilename = " + assetName +
|
||||
".fbx\n" + "texdir = textures\n");
|
||||
} catch {
|
||||
EditorUtility.DisplayDialog("Error", "Failed to write file " + exportFstPath +
|
||||
". Please check the location and try again.", "Ok");
|
||||
|
@ -612,7 +647,7 @@ class AvatarExporter : MonoBehaviour {
|
|||
foreach (var userBoneInfo in userBoneInfos) {
|
||||
if (userBoneInfo.Value.HasHumanMapping()) {
|
||||
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
|
||||
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");
|
||||
}
|
||||
|
||||
|
@ -690,14 +725,13 @@ class AvatarExporter : MonoBehaviour {
|
|||
userBoneTree = new BoneTreeNode();
|
||||
|
||||
materialDatas.Clear();
|
||||
materialAlternateStandardShader.Clear();
|
||||
materialUnsupportedShader.Clear();
|
||||
alternateStandardShaderMaterials.Clear();
|
||||
unsupportedShaderMaterials.Clear();
|
||||
|
||||
SetMaterialMappings();
|
||||
|
||||
// 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
|
||||
UnityEngine.Object avatarResource = AssetDatabase.LoadAssetAtPath(assetPath, typeof(UnityEngine.Object));
|
||||
GameObject assetGameObject = (GameObject)Instantiate(avatarResource);
|
||||
TraverseUserBoneTree(assetGameObject.transform);
|
||||
DestroyImmediate(assetGameObject);
|
||||
|
@ -732,8 +766,8 @@ class AvatarExporter : MonoBehaviour {
|
|||
bool light = gameObject.GetComponent<Light>() != 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 (mesh && modelImporter.materialLocation == ModelImporterMaterialLocation.External) {
|
||||
// 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) {
|
||||
Material[] materials = skinnedMeshRenderer != null ? skinnedMeshRenderer.sharedMaterials : meshRenderer.sharedMaterials;
|
||||
StoreMaterialData(materials);
|
||||
} else if (!light && !camera) {
|
||||
|
@ -959,7 +993,8 @@ class AvatarExporter : MonoBehaviour {
|
|||
string userBoneName = "";
|
||||
// avatar rule fails if bone is not mapped in Humanoid
|
||||
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;
|
||||
}
|
||||
|
@ -1072,8 +1107,8 @@ class AvatarExporter : MonoBehaviour {
|
|||
|
||||
// don't store any material data for unsupported shader types
|
||||
if (Array.IndexOf(SUPPORTED_SHADERS, shaderName) == -1) {
|
||||
if (!materialUnsupportedShader.ContainsKey(materialName)) {
|
||||
materialUnsupportedShader.Add(materialName, shaderName);
|
||||
if (!unsupportedShaderMaterials.Contains(materialName)) {
|
||||
unsupportedShaderMaterials.Add(materialName);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -1100,18 +1135,19 @@ class AvatarExporter : MonoBehaviour {
|
|||
// for non-roughness Standard shaders give a warning that is not the recommended Standard shader,
|
||||
// and invert smoothness for roughness
|
||||
if (shaderName == STANDARD_SHADER || shaderName == STANDARD_SPECULAR_SHADER) {
|
||||
if (!materialAlternateStandardShader.Contains(materialName)) {
|
||||
materialAlternateStandardShader.Add(materialName);
|
||||
if (!alternateStandardShaderMaterials.Contains(materialName)) {
|
||||
alternateStandardShaderMaterials.Add(materialName);
|
||||
}
|
||||
materialData.roughness = 1.0f - materialData.roughness;
|
||||
}
|
||||
|
||||
// remap the material name from the Unity material name to the fbx material name that it overrides
|
||||
if (materialMappings.ContainsKey(materialName)) {
|
||||
materialName = materialMappings[materialName];
|
||||
// store the material data under each fbx material name that it overrides from the material mapping
|
||||
foreach (var materialMapping in materialMappings) {
|
||||
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() {
|
||||
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();
|
||||
foreach (var mapping in objectMap) {
|
||||
var material = mapping.Value as UnityEngine.Material;
|
||||
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 {
|
||||
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 LABEL_FONT_SIZE = 16;
|
||||
const int TEXT_FIELD_FONT_SIZE = 14;
|
||||
|
@ -1157,25 +1283,59 @@ class ExportProjectWindow : EditorWindow {
|
|||
const int ERROR_FONT_SIZE = 12;
|
||||
const int WARNING_SCROLL_HEIGHT = 170;
|
||||
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 projectLocation = "";
|
||||
string initialProjectLocation = "";
|
||||
string projectDirectory = "";
|
||||
string errorText = EMPTY_ERROR_TEXT;
|
||||
string warningText = "";
|
||||
string warningText = "\n";
|
||||
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;
|
||||
|
||||
public void Init(string initialPath, string warnings, OnCloseDelegate closeCallback) {
|
||||
minSize = new Vector2(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
maxSize = new Vector2(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
titleContent.text = "Export New Avatar";
|
||||
projectLocation = initialPath;
|
||||
public void Init(string initialPath, string warnings, bool updateExisting, GameObject avatarObject,
|
||||
OnExportDelegate exportCallback, OnCloseDelegate closeCallback) {
|
||||
updateExistingAvatar = updateExisting;
|
||||
float windowHeight = updateExistingAvatar ? UPDATE_EXISTING_WINDOW_HEIGHT : EXPORT_NEW_WINDOW_HEIGHT;
|
||||
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;
|
||||
onExportCallback = exportCallback;
|
||||
onCloseCallback = closeCallback;
|
||||
|
||||
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() {
|
||||
|
@ -1192,10 +1352,24 @@ class ExportProjectWindow : EditorWindow {
|
|||
errorStyle.normal.textColor = Color.red;
|
||||
errorStyle.wordWrap = true;
|
||||
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);
|
||||
|
||||
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
|
||||
GUILayout.Label("Export project name:", labelStyle);
|
||||
projectName = GUILayout.TextField(projectName, textStyle);
|
||||
|
@ -1205,22 +1379,55 @@ class ExportProjectWindow : EditorWindow {
|
|||
// Project location label and input text field
|
||||
GUILayout.Label("Export project location:", labelStyle);
|
||||
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)) {
|
||||
string result = EditorUtility.OpenFolderPanel("Select export location", projectLocation, "");
|
||||
if (result.Length > 0) { // folder selection not cancelled
|
||||
string result = "";
|
||||
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('/', '\\');
|
||||
}
|
||||
}
|
||||
|
||||
// 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(errorText, errorStyle);
|
||||
|
||||
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);
|
||||
warningScrollPosition = GUILayout.BeginScrollView(warningScrollPosition, GUILayout.Width(WINDOW_WIDTH),
|
||||
GUILayout.Height(WARNING_SCROLL_HEIGHT));
|
||||
|
@ -1229,30 +1436,43 @@ class ExportProjectWindow : EditorWindow {
|
|||
|
||||
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
|
||||
bool export = false;
|
||||
if (GUILayout.Button("Export", buttonStyle)) {
|
||||
export = true;
|
||||
if (!CheckForErrors(true)) {
|
||||
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)) {
|
||||
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) {
|
||||
CheckForErrors(false);
|
||||
UpdateScaleWarning();
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckForErrors(bool exporting) {
|
||||
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 + "\\";
|
||||
if (projectName.Length > 0) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
|
@ -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.
|
||||
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.
|
||||
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:
|
||||
1. Select the existing .fbx avatar in the Assets window that you would like to re-export.
|
||||
2. Choose High Fidelity menu > Update Existing Avatar and browse to the .fst file you would like to update.
|
||||
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. 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.
|
||||
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 *
|
||||
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