squash commits
This commit is contained in:
@@ -0,0 +1,841 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UMA.CharacterSystem;
|
||||
using Unity.Collections;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
|
||||
/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
/// Are we missing // SkinnedMeshAligner.AlignBindPose(prefabMesh, resultingSkinnedMesh);
|
||||
/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
namespace UMA
|
||||
{
|
||||
public class DecalEditor : IEditorScene
|
||||
{
|
||||
static int instance = 0;
|
||||
int localInstance;
|
||||
Scene scene;
|
||||
InteractiveUMAWindow sceneView;
|
||||
private Rect infoRect = new Rect(10, 30, 400, 30);
|
||||
private GUIStyle whiteLabels;
|
||||
private GUIStyle blackLabels;
|
||||
private GameObject Character;
|
||||
private DynamicCharacterAvatar avatar;
|
||||
private GameObject sceneRoot;
|
||||
// UMA transform bones
|
||||
private Transform Root;
|
||||
private Transform Global;
|
||||
private Transform Position;
|
||||
|
||||
public Material ScreenBlocker;
|
||||
public Texture blockerTex;
|
||||
|
||||
private bool showHelp;
|
||||
private bool showRadius = true;
|
||||
private int savedLockedLayers;
|
||||
private DecalIndicator decalIndicator;
|
||||
private DecalManager decalManager;
|
||||
float currentRotation = 0;
|
||||
float distance = 0.006f;
|
||||
public Material decalMaterial;
|
||||
public List<string> RaceNames = new List<string>();
|
||||
int raceNumber = 0;
|
||||
|
||||
private GameObject VertexMarker;
|
||||
private GameObject PlanesMarker;
|
||||
|
||||
bool ShowSlotDialog = false;
|
||||
DecalDefinition SlotDecal;
|
||||
|
||||
private string SaveFolder;
|
||||
private string decalSlotName;
|
||||
int decalNum;
|
||||
|
||||
public int refVertexNumber;
|
||||
public Vector3 refVertexPosition;
|
||||
|
||||
NativeArray<byte> basebonesPerVertex;
|
||||
NativeArray<BoneWeight1> baseboneWeights;
|
||||
List<string> boneNames = new List<string>();
|
||||
|
||||
|
||||
public DecalEditor()
|
||||
{
|
||||
localInstance = instance;
|
||||
instance++;
|
||||
}
|
||||
|
||||
|
||||
[MenuItem("UMA/Interactive Decals (EXPERIMENTAL)")]
|
||||
public static void Init()
|
||||
{
|
||||
DecalEditor de = new DecalEditor();
|
||||
InteractiveUMAWindow.Init("UMA Decals - EXPERIMENTAL", de);
|
||||
}
|
||||
|
||||
private void ResetLabelStart()
|
||||
{
|
||||
infoRect = new Rect(10, 20, 400, 30);
|
||||
}
|
||||
|
||||
private void MoveToNextMessage(float xoffset, float yoffset)
|
||||
{
|
||||
infoRect.x += xoffset;
|
||||
infoRect.y += yoffset;
|
||||
}
|
||||
|
||||
private void DrawNextLabel(string lbl)
|
||||
{
|
||||
// Frame the text so it's visible everywhere
|
||||
MoveToNextMessage(-1, -1);
|
||||
GUI.Label(infoRect, lbl, blackLabels);
|
||||
MoveToNextMessage(2, 0);
|
||||
GUI.Label(infoRect, lbl, blackLabels);
|
||||
MoveToNextMessage(0, 2);
|
||||
GUI.Label(infoRect, lbl, blackLabels);
|
||||
MoveToNextMessage(-2, 0);
|
||||
GUI.Label(infoRect, lbl, blackLabels);
|
||||
MoveToNextMessage(1, -1);
|
||||
GUI.Label(infoRect, lbl, whiteLabels);
|
||||
MoveToNextMessage(0, 20);
|
||||
}
|
||||
|
||||
public void Initialize(InteractiveUMAWindow sceneView, Scene scene)
|
||||
{
|
||||
this.sceneView = sceneView;
|
||||
this.scene = scene;
|
||||
ResetLabelStart();
|
||||
whiteLabels = new GUIStyle(EditorStyles.boldLabel);
|
||||
blackLabels = new GUIStyle(EditorStyles.boldLabel);
|
||||
whiteLabels.normal.textColor = Color.white;
|
||||
blackLabels.normal.textColor = Color.black;
|
||||
}
|
||||
|
||||
void HelpWindow(int WindowID)
|
||||
{
|
||||
GUILayout.Label("Left click and drag to area select");
|
||||
GUILayout.Label("Hold SHIFT while dragging to ADD polygons");
|
||||
GUILayout.Label("Hold CTRL while dragging to REMOVE polygons");
|
||||
GUILayout.Label("Hold ALT while dragging to orbit");
|
||||
}
|
||||
|
||||
Plane GetPlaneInWorldSpace(GameObject planeObject)
|
||||
{
|
||||
// get the corners of the plane in worldspace
|
||||
// return new plane for those corners.
|
||||
|
||||
// 0, 10, 110
|
||||
|
||||
MeshFilter m = planeObject.GetComponent<MeshFilter>();
|
||||
Transform t = planeObject.transform;
|
||||
|
||||
Vector3 v0 = t.TransformPoint(m.sharedMesh.vertices[0]);
|
||||
Vector3 v2 = t.TransformPoint(m.sharedMesh.vertices[10]);
|
||||
Vector3 v1 = t.TransformPoint(m.sharedMesh.vertices[110]);
|
||||
#if SHOW_PLANES
|
||||
GameObject g1 = GameObject.Instantiate(PlanesMarker, v0, Quaternion.identity, Root);
|
||||
GameObject g2 = GameObject.Instantiate(PlanesMarker, v1, Quaternion.identity, Root);
|
||||
GameObject g3 = GameObject.Instantiate(PlanesMarker, v2, Quaternion.identity, Root);
|
||||
SceneManager.MoveGameObjectToScene(g1, scene);
|
||||
SceneManager.MoveGameObjectToScene(g2, scene);
|
||||
SceneManager.MoveGameObjectToScene(g3, scene);
|
||||
#endif
|
||||
return new Plane(v0, v1, v2);
|
||||
}
|
||||
|
||||
Plane[] GetPlanesInWorldspace()
|
||||
{
|
||||
Plane[] WorldspacePlanes = new Plane[6];
|
||||
|
||||
WorldspacePlanes[0] = GetPlaneInWorldSpace(decalIndicator.U1);
|
||||
WorldspacePlanes[1] = GetPlaneInWorldSpace(decalIndicator.U2);
|
||||
WorldspacePlanes[2] = GetPlaneInWorldSpace(decalIndicator.V1);
|
||||
WorldspacePlanes[3] = GetPlaneInWorldSpace(decalIndicator.V2);
|
||||
WorldspacePlanes[4] = GetPlaneInWorldSpace(decalIndicator.Front);
|
||||
WorldspacePlanes[5] = GetPlaneInWorldSpace(decalIndicator.Back);
|
||||
|
||||
return WorldspacePlanes;
|
||||
}
|
||||
|
||||
private void SlotDialog(int id)
|
||||
{
|
||||
GUILayout.BeginHorizontal(EditorStyles.toolbarButton);
|
||||
EditorGUILayout.LabelField("Save Slot",EditorStyles.boldLabel);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Select Folder", GUILayout.Width(100)))
|
||||
{
|
||||
SaveFolder = EditorUtility.OpenFolderPanel("Select destination folder", SaveFolder, "Decal_" + decalNum);
|
||||
PlayerPrefs.SetString("UMADecalFolder", SaveFolder);
|
||||
}
|
||||
GUILayout.Space(16);
|
||||
GUILayout.Label(SaveFolder);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Enter Name", GUILayout.Width(100));
|
||||
SlotDecal.Name = GUILayout.TextField(SlotDecal.Name);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(10);
|
||||
if (String.IsNullOrEmpty(SaveFolder))
|
||||
{
|
||||
GUILayout.Label("Select a folder to save the prefab");
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label(" ");
|
||||
}
|
||||
|
||||
GUILayout.Space(60);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("", GUILayout.ExpandWidth(true));
|
||||
|
||||
if (GUILayout.Button("Save",GUILayout.Width(60)))
|
||||
{
|
||||
if (string.IsNullOrEmpty(SaveFolder))
|
||||
{
|
||||
EditorUtility.DisplayDialog("error", "Please select a folder before saving the slot!", "OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
SaveSlot(SlotDecal);
|
||||
ShowSlotDialog = false;
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button("Exit",GUILayout.Width(60)))
|
||||
{
|
||||
ShowSlotDialog = false;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
void SaveSlot(DecalDefinition d)
|
||||
{
|
||||
SimpleDecal sd = d.DecalMeshObject.GetComponent<SimpleDecal>();
|
||||
sd.SaveDecal(d.Name, SaveFolder, true, Character.GetComponentInChildren<SkinnedMeshRenderer>(),d,VertexMarker,scene,sceneRoot);
|
||||
}
|
||||
|
||||
void DecalList(int WindowID)
|
||||
{
|
||||
DecalDefinition deleteMe = null;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
raceNumber = EditorGUILayout.Popup(raceNumber, RaceNames.ToArray(),GUILayout.ExpandWidth(true));
|
||||
|
||||
if (GUILayout.Button("Change Race",GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
if (raceNumber >= 0)
|
||||
{
|
||||
Debug.Log($"Changing race to {raceNumber}: {RaceNames[raceNumber]} ");
|
||||
string theRace = RaceNames[raceNumber];
|
||||
avatar.ForceRaceChange(theRace);
|
||||
avatar.GenerateSingleUMA();
|
||||
}
|
||||
|
||||
foreach (DecalDefinition d in decalManager.Decals)
|
||||
{
|
||||
if (d.DecalMeshObject != null)
|
||||
{
|
||||
GameObject.DestroyImmediate(d.DecalMeshObject);
|
||||
}
|
||||
}
|
||||
decalManager.Decals.Clear();
|
||||
}
|
||||
if (GUILayout.Button("Insp Char", GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
InspectorUtlity.InspectTarget(Character);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
decalNum = 1;
|
||||
foreach(DecalDefinition d in decalManager.Decals)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button(d.Name, GUILayout.ExpandWidth(true)))
|
||||
{
|
||||
Selection.activeGameObject = d.DecalMeshObject;
|
||||
sceneView.FrameSelected();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Insp",GUILayout.Width(42)))
|
||||
{
|
||||
InspectorUtlity.InspectTarget(d.DecalMeshObject);
|
||||
}
|
||||
if (GUILayout.Button("Save", GUILayout.Width(42)))
|
||||
{
|
||||
SlotDecal = d;
|
||||
SaveFolder = PlayerPrefs.GetString("UMADecalFolder", "");
|
||||
ShowSlotDialog = true;
|
||||
}
|
||||
if (GUILayout.Button("x",GUILayout.Width(20)))
|
||||
{
|
||||
deleteMe = d;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
decalNum++;
|
||||
}
|
||||
|
||||
if (deleteMe != null)
|
||||
{
|
||||
decalManager.Decals.Remove(deleteMe);
|
||||
if (deleteMe.DecalMeshObject != null)
|
||||
{
|
||||
GameObject.DestroyImmediate(deleteMe.DecalMeshObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneWindow(int WindowID)
|
||||
{
|
||||
if (decalIndicator == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float val = decalIndicator.transform.localScale.x;
|
||||
|
||||
float newval = EditorGUILayout.Slider("Decal Size", val, 0.0f, 1.0f);
|
||||
if (val != newval)
|
||||
{
|
||||
decalIndicator.transform.localScale = new Vector3(newval, newval, newval);
|
||||
EditorPrefs.SetFloat("DecalIndicatorScale", newval);
|
||||
}
|
||||
|
||||
float newRotation = EditorGUILayout.Slider("Decal Rotation", currentRotation, 0.0f, 360.0f);
|
||||
if (newRotation != currentRotation)
|
||||
{
|
||||
Vector3 localEuler = decalIndicator.LocalEuler;
|
||||
localEuler.z = newRotation;
|
||||
decalIndicator.transform.localEulerAngles = localEuler;
|
||||
currentRotation = newRotation;
|
||||
}
|
||||
|
||||
distance = EditorGUILayout.Slider("Decal Offset",distance, 0.001f, 0.02f);
|
||||
|
||||
showRadius = GUILayout.Toggle(showRadius, "Show indicator");
|
||||
if (GUI.changed)
|
||||
{
|
||||
decalIndicator.gameObject.SetActive(showRadius);
|
||||
}
|
||||
|
||||
var newMaterial = EditorGUILayout.ObjectField(decalMaterial, typeof(Material),false) as Material;
|
||||
|
||||
if (newMaterial != decalMaterial)
|
||||
{
|
||||
decalIndicator.visualPlane.GetComponent<MeshRenderer>().material = newMaterial;
|
||||
decalMaterial = newMaterial;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Capture current decal"))
|
||||
{
|
||||
// Todo: get all meshes
|
||||
Mesh bakedMesh = FreezeCurrentMesh(sceneView);
|
||||
|
||||
GameObject newDecal = GameObject.Instantiate(decalIndicator.visualPlane,Character.transform.position,Character.transform.rotation);
|
||||
|
||||
newDecal.transform.localScale= new Vector3(1f, 1f, 1f);
|
||||
MeshFilter DecalMeshFilter = newDecal.GetComponent<MeshFilter>();
|
||||
|
||||
Mesh decalMesh = Mesh.Instantiate(DecalMeshFilter.sharedMesh);
|
||||
|
||||
Vector3[] verts = DecalMeshFilter.sharedMesh.vertices;
|
||||
|
||||
PhysicsScene physcene = PhysicsSceneExtensions.GetPhysicsScene(scene);
|
||||
|
||||
Transform t = decalIndicator.visualPlane.transform;
|
||||
|
||||
Mesh characterMesh = avatar.umaData.GetRenderer(0).sharedMesh;
|
||||
|
||||
NativeArray<byte> basebonesPerVertex = characterMesh.GetBonesPerVertex();
|
||||
NativeArray<BoneWeight1> baseboneWeights = characterMesh.GetAllBoneWeights();
|
||||
Dictionary<int, int> VertexBoneWeightOffset = CalculateVertxBoneWeightOffsets(basebonesPerVertex,baseboneWeights);
|
||||
|
||||
List<BoneWeight1> newBoneWeights = new List<BoneWeight1>();
|
||||
List<byte> newBonesPerVertex = new List<byte>();
|
||||
|
||||
// logbones = true;
|
||||
FoundBones.Clear();
|
||||
|
||||
|
||||
for (int i=0;i<verts.Length;i++)
|
||||
{
|
||||
Vector3 src =t.TransformPoint(verts[i]);
|
||||
verts[i] = LocalRayHit(physcene, src , distance, bakedMesh,VertexBoneWeightOffset,basebonesPerVertex,baseboneWeights);
|
||||
if (lastboneWeights != null)
|
||||
{
|
||||
newBoneWeights.AddRange(lastboneWeights);
|
||||
newBonesPerVertex.Add((byte)lastboneWeights.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
BoneWeight1 nullBW = new BoneWeight1();
|
||||
nullBW.boneIndex = 0;
|
||||
nullBW.weight = 1.0f;
|
||||
|
||||
newBoneWeights.Add(nullBW);
|
||||
newBonesPerVertex.Add(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (FoundBones.Count > 0)
|
||||
{
|
||||
foreach(var kp in FoundBones)
|
||||
{
|
||||
Debug.Log($"FoundBone: {kp.Key}, {kp.Value} Hash {UMAUtils.StringToHash(kp.Value)}");
|
||||
}
|
||||
}
|
||||
|
||||
decalMesh.SetVertices(verts);
|
||||
DecalMeshFilter.mesh = decalMesh;
|
||||
decalMesh.RecalculateNormals();
|
||||
decalMesh.RecalculateTangents();
|
||||
decalMesh.RecalculateBounds();
|
||||
|
||||
var smr = newDecal.AddComponent<SkinnedMeshRenderer>();
|
||||
smr.sharedMesh = decalMesh;
|
||||
smr.updateWhenOffscreen = true;
|
||||
|
||||
SimpleDecal sd = newDecal.AddComponent<SimpleDecal>();
|
||||
|
||||
SkinnedMeshRenderer characterRenderer = Character.GetComponentInChildren<SkinnedMeshRenderer>();
|
||||
UMAData cData = avatar.umaData;
|
||||
|
||||
var boneHashNames = cData.skeleton.GetBoneHashNames();
|
||||
|
||||
int[] hashes = new int[boneHashNames.Count];
|
||||
string[] names = new string[boneHashNames.Count];
|
||||
|
||||
|
||||
for(int i=0;i<boneHashNames.Count;i++)
|
||||
{
|
||||
hashes[i] = boneHashNames[i].Key;
|
||||
names[i] = boneHashNames[i].Value;
|
||||
}
|
||||
|
||||
sd.Configure(names,hashes, newBonesPerVertex.ToArray(), newBoneWeights.ToArray());
|
||||
SceneManager.MoveGameObjectToScene(newDecal, scene);
|
||||
|
||||
DecalManager dm = Character.GetComponentInChildren<DecalManager>();
|
||||
|
||||
DecalDefinition dd = new DecalDefinition();
|
||||
dd.bakedMesh = bakedMesh;
|
||||
|
||||
dd.planesInWorldSpace = GetPlanesInWorldspace();
|
||||
dd.WorldImpactPoint = decalIndicator.gameObject.transform.position;
|
||||
dd.LocalImpactPoint = avatar.gameObject.transform.InverseTransformPoint(dd.WorldImpactPoint);
|
||||
|
||||
int MaxIndex = 0;
|
||||
foreach(DecalDefinition cd in dm.Decals)
|
||||
{
|
||||
if (cd.material.name == decalMaterial.name)
|
||||
{
|
||||
if (cd.InitialIndex > MaxIndex)
|
||||
{
|
||||
MaxIndex = cd.InitialIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dd.InitialIndex = MaxIndex + 1;
|
||||
dd.Name = decalMaterial.name + "_" + dd.InitialIndex;
|
||||
|
||||
dd.material = decalMaterial;
|
||||
dd.DecalMeshObject = newDecal;
|
||||
|
||||
dm.Decals.Add(dd);
|
||||
|
||||
// DecalMeshFilter.sharedMesh.SetVertices(verts);
|
||||
// get all vertexes in the circle,
|
||||
// get all triangles that face the camera.
|
||||
// build new triangle list for the submesh
|
||||
|
||||
/*
|
||||
List<Vector3> verts = new List<Vector3>();
|
||||
List<int> decalVerts = new List<int>();
|
||||
m.GetVertices(verts);
|
||||
|
||||
|
||||
|
||||
for(int i=0;i<verts.Count;i++)
|
||||
{
|
||||
Vector3 meshvert = verts[i];
|
||||
Vector3 Delta = meshvert - decalIndicator.transform.localPosition;
|
||||
|
||||
if (Delta.magnitude < decalIndicator.transform.localScale.x)
|
||||
{
|
||||
decalVerts.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (decalVerts.Count > 0)
|
||||
{
|
||||
// find all the triangles for the new decal.
|
||||
//
|
||||
}
|
||||
// Save decal information needed for submesh.
|
||||
// Add the submesh.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<int, int> CalculateVertxBoneWeightOffsets(NativeArray<byte> basebonesPerVertex, NativeArray<BoneWeight1> baseboneWeights)
|
||||
{
|
||||
Dictionary<int, int> offsets = new Dictionary<int, int>();
|
||||
|
||||
int offset = 0;
|
||||
for(int i=0;i<basebonesPerVertex.Length;i++)
|
||||
{
|
||||
offsets.Add(i, offset);
|
||||
offset += basebonesPerVertex[i];
|
||||
}
|
||||
return offsets;
|
||||
}
|
||||
|
||||
public void Cleanup(InteractiveUMAWindow scene)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnSceneGUI(InteractiveUMAWindow sceneView)
|
||||
{
|
||||
ProcessEvents(sceneView);
|
||||
|
||||
const float WindowHeight = 140;
|
||||
const float WindowWidth = 380;
|
||||
const float Margin = 20;
|
||||
Handles.BeginGUI();
|
||||
if (ShowSlotDialog)
|
||||
{
|
||||
Rect ScrBox = new Rect(0, 0, sceneView.position.width, sceneView.position.height);
|
||||
// EditorGUI.DrawPreviewTexture(ScrBox,blockerTex, ScreenBlocker,ScaleMode.StretchToFill);
|
||||
GUI.DrawTexture(ScrBox, blockerTex, ScaleMode.StretchToFill, true, 0, new Color(0, 0, 0, 0.8f), 0, 0);
|
||||
//GUI.Box(ScrBox, blockerTex);
|
||||
GUI.Window(3, new Rect((sceneView.position.width/2) - 250, (sceneView.position.height/2) - 150, 500, 200), SlotDialog, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (showHelp)
|
||||
{
|
||||
// GUI.Window(2, new Rect(10, 20, 280, 104), HelpWindow, "");
|
||||
GUI.Window(2, new Rect(10, 20, 300, 300), DecalList, "");
|
||||
}
|
||||
GUI.Window(1, new Rect(sceneView.position.width - (WindowWidth + Margin), sceneView.position.height - (WindowHeight + Margin), WindowWidth, WindowHeight), SceneWindow, "Interactive Decals");
|
||||
}
|
||||
Handles.EndGUI();
|
||||
}
|
||||
|
||||
|
||||
BoneWeight1[] lastboneWeights = null;
|
||||
|
||||
private bool logbones = false;
|
||||
private Dictionary<int, string> FoundBones = new Dictionary<int, string>();
|
||||
|
||||
private Vector3 LocalRayHit(PhysicsScene physcene, Vector3 vert, float offset, Mesh theMesh,
|
||||
Dictionary<int, int> VertexBoneWeightOffset,
|
||||
NativeArray<byte> basebonesPerVertex,
|
||||
NativeArray<BoneWeight1> baseboneWeights)
|
||||
{
|
||||
lastboneWeights = null;
|
||||
// get world position of hit.
|
||||
// translate to local coordinates of character.
|
||||
//
|
||||
Ray ray = new Ray(vert, decalIndicator.Ray.direction);
|
||||
RaycastHit hit;
|
||||
|
||||
|
||||
Debug.DrawRay(vert, decalIndicator.Ray.direction, Color.green,30.0f);
|
||||
// Rays.Add(ray);
|
||||
|
||||
if (!physcene.Raycast(ray.origin, ray.direction, out hit, 512.0f, LayerMask.GetMask("Player")))
|
||||
{
|
||||
Debug.Log("Ray did not hit");
|
||||
return vert;
|
||||
}
|
||||
|
||||
if (hit.triangleIndex < 0)
|
||||
{
|
||||
return vert;
|
||||
}
|
||||
|
||||
Vector3 hitpoint = hit.point + ((decalIndicator.Ray.direction.normalized * -1) * offset);
|
||||
|
||||
Vector3 LocalHitpoint = hit.transform.InverseTransformPoint(hitpoint);
|
||||
|
||||
|
||||
// Transform umaTransform = GetUMATransform(hit.transform);
|
||||
|
||||
|
||||
|
||||
for (int i = 0; i < theMesh.subMeshCount; i++)
|
||||
{
|
||||
var smd = theMesh.GetSubMesh(i);
|
||||
if (hit.triangleIndex < smd.indexStart)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hit.triangleIndex >= (smd.indexStart + (smd.indexCount/3)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// should fall through for only ONE submesh.
|
||||
int[] tris = theMesh.GetTriangles(i);
|
||||
int submishtricount = smd.indexCount / 3;
|
||||
int baseIndexStart = hit.triangleIndex - smd.indexStart;
|
||||
int tribase = 3 * (hit.triangleIndex - smd.indexStart);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
int v1x = tris[tribase];
|
||||
int v2x = tris[tribase + 1];
|
||||
int v3x = tris[tribase + 2];
|
||||
|
||||
Vector3 v1 = theMesh.vertices[v1x];
|
||||
Vector3 v2 = theMesh.vertices[v2x];
|
||||
Vector3 v3 = theMesh.vertices[v3x];
|
||||
|
||||
|
||||
#if LOCAL_SPACE
|
||||
// lastboneWeights = GetBoneWeights(LocalHitpoint, v1, v2, v3, v1x, v2x, v3x, VertexBoneWeightOffset, basebonesPerVertex, baseboneWeights);
|
||||
#else
|
||||
Matrix4x4 theMat = Character.transform.localToWorldMatrix;
|
||||
|
||||
v1 = theMat * v1;
|
||||
v2 = theMat * v2;
|
||||
v3 = theMat * v3;
|
||||
lastboneWeights = GetBoneWeights(hitpoint, v1, v2, v3, v1x, v2x, v3x, VertexBoneWeightOffset, basebonesPerVertex, baseboneWeights);
|
||||
#endif
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return LocalHitpoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="Hit"></param>
|
||||
/// <param name="v1"></param>
|
||||
/// <param name="v2"></param>
|
||||
/// <param name="v3"></param>
|
||||
/// <param name="v1x"></param>
|
||||
/// <param name="v2x"></param>
|
||||
/// <param name="v3x"></param>
|
||||
/// <param name="VertexBoneWeightOffset"> this is a dictionary calculated from the following two. It translates a vertex to the starting index by adding up all the BonesPerVertex of preceding verts</param>
|
||||
/// <param name="basebonesPerVertex"></param>
|
||||
/// <param name="baseboneWeights"></param>
|
||||
/// <returns></returns>
|
||||
private BoneWeight1[] GetBoneWeights(Vector3 Hit, Vector3 v1, Vector3 v2, Vector3 v3,
|
||||
int v1x, int v2x, int v3x,
|
||||
Dictionary<int,int> VertexBoneWeightOffset,
|
||||
NativeArray<byte> basebonesPerVertex,
|
||||
NativeArray<BoneWeight1> baseboneWeights)
|
||||
{
|
||||
Dictionary<int, float> boneDictionary = new Dictionary<int, float>();
|
||||
List<BoneWeight1> boneWeights = new List<BoneWeight1>();
|
||||
|
||||
float v1len = Mathf.Abs((Hit - v1).magnitude);
|
||||
float v2len = Mathf.Abs((Hit - v2).magnitude);
|
||||
float v3len = Mathf.Abs((Hit - v3).magnitude);
|
||||
|
||||
float totalDistance = v1len + v2len + v3len;
|
||||
|
||||
float v1Perc = v1len / totalDistance;
|
||||
float v2Perc = v2len / totalDistance;
|
||||
float v3Perc = v3len / totalDistance;
|
||||
|
||||
AddBoneWeights(boneDictionary, v1Perc, v1x, VertexBoneWeightOffset, basebonesPerVertex, baseboneWeights);
|
||||
AddBoneWeights(boneDictionary, v2Perc, v2x, VertexBoneWeightOffset, basebonesPerVertex, baseboneWeights);
|
||||
AddBoneWeights(boneDictionary, v3Perc, v3x, VertexBoneWeightOffset, basebonesPerVertex, baseboneWeights);
|
||||
|
||||
foreach(var kp in boneDictionary)
|
||||
{
|
||||
BoneWeight1 b = new BoneWeight1();
|
||||
b.boneIndex = kp.Key;
|
||||
b.weight = kp.Value;
|
||||
boneWeights.Add(b);
|
||||
}
|
||||
boneWeights.Sort((a, b) => (0-(a.weight.CompareTo(b.weight))));
|
||||
return boneWeights.ToArray();
|
||||
}
|
||||
|
||||
private void AddBoneWeights(Dictionary<int, float> boneDictionary,float percentage, int vertexnumber,
|
||||
Dictionary<int, int> VertexBoneWeightOffset,
|
||||
NativeArray<byte> basebonesPerVertex,
|
||||
NativeArray<BoneWeight1> baseboneWeights)
|
||||
{
|
||||
int boneStart = VertexBoneWeightOffset[vertexnumber];
|
||||
int numBones = basebonesPerVertex[vertexnumber];
|
||||
for(int i = boneStart; i < (boneStart + numBones); i++)
|
||||
{
|
||||
BoneWeight1 b = baseboneWeights[i];
|
||||
#if _INDEX
|
||||
if (!boneDictionary.ContainsKey(b.boneIndex)) boneDictionary.Add(b.boneIndex, 0.0f);
|
||||
boneDictionary[b.boneIndex] += b.weight * percentage;
|
||||
#else
|
||||
int boneNum = b.boneIndex;
|
||||
int boneHash = UMAUtils.StringToHash(boneNames[boneNum]);
|
||||
|
||||
if (!boneDictionary.ContainsKey(boneHash))
|
||||
{
|
||||
boneDictionary.Add(boneHash, 0.0f);
|
||||
}
|
||||
|
||||
boneDictionary[boneHash] += b.weight * percentage;
|
||||
|
||||
#endif
|
||||
if (logbones)
|
||||
{
|
||||
if (FoundBones.ContainsKey(b.boneIndex) == false)
|
||||
{
|
||||
FoundBones.Add(b.boneIndex, boneNames[b.boneIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
//logbones = false;
|
||||
}
|
||||
|
||||
private void ProcessEvents(InteractiveUMAWindow sceneView)
|
||||
{
|
||||
if (Event.current != null && Event.current.type == EventType.MouseDown && Event.current.button == 0)
|
||||
{
|
||||
FreezeCurrentMesh(sceneView);
|
||||
Ray ray = sceneView.GUIPointToWorldRay(Event.current.mousePosition);
|
||||
|
||||
RaycastHit hit;
|
||||
PhysicsScene physcene = PhysicsSceneExtensions.GetPhysicsScene(sceneView.CurrentScene);
|
||||
if (!physcene.Raycast(ray.origin, ray.direction, out hit, 512.0f, LayerMask.GetMask("Player")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (decalIndicator != null)
|
||||
{
|
||||
if ((hit.transform.gameObject == sceneView.avatarGo) || (hit.transform.parent == sceneView.avatarGo.transform))
|
||||
{
|
||||
// Event.current.Use();
|
||||
// Indicator.transform.position = hit.point;
|
||||
decalIndicator.gameObject.transform.position = hit.point;
|
||||
decalIndicator.Ray = ray;
|
||||
decalIndicator.gameObject.transform.forward = ray.direction;
|
||||
decalIndicator.LocalEuler = decalIndicator.gameObject.transform.localEulerAngles;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Mesh FreezeCurrentMesh(InteractiveUMAWindow sceneView)
|
||||
{
|
||||
SkinnedMeshRenderer smr = sceneView.avatarGo.GetComponentInChildren<SkinnedMeshRenderer>();
|
||||
|
||||
boneNames.Clear();
|
||||
var t = smr.bones;
|
||||
for (int i=0;i<t.Length;i++)
|
||||
{
|
||||
boneNames.Add(t[i].name);
|
||||
}
|
||||
MeshCollider mc = sceneView.avatarGo.GetComponentInChildren<MeshCollider>();
|
||||
if (smr != null)
|
||||
{
|
||||
Mesh mesh = new Mesh();
|
||||
smr.BakeMesh(mesh);
|
||||
|
||||
Physics.BakeMesh(mesh.GetInstanceID(), false);
|
||||
mc.sharedMesh = mesh;
|
||||
Physics.SyncTransforms();
|
||||
return mesh;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ShowHelp(bool isShown)
|
||||
{
|
||||
showHelp = isShown;
|
||||
}
|
||||
|
||||
public Material FindBlockerMaterial(GameObject root)
|
||||
{
|
||||
MeshRenderer[] mrs = root.GetComponentsInChildren<MeshRenderer>();
|
||||
|
||||
foreach (MeshRenderer r in mrs)
|
||||
{
|
||||
if (r.gameObject.name == "screenBlocker")
|
||||
{
|
||||
return r.sharedMaterial;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void InitializationComplete(GameObject root)
|
||||
{
|
||||
sceneRoot = root;
|
||||
float scale = EditorPrefs.GetFloat("DecalIndicatorScale", 1.0f);
|
||||
decalIndicator = root.GetComponentInChildren<DecalIndicator>();
|
||||
|
||||
this.ScreenBlocker = FindBlockerMaterial(root);
|
||||
string[] texs = ScreenBlocker.GetTexturePropertyNames();
|
||||
foreach(string s in texs)
|
||||
{
|
||||
Texture tex = ScreenBlocker.GetTexture(s);
|
||||
if (tex != null)
|
||||
{
|
||||
blockerTex = tex;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Transform t in root.transform)
|
||||
{
|
||||
if (t.name == "Sphere")
|
||||
{
|
||||
PlanesMarker = t.gameObject;
|
||||
}
|
||||
|
||||
if (t.name == "VertexMarker")
|
||||
{
|
||||
VertexMarker = t.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
if (decalIndicator != null)
|
||||
{
|
||||
decalIndicator.transform.localScale = new Vector3(scale, scale, scale);
|
||||
}
|
||||
avatar = root.GetComponentInChildren<DynamicCharacterAvatar>();
|
||||
Character = avatar.gameObject;
|
||||
decalManager = root.GetComponentInChildren<DecalManager>();
|
||||
|
||||
var races = UMAAssetIndexer.Instance.GetAllAssets<RaceData>();
|
||||
|
||||
|
||||
foreach(RaceData r in races)
|
||||
{
|
||||
if (r.raceName == avatar.activeRace.name)
|
||||
{
|
||||
raceNumber = RaceNames.Count;
|
||||
}
|
||||
RaceNames.Add(r.raceName);
|
||||
}
|
||||
|
||||
var mr = decalIndicator.visualPlane.GetComponent<MeshRenderer>();
|
||||
if (mr != null)
|
||||
{
|
||||
decalMaterial = mr.sharedMaterial;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7aca515d4e40c624c8db3b66e9a6c63e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 35611
|
||||
packageName: UMA 2
|
||||
packageVersion: 2.13
|
||||
assetPath: Assets/UMA/Core/Editor/Decals/DecalEditor.cs
|
||||
uploadId: 679826
|
||||
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class GameObjectTreeViewItem : MonoBehaviour
|
||||
{
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b60b7fae88d7a54bb2c4fd9f5593461
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 35611
|
||||
packageName: UMA 2
|
||||
packageVersion: 2.13
|
||||
assetPath: Assets/UMA/Core/Editor/Decals/GameObjectTreeViewItem.cs
|
||||
uploadId: 679826
|
||||
@@ -0,0 +1,14 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace UMA
|
||||
{
|
||||
public interface IEditorScene
|
||||
{
|
||||
void OnSceneGUI(InteractiveUMAWindow scene);
|
||||
void Initialize(InteractiveUMAWindow sceneView, Scene scene);
|
||||
void InitializationComplete(GameObject root);
|
||||
void Cleanup(InteractiveUMAWindow scene);
|
||||
void ShowHelp(bool isShown);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f14d5c18226f034bbe531ed3b5b3d23
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 35611
|
||||
packageName: UMA 2
|
||||
packageVersion: 2.13
|
||||
assetPath: Assets/UMA/Core/Editor/Decals/IEditorScene.cs
|
||||
uploadId: 679826
|
||||
@@ -0,0 +1,334 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UMA.CharacterSystem;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UMA;
|
||||
using UnityEditor.Compilation;
|
||||
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
// Get rid of the annoying icon not found error.
|
||||
[EditorWindowTitle(icon = "", title = "InteractiveWindow", useTypeNameAsIconName = false)]
|
||||
#endif
|
||||
public class InteractiveUMAWindow : SceneView
|
||||
{
|
||||
bool isInitialized;
|
||||
string UMAPrefab = "";
|
||||
GameObject EnvironmentPrefab;
|
||||
public GameObject libGo;
|
||||
public GameObject avatarGo;
|
||||
public DynamicCharacterAvatar avatar;
|
||||
public IEditorScene editor;
|
||||
public Scene CurrentScene;
|
||||
private static GUIStyle bsNormal = null;
|
||||
private static GUIStyle bsToggled = null;
|
||||
private string[] cameraModeNames = { "Textured", "Textured Wireframe", "Wireframe" };
|
||||
private DrawCameraMode[] cameraModes = { DrawCameraMode.Textured, DrawCameraMode.TexturedWire, DrawCameraMode.Wireframe };
|
||||
private int camMode = 0;
|
||||
private int savedLockedLayers;
|
||||
private static List<InteractiveUMAWindow> Windows = new List<InteractiveUMAWindow>();
|
||||
public GameObject Indicator;
|
||||
//private GameObject capsule;
|
||||
public static string WindowName;
|
||||
private bool showHelp = true;
|
||||
|
||||
private static Dictionary<string, InteractiveUMAWindow> windows = new Dictionary<string, InteractiveUMAWindow>();
|
||||
|
||||
public static void Init(string windowName, IEditorScene editor)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("Error", "The UMA Interactive window does not work in playmode", "OK"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (windows.ContainsKey(windowName))
|
||||
{
|
||||
InteractiveUMAWindow window = windows[windowName];
|
||||
window.Close();
|
||||
}
|
||||
|
||||
|
||||
bsNormal = "Button";
|
||||
bsToggled = new GUIStyle(bsNormal);
|
||||
bsToggled.normal.background = bsToggled.active.background;
|
||||
WindowName = windowName;
|
||||
var w = GetWindow<InteractiveUMAWindow>(WindowName, true, typeof(SceneView));
|
||||
if (w == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Error", "Unable to create or get Interactive UMA window!", "OK");
|
||||
return;
|
||||
}
|
||||
w.editor = editor;
|
||||
//w.InitializeIfNeeded();
|
||||
w.showGrid = false;
|
||||
w.drawGizmos = false;
|
||||
w.sceneLighting = true;
|
||||
w.SetCameraMode(w.camMode);
|
||||
w.Focus();
|
||||
AppDomain.CurrentDomain.DomainUnload += CurrentDomain_DomainUnload;
|
||||
}
|
||||
|
||||
public bool ShowToggleButton(string txt, bool initialValue, params GUILayoutOption[] Options)
|
||||
{
|
||||
if (GUILayout.Button(txt, initialValue ? bsToggled : bsNormal, Options))
|
||||
{
|
||||
initialValue = !initialValue;
|
||||
}
|
||||
return initialValue;
|
||||
}
|
||||
|
||||
public bool ShowToggleButton(GUIContent content, bool initialValue, params GUILayoutOption[] Options)
|
||||
{
|
||||
if (GUILayout.Button(content, initialValue ? bsToggled : bsNormal, Options))
|
||||
{
|
||||
initialValue = !initialValue;
|
||||
}
|
||||
return initialValue;
|
||||
}
|
||||
|
||||
|
||||
public void SetCameraMode(int mode)
|
||||
{
|
||||
DrawCameraMode newMode = cameraModes[mode];
|
||||
CameraMode currentMode = this.cameraMode;
|
||||
|
||||
if (currentMode.drawMode == newMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cameraMode = SceneView.GetBuiltinCameraMode(newMode);
|
||||
}
|
||||
|
||||
protected override void OnSceneGUI()
|
||||
{
|
||||
InitializeIfNeeded();
|
||||
if (bsToggled == null)
|
||||
{
|
||||
// lost it all...
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
drawGizmos = ShowToggleButton("Gizmos:" + drawGizmos, drawGizmos, GUILayout.ExpandWidth(false));
|
||||
sceneLighting = ShowToggleButton("Lighting:" + sceneLighting, sceneLighting, GUILayout.ExpandWidth(false));
|
||||
showHelp = ShowToggleButton("Help:" + showHelp, showHelp, GUILayout.ExpandWidth(false));
|
||||
camMode = EditorGUILayout.Popup(camMode, cameraModeNames, GUILayout.ExpandWidth(false));
|
||||
editor.ShowHelp(showHelp);
|
||||
SetCameraMode(camMode);
|
||||
GUILayout.Button("", GUILayout.ExpandWidth(true));
|
||||
if (GUILayout.Button("Focus Avatar", GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
Selection.activeGameObject = avatar.gameObject;
|
||||
avatar.gameObject.SetActive(true);
|
||||
FrameSelected();
|
||||
}
|
||||
}
|
||||
base.OnSceneGUI();
|
||||
}
|
||||
|
||||
|
||||
private void InitializeIfNeeded()
|
||||
{
|
||||
if (isInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (UMAPrefab == "")
|
||||
{
|
||||
string[] assets = AssetDatabase.FindAssets("UMADefaultUtilityEnvironment");
|
||||
if (assets == null || assets.Length < 1)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Error", "Unable to find UMADefaultUtilityEnvironment Prefab!", "OK");
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
UMAPrefab = AssetDatabase.GUIDToAssetPath(assets[0]);
|
||||
}
|
||||
|
||||
|
||||
customScene = EditorSceneManager.NewPreviewScene();
|
||||
CurrentScene = customScene;
|
||||
sceneLighting = true;
|
||||
drawGizmos = true;
|
||||
editor.Initialize(this, customScene);
|
||||
|
||||
EnvironmentPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(UMAPrefab);
|
||||
libGo = GameObject.Instantiate(EnvironmentPrefab);
|
||||
SceneManager.MoveGameObjectToScene(libGo, customScene);
|
||||
|
||||
avatar = libGo.GetComponentInChildren<DynamicCharacterAvatar>();
|
||||
avatarGo = avatar.gameObject;
|
||||
// cube = libGo.GetComponentInChildren<BoxCollider>().gameObject;
|
||||
// sphere = libGo.GetComponentInChildren<SphereCollider>().gameObject;
|
||||
//capsule = libGo.GetComponentInChildren<CapsuleCollider>().gameObject;
|
||||
|
||||
Selection.activeObject = avatarGo;
|
||||
// Zoom the scene view into the new object
|
||||
bool val = FrameSelected(true, true);
|
||||
Repaint();
|
||||
|
||||
avatar.InitialStartup();
|
||||
isInitialized = true;
|
||||
editor.InitializationComplete(libGo);
|
||||
}
|
||||
|
||||
public void OnFocus()
|
||||
{
|
||||
if (avatarGo != null)
|
||||
{
|
||||
Selection.activeTransform = avatarGo.transform;
|
||||
FrameSelected();
|
||||
}
|
||||
savedLockedLayers = Tools.lockedLayers;
|
||||
Tools.lockedLayers = ~LayerMask.GetMask("Player");
|
||||
}
|
||||
|
||||
public void OnLostFocus()
|
||||
{
|
||||
Debug.Log("lost focus");
|
||||
Tools.lockedLayers = savedLockedLayers;
|
||||
}
|
||||
|
||||
private void EditorChanged(PlayModeStateChange state)
|
||||
{
|
||||
// stop the gazillion errors trying to get the controls
|
||||
|
||||
CloseCleanup();
|
||||
}
|
||||
|
||||
private static void CurrentDomain_DomainUnload(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public new void OnDestroy()
|
||||
{
|
||||
Cleanup();
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
try
|
||||
{
|
||||
//InitializeIfNeeded(); Don't ever do this
|
||||
base.OnEnable();
|
||||
titleContent = new GUIContent(WindowName);
|
||||
EditorApplication.playModeStateChanged += EditorChanged;
|
||||
CompilationPipeline.compilationStarted += CompilationPipeline_assemblyCompilationStarted;
|
||||
duringSceneGui += InteractiveUMAWindow_duringSceneGui;
|
||||
}
|
||||
catch (Exception) { };
|
||||
}
|
||||
|
||||
private void InteractiveUMAWindow_duringSceneGui(SceneView obj)
|
||||
{
|
||||
if (this != null)
|
||||
{
|
||||
//Rect rect = new Rect(0, 0, position.width, position.height);
|
||||
//using (new GUILayout.AreaScope(rect))
|
||||
//{
|
||||
if (obj == this)
|
||||
{
|
||||
editor.OnSceneGUI(this);
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 GUIPointToScreenPixelCoordinate(Vector2 guiPoint)
|
||||
{
|
||||
return HandleUtility.GUIPointToScreenPixelCoordinate(guiPoint);
|
||||
}
|
||||
|
||||
public Ray GUIPointToWorldRay(Vector2 position, float startZ = float.NegativeInfinity)
|
||||
{
|
||||
if (float.IsNegativeInfinity(startZ))
|
||||
{
|
||||
startZ = camera.nearClipPlane;
|
||||
}
|
||||
|
||||
Vector2 screenPixelPos = GUIPointToScreenPixelCoordinate(position);
|
||||
Rect viewport = camera.pixelRect;
|
||||
|
||||
Matrix4x4 camToWorld = camera.cameraToWorldMatrix;
|
||||
Matrix4x4 camToClip = camera.projectionMatrix;
|
||||
Matrix4x4 clipToCam = camToClip.inverse;
|
||||
|
||||
// calculate ray origin and direction in world space
|
||||
Vector3 rayOriginWorldSpace;
|
||||
Vector3 rayDirectionWorldSpace;
|
||||
|
||||
// first construct an arbitrary point that is on the ray through this screen pixel (remap screen pixel point to clip space [-1, 1])
|
||||
Vector3 rayPointClipSpace = new Vector3(
|
||||
(screenPixelPos.x - viewport.x) * 2.0f / viewport.width - 1.0f,
|
||||
(screenPixelPos.y - viewport.y) * 2.0f / viewport.height - 1.0f,
|
||||
0.95f
|
||||
);
|
||||
|
||||
// and convert that point to camera space
|
||||
Vector3 rayPointCameraSpace = clipToCam.MultiplyPoint(rayPointClipSpace);
|
||||
|
||||
|
||||
// in projective mode, the ray passes through the origin in camera space
|
||||
// so the ray direction is just (ray point - origin) == (ray point)
|
||||
Vector3 rayDirectionCameraSpace = rayPointCameraSpace;
|
||||
rayDirectionCameraSpace.Normalize();
|
||||
|
||||
rayDirectionWorldSpace = camToWorld.MultiplyVector(rayDirectionCameraSpace);
|
||||
|
||||
// calculate the correct startZ offset from the camera by moving a distance along the ray direction
|
||||
// this assumes camToWorld is a pure rotation/offset, with no scale, so we can use rayDirection.z to calculate how far we need to move
|
||||
Vector3 cameraPositionWorldSpace = camToWorld.MultiplyPoint(Vector3.zero);
|
||||
// The camera/projection matrices follow OpenGL convention: positive Z is towards the viewer.
|
||||
// So negate it to get into Unity convention.
|
||||
Vector3 originOffsetWorldSpace = rayDirectionWorldSpace * -startZ / rayDirectionCameraSpace.z;
|
||||
rayOriginWorldSpace = cameraPositionWorldSpace + originOffsetWorldSpace;
|
||||
|
||||
return new Ray(rayOriginWorldSpace, rayDirectionWorldSpace);
|
||||
}
|
||||
|
||||
|
||||
private void CompilationPipeline_assemblyCompilationStarted(object obj)
|
||||
{
|
||||
CloseCleanup();
|
||||
}
|
||||
|
||||
public void CloseCleanup()
|
||||
{
|
||||
Cleanup();
|
||||
Close();
|
||||
}
|
||||
|
||||
public override void OnDisable()
|
||||
{
|
||||
Debug.Log("On Disable");
|
||||
base.OnDisable();
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
private void Cleanup()
|
||||
{
|
||||
if (isInitialized)
|
||||
{
|
||||
isInitialized = false;
|
||||
editor.Cleanup(this);
|
||||
if (customScene != null)
|
||||
{
|
||||
Scene s = customScene;
|
||||
EditorSceneManager.ClosePreviewScene(s);
|
||||
}
|
||||
EditorApplication.playModeStateChanged -= EditorChanged;
|
||||
CompilationPipeline.compilationStarted -= CompilationPipeline_assemblyCompilationStarted;
|
||||
duringSceneGui -= InteractiveUMAWindow_duringSceneGui;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f91282e70d6b76b4b80ea9341c8fcbff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 35611
|
||||
packageName: UMA 2
|
||||
packageVersion: 2.13
|
||||
assetPath: Assets/UMA/Core/Editor/Decals/InteractiveWindow.cs
|
||||
uploadId: 679826
|
||||
Reference in New Issue
Block a user