677 lines
23 KiB
C#
677 lines
23 KiB
C#
//This is UnityEditor only for the time being...
|
|
#if UNITY_EDITOR
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using UMA;
|
|
using UMA.CharacterSystem;
|
|
|
|
namespace UMA.CharacterSystem.Examples
|
|
{
|
|
//UPDATED For CharacterSystem.
|
|
//Takes photos of the character based on the Wardrobe slots.
|
|
//HUGE MemoryLeak or infinite loop in this somewhere...
|
|
public class PhotoBooth : MonoBehaviour
|
|
{
|
|
|
|
public RenderTexture bodyRenderTexture;
|
|
public RenderTexture outfitRenderTexture;
|
|
public RenderTexture headRenderTexture;
|
|
public RenderTexture chestRenderTexture;
|
|
public RenderTexture handsRenderTexture;
|
|
public RenderTexture legsRenderTexture;
|
|
public RenderTexture feetRenderTexture;
|
|
public DynamicCharacterAvatar avatarToPhoto;
|
|
|
|
public enum renderTextureOpts { BodyRenderTexture, OutfitRenderTexture, HeadRenderTexture, ChestRenderTexture, HandsRenderTexture, LegsRenderTexture, FeetRenderTexture };
|
|
public string photoName;
|
|
|
|
public bool freezeAnimation;
|
|
public float animationFreezeFrame = 1.8f;
|
|
public string destinationFolder;//non-serialized?
|
|
[Tooltip("If true will automatically take all possible wardrobe photos for the current character. Otherwise photographs character in its current state.")]
|
|
public bool autoPhotosEnabled = true;
|
|
[Tooltip("In manual mode use this to select the RenderTexture you wish to Photo")]
|
|
public renderTextureOpts textureToPhoto = renderTextureOpts.BodyRenderTexture;
|
|
[Tooltip("If true will dim everything but the target wardrobe recipe (AutoPhotosEnabled only)")]
|
|
public bool dimAllButTarget = false;
|
|
public Color dimToColor = new Color(0, 0, 0, 1);
|
|
public Color dimToMetallic = new Color(0, 0, 0, 1);
|
|
[Tooltip("If true will set the colors for the target wardrobe recipe to the neuttal color (AutoPhotosEnabled only)")]
|
|
public bool neutralizeTargetColors = false;
|
|
public Color neutralizeToColor = new Color(1, 1, 1, 1);
|
|
public Color neutralizeToMetallic = new Color(0, 0, 0, 1);
|
|
[Tooltip("If true will attempt to find an underwear wardrobe slot to apply when taking the base race photo (AutoPhotosEnabled only)")]
|
|
public bool addUnderwearToBasePhoto = true;
|
|
public bool overwriteExistingPhotos = true;
|
|
public bool doingTakePhoto = false;
|
|
bool canTakePhoto = true;
|
|
|
|
RenderTexture renderTextureToUse;
|
|
List<UMATextRecipe> wardrobeRecipeToPhoto = new List<UMATextRecipe>();
|
|
Dictionary<int, Dictionary<int, Color>> originalColors = new Dictionary<int, Dictionary<int, Color>>();
|
|
|
|
bool basePhotoTaken;
|
|
|
|
void Start()
|
|
{
|
|
destinationFolder = "";
|
|
}
|
|
|
|
public void TakePhotos()
|
|
{
|
|
if (doingTakePhoto == false)
|
|
{
|
|
doingTakePhoto = true;
|
|
if (avatarToPhoto == null)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("You need to set the Avatar to photo in the inspector!");
|
|
doingTakePhoto = false;
|
|
return;
|
|
}
|
|
if (destinationFolder == "")
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("You need to set a DestinationFolder in the inspector!");
|
|
doingTakePhoto = false;
|
|
return;
|
|
}
|
|
if (!autoPhotosEnabled)
|
|
{
|
|
bool canPhoto = SetBestRenderTexture();
|
|
if (canPhoto)
|
|
{
|
|
photoName = photoName == "" ? avatarToPhoto.activeRace.name + Path.GetRandomFileName().Replace(".", "") : photoName;
|
|
StartCoroutine(TakePhotoCoroutine());
|
|
}
|
|
else
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Unknown RenderTexture Error...");
|
|
doingTakePhoto = false;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Dictionary<string, List<UMATextRecipe>> recipesToPhoto = UMAContext.Instance.GetRecipes(avatarToPhoto.activeRace.name);
|
|
basePhotoTaken = false;
|
|
StartCoroutine(TakePhotosCoroutine(recipesToPhoto));
|
|
}
|
|
}
|
|
}
|
|
|
|
IEnumerator TakePhotosCoroutine(Dictionary<string, List<UMATextRecipe>> recipesToPhoto)
|
|
{
|
|
yield return null;
|
|
wardrobeRecipeToPhoto.Clear();
|
|
if (!basePhotoTaken)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Gonna take base Photo...");
|
|
avatarToPhoto.ClearSlots();
|
|
if (addUnderwearToBasePhoto)
|
|
{
|
|
foreach (KeyValuePair<string, List<UMATextRecipe>> kp in recipesToPhoto)
|
|
{
|
|
if (kp.Key.IndexOf("Underwear") > -1 || kp.Key.IndexOf("underwear") > -1)
|
|
{
|
|
avatarToPhoto.SetSlot(kp.Value[0]);
|
|
}
|
|
}
|
|
}
|
|
bool renderTextureFound = SetBestRenderTexture("Body");
|
|
if (!renderTextureFound)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("No suitable RenderTexture found for Base Photo..");
|
|
doingTakePhoto = false;
|
|
yield break;
|
|
}
|
|
photoName = avatarToPhoto.activeRace.name;
|
|
canTakePhoto = false;
|
|
avatarToPhoto.CharacterUpdated.AddListener(SetCharacterReady);
|
|
avatarToPhoto.BuildCharacter(true);
|
|
while (!canTakePhoto)
|
|
{
|
|
yield return new WaitForSeconds(1f);
|
|
}
|
|
yield return StartCoroutine("TakePhotoCoroutine");
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Took base Photo...");
|
|
StopCoroutine("TakePhotoCoroutine");
|
|
//really we need photos for each area of the body (i.e. from each renderTexture/Cam) with no clothes on so we can have a 'None' image
|
|
//so we'll need head, chest, hands, legs, feet, full outfit...
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Now taking the Base Photos for body parts...");
|
|
List<string> emptySlotsToPhoto = new List<string> { "Head", "Chest", "Hands", "Legs", "Feet", "Outfit" };
|
|
//if dimming and neutralizing is on do it
|
|
if (dimAllButTarget && neutralizeTargetColors)
|
|
{
|
|
canTakePhoto = false;
|
|
avatarToPhoto.CharacterUpdated.AddListener(SetCharacterReadyAfterColorChange);
|
|
DoDimmingAndNeutralizing();
|
|
while (!canTakePhoto)
|
|
{
|
|
yield return new WaitForSeconds(1f);
|
|
}
|
|
}
|
|
foreach (string emptySlotToPhoto in emptySlotsToPhoto)
|
|
{
|
|
photoName = avatarToPhoto.activeRace.name + emptySlotToPhoto + "None";
|
|
renderTextureFound = SetBestRenderTexture(emptySlotToPhoto);
|
|
if (!renderTextureFound)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("No suitable RenderTexture found for " + emptySlotToPhoto + " Photo..");
|
|
continue;
|
|
}
|
|
yield return StartCoroutine("TakePhotoCoroutine");
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Took base " + emptySlotToPhoto + " Photo...");
|
|
StopCoroutine("TakePhotoCoroutine");
|
|
}
|
|
basePhotoTaken = true;
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Now taking the rest...");
|
|
StartCoroutine(TakePhotosCoroutine(recipesToPhoto));
|
|
yield break;
|
|
}
|
|
else
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Gonna take other wardrobe photos...");
|
|
if (originalColors.Count > 0)
|
|
{
|
|
avatarToPhoto.CharacterUpdated.RemoveListener(SetCharacterReadyAfterColorChange);
|
|
UndoDimmingAnNeutralizing();
|
|
}
|
|
var numKeys = recipesToPhoto.Count;
|
|
int slotsDone = 0;
|
|
foreach (string wardrobeSlot in recipesToPhoto.Keys)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Gonna take photos for " + wardrobeSlot);
|
|
bool renderTextureFound = SetBestRenderTexture(wardrobeSlot);
|
|
if (!renderTextureFound)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("No suitable RenderTexture found for " + wardrobeSlot + " Photo..");
|
|
doingTakePhoto = false;
|
|
yield break;
|
|
}
|
|
foreach (UMATextRecipe wardrobeRecipe in recipesToPhoto[wardrobeSlot])
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Gonna take photos for " + wardrobeRecipe.name + " in " + wardrobeSlot);
|
|
photoName = wardrobeRecipe.name;
|
|
var path = destinationFolder + "/" + photoName + ".png";
|
|
if (!overwriteExistingPhotos && File.Exists(Application.dataPath + "/" + path))
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Photo already existed for " + photoName + ". Turn on overwrite photos to replace existig ones");
|
|
continue;
|
|
}
|
|
wardrobeRecipeToPhoto.Clear();
|
|
wardrobeRecipeToPhoto.Add(wardrobeRecipe);
|
|
avatarToPhoto.ClearSlots();
|
|
if (addUnderwearToBasePhoto)
|
|
{
|
|
foreach (KeyValuePair<string, List<UMATextRecipe>> kp in recipesToPhoto)
|
|
{
|
|
if (kp.Key.IndexOf("Underwear") > -1 || kp.Key.IndexOf("underwear") > -1)
|
|
{
|
|
avatarToPhoto.SetSlot(kp.Value[0]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
avatarToPhoto.SetSlot(wardrobeRecipe);
|
|
canTakePhoto = false;
|
|
avatarToPhoto.CharacterUpdated.AddListener(SetCharacterReady);
|
|
avatarToPhoto.BuildCharacter(true);
|
|
while (!canTakePhoto)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Waiting to take photo...");
|
|
yield return new WaitForSeconds(1f);
|
|
}
|
|
yield return StartCoroutine("TakePhotoCoroutine");
|
|
StopCoroutine("TakePhotoCoroutine");
|
|
}
|
|
slotsDone++;
|
|
if (slotsDone == numKeys)
|
|
{
|
|
ResetCharacter();
|
|
doingTakePhoto = false;
|
|
StopAllCoroutines();
|
|
yield break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ResetCharacter()
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Doing Final Reset");
|
|
if (originalColors.Count > 0)
|
|
{
|
|
avatarToPhoto.CharacterUpdated.RemoveListener(SetCharacterReadyAfterColorChange);
|
|
UndoDimmingAnNeutralizing();
|
|
}
|
|
if (freezeAnimation)
|
|
{
|
|
avatarToPhoto.umaData.animator.speed = 1f;
|
|
avatarToPhoto.umaData.gameObject.GetComponent<UMA.PoseTools.UMAExpressionPlayer>().enableBlinking = true;
|
|
avatarToPhoto.umaData.gameObject.GetComponent<UMA.PoseTools.UMAExpressionPlayer>().enableSaccades = true;
|
|
}
|
|
avatarToPhoto.LoadDefaultWardrobe();
|
|
avatarToPhoto.BuildCharacter(true);
|
|
}
|
|
|
|
public void SetCharacterReady(UMAData umaData)
|
|
{
|
|
avatarToPhoto.CharacterUpdated.RemoveListener(SetCharacterReady);
|
|
if ((dimAllButTarget || neutralizeTargetColors) /*&& wardrobeRecipeToPhoto != null*/)//should we be making it possible to dim the base slot photos too?
|
|
{
|
|
if (originalColors.Count > 0)
|
|
{
|
|
avatarToPhoto.CharacterUpdated.RemoveListener(SetCharacterReadyAfterColorChange);
|
|
UndoDimmingAnNeutralizing();//I think this is causing character updates maybe?
|
|
}
|
|
avatarToPhoto.CharacterUpdated.AddListener(SetCharacterReadyAfterColorChange);
|
|
DoDimmingAndNeutralizing();
|
|
}
|
|
else
|
|
{
|
|
if (freezeAnimation)
|
|
{
|
|
SetAnimationFrame();
|
|
}
|
|
canTakePhoto = true;
|
|
}
|
|
}
|
|
public void SetCharacterReadyAfterColorChange(UMAData umaData)
|
|
{
|
|
avatarToPhoto.CharacterUpdated.RemoveListener(SetCharacterReadyAfterColorChange);
|
|
if (freezeAnimation)
|
|
{
|
|
SetAnimationFrame();
|
|
}
|
|
canTakePhoto = true;
|
|
}
|
|
|
|
private void SetAnimationFrame()
|
|
{
|
|
var thisAnimatonClip = avatarToPhoto.umaData.animationController.animationClips[0];
|
|
avatarToPhoto.umaData.animator.Play(thisAnimatonClip.name, 0, animationFreezeFrame);
|
|
avatarToPhoto.umaData.animator.speed = 0f;
|
|
avatarToPhoto.umaData.gameObject.GetComponent<UMA.PoseTools.UMAExpressionPlayer>().enableBlinking = false;
|
|
avatarToPhoto.umaData.gameObject.GetComponent<UMA.PoseTools.UMAExpressionPlayer>().enableSaccades = false;
|
|
}
|
|
|
|
IEnumerator TakePhotoCoroutine()
|
|
{
|
|
canTakePhoto = false;
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Taking Photo...");
|
|
if (!autoPhotosEnabled)
|
|
{
|
|
if (dimAllButTarget && neutralizeTargetColors)
|
|
{
|
|
canTakePhoto = false;
|
|
avatarToPhoto.CharacterUpdated.AddListener(SetCharacterReadyAfterColorChange);
|
|
wardrobeRecipeToPhoto.Clear();
|
|
foreach (KeyValuePair<string, UMATextRecipe> kp in avatarToPhoto.WardrobeRecipes)
|
|
{
|
|
wardrobeRecipeToPhoto.Add(kp.Value);
|
|
}
|
|
DoDimmingAndNeutralizing();
|
|
while (!canTakePhoto)
|
|
{
|
|
yield return new WaitForSeconds(1f);
|
|
}
|
|
}
|
|
}
|
|
var path = destinationFolder + "/" + photoName + ".png";
|
|
if (!overwriteExistingPhotos && File.Exists(path))
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("could not overwrite existing Photo. Turn on Overwrite Existing Photos if you want to allow this");
|
|
canTakePhoto = true;
|
|
doingTakePhoto = false;
|
|
if (!autoPhotosEnabled)
|
|
{
|
|
ResetCharacter();
|
|
}
|
|
yield return true;
|
|
}
|
|
else
|
|
{
|
|
Texture2D texToSave = new Texture2D(renderTextureToUse.width, renderTextureToUse.height,TextureFormat.ARGB32,false,false);
|
|
RenderTexture prev = RenderTexture.active;
|
|
RenderTexture.active = renderTextureToUse;
|
|
texToSave.ReadPixels(new Rect(0, 0, renderTextureToUse.width, renderTextureToUse.height), 0, 0, true);
|
|
texToSave.Apply();
|
|
byte[] texToSavePNG = texToSave.EncodeToPNG();
|
|
//path must be inside assets
|
|
File.WriteAllBytes(path, texToSavePNG);
|
|
RenderTexture.active = prev;
|
|
var relativePath = path;
|
|
if (path.StartsWith(Application.dataPath))
|
|
{
|
|
relativePath = "Assets" + path.Substring(Application.dataPath.Length);
|
|
}
|
|
AssetDatabase.ImportAsset(relativePath, ImportAssetOptions.ForceUncompressedImport);
|
|
TextureImporter textureImporter = AssetImporter.GetAtPath(relativePath) as TextureImporter;
|
|
textureImporter.textureType = TextureImporterType.Sprite;
|
|
textureImporter.mipmapEnabled = false;
|
|
textureImporter.maxTextureSize = 256;
|
|
AssetDatabase.ImportAsset(relativePath, ImportAssetOptions.ForceUpdate);
|
|
canTakePhoto = true;
|
|
doingTakePhoto = false;
|
|
if (!autoPhotosEnabled)
|
|
{
|
|
ResetCharacter();
|
|
}
|
|
yield return true;
|
|
}
|
|
}
|
|
|
|
private void UndoDimmingAnNeutralizing()
|
|
{
|
|
int numSlots = avatarToPhoto.umaData.GetSlotArraySize();
|
|
for (int i = 0; i < numSlots; i++)
|
|
{
|
|
if (avatarToPhoto.umaData.GetSlot(i))
|
|
{
|
|
var thisSlot = avatarToPhoto.umaData.GetSlot(i);
|
|
var thisSlotOverlays = thisSlot.GetOverlayList();
|
|
for (int ii = 0; ii < thisSlotOverlays.Count; ii++)
|
|
{
|
|
if (originalColors.ContainsKey(i))
|
|
{
|
|
if (originalColors[i].ContainsKey(ii))
|
|
{
|
|
thisSlotOverlays[ii].SetColor(0, originalColors[i][ii]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DoDimmingAndNeutralizing()
|
|
{
|
|
if (wardrobeRecipeToPhoto.Count > 0)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Doing Dimming And Neutralizing for " + wardrobeRecipeToPhoto[0].name);
|
|
}
|
|
else
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("Doing Dimming And Neutralizing for Body shots");
|
|
}
|
|
int numAvatarSlots = avatarToPhoto.umaData.GetSlotArraySize();
|
|
originalColors.Clear();
|
|
List<string> slotsInRecipe = new List<string>();
|
|
List<string> overlaysInRecipe = new List<string>();
|
|
foreach (UMATextRecipe utr in wardrobeRecipeToPhoto)
|
|
{
|
|
UMAData.UMARecipe tempLoadedRecipe = new UMAData.UMARecipe();
|
|
utr.Load(tempLoadedRecipe, avatarToPhoto.context);
|
|
foreach (SlotData slot in tempLoadedRecipe.slotDataList)
|
|
{
|
|
if (slot != null)
|
|
{
|
|
slotsInRecipe.Add(slot.asset.name);
|
|
foreach (OverlayData wOverlay in slot.GetOverlayList())
|
|
{
|
|
if (!overlaysInRecipe.Contains(wOverlay.asset.name))
|
|
overlaysInRecipe.Add(wOverlay.asset.name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Deal with skin color first if we are dimming
|
|
if (dimAllButTarget)
|
|
{
|
|
OverlayColorData[] sharedColors = avatarToPhoto.umaData.umaRecipe.sharedColors;
|
|
for (int i = 0; i < sharedColors.Length; i++)
|
|
{
|
|
if (sharedColors[i].name == "Skin" || sharedColors[i].name == "skin")
|
|
{
|
|
sharedColors[i].color = dimToColor;
|
|
if (sharedColors[i].channelAdditiveMask.Length >= 3)
|
|
{
|
|
sharedColors[i].channelAdditiveMask[2] = dimToMetallic;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (int i = 0; i < numAvatarSlots; i++)
|
|
{
|
|
if (avatarToPhoto.umaData.GetSlot(i) != null)
|
|
{
|
|
var overlaysInAvatarSlot = avatarToPhoto.umaData.GetSlot(i).GetOverlayList();
|
|
if (slotsInRecipe.Contains(avatarToPhoto.umaData.GetSlot(i).asset.name))
|
|
{
|
|
if (neutralizeTargetColors || dimAllButTarget)
|
|
{
|
|
for (int ii = 0; ii < overlaysInAvatarSlot.Count; ii++)
|
|
{
|
|
//there is a problem here where if the recipe also contains replacement body slots (like my toon CapriPants_LEGS) these also get set to white
|
|
//so we need to check if the overlay contains any body part names I think
|
|
bool overlayIsBody = false;
|
|
var thisOverlayName = overlaysInAvatarSlot[ii].asset.name;
|
|
if (thisOverlayName.IndexOf("Face", StringComparison.OrdinalIgnoreCase) > -1
|
|
// || thisOverlayName.IndexOf("Torso", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| thisOverlayName.IndexOf("Arms", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| thisOverlayName.IndexOf("Hands", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| thisOverlayName.IndexOf("Legs", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| thisOverlayName.IndexOf("Feet", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| thisOverlayName.IndexOf("Body", StringComparison.OrdinalIgnoreCase) > -1)
|
|
{
|
|
overlayIsBody = true;
|
|
}
|
|
if (overlaysInRecipe.Contains(overlaysInAvatarSlot[ii].asset.name) && overlayIsBody == false)
|
|
{
|
|
if (!originalColors.ContainsKey(i))
|
|
{
|
|
originalColors.Add(i, new Dictionary<int, Color>());
|
|
}
|
|
if (!originalColors[i].ContainsKey(ii))
|
|
originalColors[i].Add(ii, overlaysInAvatarSlot[ii].colorData.color);
|
|
overlaysInAvatarSlot[ii].colorData.color = neutralizeToColor;
|
|
if (overlaysInAvatarSlot[ii].colorData.channelAdditiveMask.Length >= 3)
|
|
{
|
|
overlaysInAvatarSlot[ii].colorData.channelAdditiveMask[2] = neutralizeToMetallic;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dimAllButTarget)
|
|
{
|
|
if (!originalColors.ContainsKey(i))
|
|
{
|
|
originalColors.Add(i, new Dictionary<int, Color>());
|
|
}
|
|
if (!originalColors[i].ContainsKey(ii))
|
|
originalColors[i].Add(ii, overlaysInAvatarSlot[ii].colorData.color);
|
|
overlaysInAvatarSlot[ii].colorData.color = dimToColor;
|
|
if (overlaysInAvatarSlot[ii].colorData.channelAdditiveMask.Length >= 3)
|
|
{
|
|
overlaysInAvatarSlot[ii].colorData.channelAdditiveMask[2] = dimToMetallic;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dimAllButTarget)
|
|
{
|
|
for (int ii = 0; ii < overlaysInAvatarSlot.Count; ii++)
|
|
{
|
|
if (!overlaysInRecipe.Contains(overlaysInAvatarSlot[ii].asset.name))
|
|
{
|
|
if (!originalColors.ContainsKey(i))
|
|
{
|
|
originalColors.Add(i, new Dictionary<int, Color>());
|
|
}
|
|
if (!originalColors[i].ContainsKey(ii))
|
|
originalColors[i].Add(ii, overlaysInAvatarSlot[ii].colorData.color);
|
|
overlaysInAvatarSlot[ii].colorData.color = dimToColor;
|
|
if (overlaysInAvatarSlot[ii].colorData.channelAdditiveMask.Length >= 3)
|
|
{
|
|
overlaysInAvatarSlot[ii].colorData.channelAdditiveMask[2] = dimToMetallic;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
avatarToPhoto.umaData.dirty = false;
|
|
avatarToPhoto.umaData.Dirty(false, true, false);
|
|
}
|
|
|
|
private bool SetBestRenderTexture(string wardrobeSlot = "")
|
|
{
|
|
if (wardrobeSlot == "Body" || (!autoPhotosEnabled && textureToPhoto == renderTextureOpts.BodyRenderTexture))
|
|
{
|
|
if (bodyRenderTexture == null)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("You need to set the Body Render Texture in the inspector!");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
renderTextureToUse = bodyRenderTexture;
|
|
return true;
|
|
}
|
|
}
|
|
else if (wardrobeSlot.IndexOf("Hair", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| wardrobeSlot.IndexOf("Face", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| wardrobeSlot.IndexOf("Head", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| wardrobeSlot.IndexOf("Helmet", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| wardrobeSlot.IndexOf("Complexion", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| wardrobeSlot.IndexOf("Eyebrows", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| wardrobeSlot.IndexOf("Beard", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| wardrobeSlot.IndexOf("Ears", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| (!autoPhotosEnabled && textureToPhoto == renderTextureOpts.HeadRenderTexture))
|
|
{
|
|
|
|
if (headRenderTexture == null)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("You need to set the Head Render Texture in the inspector!");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
renderTextureToUse = headRenderTexture;
|
|
return true;
|
|
}
|
|
}
|
|
else if (wardrobeSlot.IndexOf("Shoulders", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| wardrobeSlot.IndexOf("Chest", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| wardrobeSlot.IndexOf("Arms", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| (!autoPhotosEnabled && textureToPhoto == renderTextureOpts.ChestRenderTexture)
|
|
)
|
|
{
|
|
if (chestRenderTexture == null)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("You need to set the Chest Render Texture in the inspector!");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
renderTextureToUse = chestRenderTexture;
|
|
return true;
|
|
}
|
|
}
|
|
else if (wardrobeSlot.IndexOf("Hands", StringComparison.OrdinalIgnoreCase) > -1 || (!autoPhotosEnabled && textureToPhoto == renderTextureOpts.HandsRenderTexture))
|
|
{
|
|
if (handsRenderTexture == null)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("You need to set the Hands Render Texture in the inspector!");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
renderTextureToUse = handsRenderTexture;
|
|
return true;
|
|
}
|
|
}
|
|
else if (wardrobeSlot.IndexOf("Waist", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| wardrobeSlot.IndexOf("Legs", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| (!autoPhotosEnabled && textureToPhoto == renderTextureOpts.LegsRenderTexture))
|
|
{
|
|
if (legsRenderTexture == null)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("You need to set the Legs Render Texture in the inspector!");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
renderTextureToUse = legsRenderTexture;
|
|
return true;
|
|
}
|
|
}
|
|
else if (wardrobeSlot.IndexOf("Feet", StringComparison.OrdinalIgnoreCase) > -1 || (!autoPhotosEnabled && textureToPhoto == renderTextureOpts.FeetRenderTexture))
|
|
{
|
|
if (feetRenderTexture == null)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("You need to set the Feet Render Texture in the inspector!");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
renderTextureToUse = feetRenderTexture;
|
|
return true;
|
|
}
|
|
}
|
|
else if (wardrobeSlot.IndexOf("Outfit", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| wardrobeSlot.IndexOf("Underwear", StringComparison.OrdinalIgnoreCase) > -1
|
|
|| (!autoPhotosEnabled && textureToPhoto == renderTextureOpts.OutfitRenderTexture))
|
|
{
|
|
if (outfitRenderTexture == null)
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("You need to set the Outfit Render Texture in the inspector!");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
renderTextureToUse = outfitRenderTexture;
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Debug.isDebugBuild)
|
|
Debug.Log("No suitable render texture found for " + wardrobeSlot + " using Body rendertexture");
|
|
renderTextureToUse = bodyRenderTexture;
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
#endif
|