public static bool FindTriangle(this SpriteMeshData spriteMeshData, Vector2 point, out Vector3Int indices, out Vector3 barycentricCoords) { indices = Vector3Int.zero; barycentricCoords = Vector3.zero; if (spriteMeshData.indices.Count < 3) { return(false); } int triangleCount = spriteMeshData.indices.Count / 3; for (int i = 0; i < triangleCount; ++i) { indices.x = spriteMeshData.indices[i * 3]; indices.y = spriteMeshData.indices[i * 3 + 1]; indices.z = spriteMeshData.indices[i * 3 + 2]; MeshModuleUtility.Barycentric( point, spriteMeshData.vertices[indices.x].position, spriteMeshData.vertices[indices.y].position, spriteMeshData.vertices[indices.z].position, out barycentricCoords); if (barycentricCoords.x >= 0f && barycentricCoords.y >= 0f && barycentricCoords.z >= 0f) { return(true); } } return(false); }
private bool SegmentIntersectsEdge(Vector2 p1, Vector2 p2, int ignoreIndex, ref Vector2 point, out int intersectingEdgeIndex) { intersectingEdgeIndex = -1; float sqrDistance = float.MaxValue; for (int i = 0; i < spriteMeshData.edges.Count; i++) { Edge edge = spriteMeshData.edges[i]; Vector2 v1 = spriteMeshData.vertices[edge.index1].position; Vector2 v2 = spriteMeshData.vertices[edge.index2].position; Vector2 pointTmp = Vector2.zero; if (!edge.Contains(ignoreIndex) && MeshModuleUtility.SegmentIntersection(p1, p2, v1, v2, ref pointTmp)) { float sqrMagnitude = (pointTmp - p1).sqrMagnitude; if (sqrMagnitude < sqrDistance) { sqrDistance = sqrMagnitude; intersectingEdgeIndex = i; point = pointTmp; } } } return(intersectingEdgeIndex != -1); }
public static List <SpriteBoneData> CreateSpriteBoneData(List <SpriteBone> spriteBoneList, Matrix4x4 rootMatrix) { List <SpriteBoneData> spriteBoneDataList = new List <SpriteBoneData>(spriteBoneList.Count); foreach (var spriteBone in spriteBoneList) { spriteBoneDataList.Add(new SpriteBoneData() { name = spriteBone.name, parentId = spriteBone.parentId, localPosition = spriteBone.position, localRotation = spriteBone.rotation, depth = spriteBone.position.z, length = spriteBone.length }); } Matrix4x4[] localToWorldMatrices = null; MeshModuleUtility.UpdateLocalToWorldMatrices(spriteBoneDataList, rootMatrix, ref localToWorldMatrices); for (int i = 0; i < spriteBoneDataList.Count; ++i) { var spriteBoneData = spriteBoneDataList[i]; spriteBoneData.position = localToWorldMatrices[i].MultiplyPoint(Vector2.zero); spriteBoneData.endPosition = localToWorldMatrices[i].MultiplyPoint(Vector2.right * spriteBoneData.length); } return(spriteBoneDataList); }
public void LayoutEdge(Vector2 startPosition, Vector2 endPosition, int index) { int controlID = guiWrapper.GetControlID(m_EdgeHashCode, FocusType.Passive); float distance = guiWrapper.DistanceToSegment(startPosition, endPosition); guiWrapper.LayoutControl(controlID, distance); if (guiWrapper.eventType == EventType.Layout) { if (guiWrapper.IsControlNearest(controlID)) { m_HoveredEdge = index; m_HoveredEdgeControlID = controlID; } distance = HandleUtility.DistancePointToLineSegment(MeshModuleUtility.ClampPositionToRect(mouseWorldPosition, frame), startPosition, endPosition); if (distance < m_MinDistance) { m_MinDistance = distance; m_ClosestEdgeIndex = index; } } }
private void HandleRotateBone() { if (bindPoseView.IsActionTriggering(BindPoseAction.RotateBone)) { m_PreviewChanged = false; undoObject.RegisterCompleteObjectUndo("Rotate Bone"); UpdateBones(); } if (bindPoseView.IsActionFinishing(BindPoseAction.RotateBone)) { m_PreviewChanged = true; undoObject.RevertAllInCurrentGroup(); UpdateBones(); } Vector2 lookAtPosition; if (bindPoseView.DoRotateBone(out lookAtPosition)) { if (selection.single == -1) { throw new ArgumentException("no bone or multiple bone selected"); } var spriteBoneData = spriteMeshData.bones[selection.single]; var localLookAtPosition = localToWorldMatrices[selection.single].inverse.MultiplyPoint3x4(lookAtPosition); spriteBoneData.localRotation = MeshModuleUtility.NormalizeQuaternion(spriteBoneData.localRotation * Quaternion.FromToRotation(Vector2.right, localLookAtPosition)); m_PreviewChanged = true; UpdateBones(); } }
private void UpdateBindPose() { MeshModuleUtility.UpdateLocalToWorldMatrices(spriteMeshData.bones, spriteMeshData.CalculateRootMatrix(), ref m_BindPose); for (int i = 0; i < m_BindPose.Length; ++i) { m_BindPose[i] = m_BindPose[i].inverse; } }
private void UpdateBones() { MeshModuleUtility.UpdateLocalToWorldMatrices(spriteMeshData.bones, spriteMeshData.CalculateRootMatrix(), ref m_LocalToWorldMatrices); spriteMeshData.UpdateSpriteBoneDataWorldPosition(m_LocalToWorldMatrices); if (onSkinPreviewChanged != null) { onSkinPreviewChanged.Invoke(); } }
public override void DoMainGUI() { HandleSpriteRectSelectionChange(); DrawGizmos(); SetupElements(); if (m_CachedSpriteMeshData != null) { m_MeshPreview.Prepare(); if (m_SpriteMeshCache.mode == Mode.Weights) { MeshModuleUtility.DrawMesh(m_MeshPreview.mesh, m_MeshPreview.meterial); } m_MeshPreview.DrawTriangles(); if (!m_BindPoseController.inSkinningPreview) { EditorGUI.BeginChangeCheck(); m_SpriteMeshController.OnGUI(); if (EditorGUI.EndChangeCheck()) { m_MeshPreview.SetVerticesDirty(); m_MeshPreview.SetIndicesDirty(); spriteEditor.SetDataModified(); } } if (m_SpriteMeshCache.mode == Mode.Weights) { m_BindPoseController.DoBoneGUI(); } m_RectSelectionTool.OnGUI(); m_UnselectTool.OnGUI(); if (m_SpriteMeshCache.mode == Mode.Weights && m_SpriteMeshCache.selectedWeightTool == WeightTool.Brush && m_BindPoseView.hoveredBone == -1) { EditorGUI.BeginChangeCheck(); m_BrushWeightTool.OnGUI(); if (EditorGUI.EndChangeCheck()) { m_MeshPreview.SetWeightsDirty(); spriteEditor.SetDataModified(); } } } }
private void MoveSelectedVertices(Vector2 delta) { delta = MeshModuleUtility.MoveRectInsideFrame(CalculateRectFromSelection(), spriteMeshData.frame, delta); undoObject.RegisterCompleteObjectUndo("Move Vertices"); foreach (int index in selection) { Vector2 v = spriteMeshData.vertices[index].position; spriteMeshData.SetVertexPosition(index, ClampToFrame(v + delta)); } spriteMeshData.Triangulate(triangulator); }
private void WeightChannelDrawer( ref bool isChannelEnabled, ref BoneWeightData boneWeightData, bool isChannelEnabledMixed = false, bool isBoneIndexMixed = false, bool isWeightMixed = false) { EditorGUILayout.BeginHorizontal(); EditorGUIUtility.fieldWidth = 1f; EditorGUIUtility.labelWidth = 1f; EditorGUI.showMixedValue = isChannelEnabledMixed; isChannelEnabled = EditorGUILayout.Toggle(GUIContent.none, isChannelEnabled); EditorGUIUtility.fieldWidth = 30f; EditorGUIUtility.labelWidth = 30f; using (new EditorGUI.DisabledScope(!isChannelEnabled && !isChannelEnabledMixed)) { int tempBoneIndex = GUI.enabled ? boneWeightData.boneIndex : -1; EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = GUI.enabled && isBoneIndexMixed; tempBoneIndex = EditorGUILayout.Popup(tempBoneIndex, MeshModuleUtility.GetBoneNameList(spriteMeshData)); if (EditorGUI.EndChangeCheck()) { boneWeightData.boneIndex = tempBoneIndex; } EditorGUIUtility.fieldWidth = 45f; EditorGUI.showMixedValue = isWeightMixed; boneWeightData.weight = EditorGUILayout.Slider(GUIContent.none, boneWeightData.weight, 0f, 1f); } EditorGUILayout.EndHorizontal(); EditorGUI.showMixedValue = false; EditorGUIUtility.labelWidth = -1; EditorGUIUtility.fieldWidth = -1; }
private Vector2 ClampToFrame(Vector2 position) { return(MeshModuleUtility.ClampPositionToRect(position, spriteMeshData.frame)); }
private void CreateVertex(Vector2 position, int edgeIndex) { position = MeshModuleUtility.ClampPositionToRect(position, spriteMeshData.frame); undoObject.RegisterCompleteObjectUndo("Create Vertex"); BoneWeight boneWeight = new BoneWeight(); Vector3Int indices; Vector3 barycentricCoords; if (spriteMeshData.FindTriangle(position, out indices, out barycentricCoords)) { EditableBoneWeight bw1 = spriteMeshData.vertices[indices.x].editableBoneWeight; EditableBoneWeight bw2 = spriteMeshData.vertices[indices.y].editableBoneWeight; EditableBoneWeight bw3 = spriteMeshData.vertices[indices.z].editableBoneWeight; EditableBoneWeight result = new EditableBoneWeight(); foreach (BoneWeightChannel channel in bw1) { if (!channel.enabled) { continue; } BoneWeightData data = channel.boneWeightData; data.weight *= barycentricCoords.x; if (data.weight > 0f) { result.AddChannel(data, true); } } foreach (BoneWeightChannel channel in bw2) { if (!channel.enabled) { continue; } BoneWeightData data = channel.boneWeightData; data.weight *= barycentricCoords.y; if (data.weight > 0f) { result.AddChannel(data, true); } } foreach (BoneWeightChannel channel in bw3) { if (!channel.enabled) { continue; } BoneWeightData data = channel.boneWeightData; data.weight *= barycentricCoords.z; if (data.weight > 0f) { result.AddChannel(data, true); } } result.UnifyChannelsWithSameBoneIndex(); result.FilterChannels(0f); result.ClampChannels(4, true); boneWeight = result.ToBoneWeight(true); } else if (edgeIndex != -1) { Edge edge = spriteMeshData.edges[edgeIndex]; Vector2 pos1 = spriteMeshData.vertices[edge.index1].position; Vector2 pos2 = spriteMeshData.vertices[edge.index2].position; Vector2 dir1 = (position - pos1); Vector2 dir2 = (pos2 - pos1); float t = Vector2.Dot(dir1, dir2.normalized) / dir2.magnitude; t = Mathf.Clamp01(t); BoneWeight bw1 = spriteMeshData.vertices[edge.index1].editableBoneWeight.ToBoneWeight(true); BoneWeight bw2 = spriteMeshData.vertices[edge.index2].editableBoneWeight.ToBoneWeight(true); boneWeight = EditableBoneWeightUtility.Lerp(bw1, bw2, t); } spriteMeshData.CreateVertex(position, edgeIndex); spriteMeshData.vertices[spriteMeshData.vertices.Count - 1].editableBoneWeight.SetFromBoneWeight(boneWeight); spriteMeshData.Triangulate(triangulator); }
public Vector3 GUIToWorld(Vector2 guiPosition, Vector3 planeNormal, Vector3 planePosition) { return(MeshModuleUtility.GUIToWorld(guiPosition, planeNormal, planePosition)); }
public Vector2 GUIToWorld(Vector2 guiPosition) { return(MeshModuleUtility.GUIToWorld(guiPosition)); }
public void OnInspectorGUI() { Debug.Assert(weightEditor != null); weightEditor.mode = (WeightEditorMode)EditorGUILayout.EnumPopup(Contents.mode, weightEditor.mode); if (weightEditor.mode != WeightEditorMode.Smooth) { weightEditor.boneIndex = EditorGUILayout.Popup(Contents.selectedBone, weightEditor.boneIndex, MeshModuleUtility.GetBoneNameList(weightEditor.spriteMeshData)); } weightEditor.autoNormalize = EditorGUILayout.Toggle(Contents.autoNormalize, weightEditor.autoNormalize); radius = EditorGUILayout.FloatField(Contents.size, radius); radius = Mathf.Max(1f, radius); EditorGUIUtility.labelWidth = 70f; hardness = EditorGUILayout.Slider(Contents.hardness, hardness, 1f, 100f); step = EditorGUILayout.Slider(Contents.step, step, 1f, 100f); EditorGUIUtility.labelWidth = 0f; if (weightEditor.boneIndex == -1 && weightEditor.mode != WeightEditorMode.Smooth) { EditorGUILayout.HelpBox(Contents.helpMessage.text, MessageType.Info, true); } }
public void OnGUI() { m_ControlID = GUIUtility.GetControlID("BrushWeightEditor".GetHashCode(), FocusType.Passive); EventType eventType = Event.current.GetTypeForControl(controlID); weightEditor.selection = m_Selection; m_CircleVertexSelector.vertices = weightEditor.spriteMeshData.vertices; Vector2 position = MeshModuleUtility.GUIToWorld(Event.current.mousePosition); if (eventType == EventType.Layout && !Event.current.alt) { HandleUtility.AddControl(controlID, 0f); } if (GUIUtility.hotControl == 0 && HandleUtility.nearestControl == controlID && eventType == EventType.MouseDown && Event.current.button == 0 && !Event.current.alt) { GUIUtility.hotControl = controlID; GUI.changed = true; m_DeltaAcc = 0f; m_LastPosition = position; weightEditor.OnEditStart(true); OnBrush(hardness / 100f, position); Event.current.Use(); } if (GUIUtility.hotControl == controlID && eventType == EventType.MouseUp && Event.current.button == 0) { GUIUtility.hotControl = 0; weightEditor.OnEditEnd(); GUI.changed = true; Event.current.Use(); } if (HandleUtility.nearestControl == controlID && Event.current.shift && eventType == EventType.ScrollWheel) { float radiusDelta = HandleUtility.niceMouseDeltaZoom * k_WheelRadiusSpeed; radius = Mathf.Max(1f, radius + radiusDelta); UpdateSelection(position); Event.current.Use(); } if (GUIUtility.hotControl == 0 && HandleUtility.nearestControl == controlID && eventType == EventType.MouseMove) { UpdateSelection(position); Event.current.Use(); } if (GUIUtility.hotControl == controlID && eventType == EventType.MouseDrag) { step = Mathf.Max(step, 1f); Vector2 delta = position - m_LastPosition; Vector2 direction = delta.normalized; Vector2 startPosition = m_LastPosition - direction * m_DeltaAcc; float magnitude = delta.magnitude; m_DeltaAcc += magnitude; if (m_DeltaAcc >= step) { Vector2 stepVector = direction * step; Vector2 currentPosition = startPosition; while (m_DeltaAcc >= step) { currentPosition += stepVector; OnBrush(hardness / 100f, currentPosition); m_DeltaAcc -= step; } } m_LastPosition = position; GUI.changed = true; Event.current.Use(); } if ((GUIUtility.hotControl == controlID || (GUIUtility.hotControl == 0 && HandleUtility.nearestControl == controlID)) && eventType == EventType.Repaint) { Color oldColor = Handles.color; Handles.color = Color.white; if (isSecondaryAction) { Handles.color = Color.red; } if (GUIUtility.hotControl == controlID) { Handles.color = Color.yellow; } Handles.DrawWireDisc(position, Vector3.forward, radius); Handles.color = oldColor; } }
public override void OnModuleActivate() { InitStyles(); Undo.undoRedoPerformed += UndoRedoPerformed; spriteEditor.enableMouseMoveEvent = true; IGUIWrapper guiWrapper = new GUIWrapper(); m_SpriteMeshCache = ScriptableObject.CreateInstance <SpriteMeshCache>(); m_Triangulator = new Triangulator(); m_WeightGenerator = new BoundedBiharmonicWeightsGenerator(); m_OutlineGenerator = new OutlineGenerator(); m_UndoObject = new UndoObject(m_SpriteMeshCache); m_SpriteMeshController = new SpriteMeshController(); m_SpriteMeshView = new SpriteMeshView(guiWrapper); m_BindPoseController = new BindPoseController(); m_BindPoseView = new BindPoseView(guiWrapper); m_RectSelectionTool = new RectSelectionTool(m_SpriteMeshCache); m_UnselectTool = new UnselectTool(m_SpriteMeshCache); m_WeightEditor = new WeightEditor(); m_BrushWeightTool = new BrushWeightTool(); m_SliderWeightTool = new SliderWeightTool(); m_WeightInspector = new WeightInspector(m_SpriteMeshCache); m_BoneInspector = new BoneInspector(m_SpriteMeshCache); m_MeshPreview = new MeshPreview(); var dataProvider = spriteEditor.GetDataProvider <ISpriteEditorDataProvider>(); var boneProvider = spriteEditor.GetDataProvider <ISpriteBoneDataProvider>(); var spriteMeshProvider = spriteEditor.GetDataProvider <ISpriteMeshDataProvider>(); var spriteRects = dataProvider.GetSpriteRects(); var textureProvider = spriteEditor.GetDataProvider <ITextureDataProvider>(); m_MeshPreview.textureDataProvider = textureProvider; for (var i = 0; i < spriteRects.Length; i++) { var spriteRect = spriteRects[i]; var spriteMeshData = new SpriteMeshData(); spriteMeshData.spriteID = spriteRect.spriteID; spriteMeshData.frame = spriteRect.rect; spriteMeshData.pivot = spriteRect.rect.position + Vector2.Scale(spriteRect.rect.size, spriteRect.pivot); spriteMeshData.bones = MeshModuleUtility.CreateSpriteBoneData(boneProvider.GetBones(spriteRect.spriteID), spriteMeshData.CalculateRootMatrix()); var metaVertices = spriteMeshProvider.GetVertices(spriteRect.spriteID); foreach (var mv in metaVertices) { var v = new Vertex2D(mv.position + spriteRect.rect.position, mv.boneWeight); spriteMeshData.vertices.Add(v); } spriteMeshData.indices = new List <int>(spriteMeshProvider.GetIndices(spriteRect.spriteID)); Vector2Int[] edges = spriteMeshProvider.GetEdges(spriteRect.spriteID); foreach (var e in edges) { spriteMeshData.edges.Add(new Edge(e.x, e.y)); } m_SpriteMeshCache.AddSpriteMeshData(spriteMeshData); } m_WeightEditorWindow = new ModuleWindow(Contents.weightEditor.text, new Rect(0f, 0f, 300f, 195f)); m_WeightEditorWindow.windowGUICallback = WeightEditorInspector; m_InspectorWindow = new ModuleWindow(Contents.inspector.text, new Rect(0f, 0f, 300f, 95f)); m_GenerateGeometryMenuContents.settings = m_GenerateGeometrySettings; m_GenerateGeometryMenuContents.onGenerateGeometry = OnGenerateGeometry; m_BindPoseController.onSkinPreviewChanged += () => { m_MeshPreview.SetSkinningDirty(); }; m_MeshPreview.SetMeshDirty(); m_CachedSpriteMeshData = selectedSpriteMeshData; }