提交Spine插件
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated May 1, 2019. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2019, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS
|
||||
* INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Spine.Unity.Modules {
|
||||
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
|
||||
public class SkeletonPartsRenderer : MonoBehaviour {
|
||||
|
||||
#region Properties
|
||||
MeshGenerator meshGenerator;
|
||||
public MeshGenerator MeshGenerator {
|
||||
get {
|
||||
LazyIntialize();
|
||||
return meshGenerator;
|
||||
}
|
||||
}
|
||||
|
||||
MeshRenderer meshRenderer;
|
||||
public MeshRenderer MeshRenderer {
|
||||
get {
|
||||
LazyIntialize();
|
||||
return meshRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
MeshFilter meshFilter;
|
||||
public MeshFilter MeshFilter {
|
||||
get {
|
||||
LazyIntialize();
|
||||
return meshFilter;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
MeshRendererBuffers buffers;
|
||||
SkeletonRendererInstruction currentInstructions = new SkeletonRendererInstruction();
|
||||
|
||||
|
||||
void LazyIntialize () {
|
||||
if (buffers == null) {
|
||||
buffers = new MeshRendererBuffers();
|
||||
buffers.Initialize();
|
||||
|
||||
if (meshGenerator != null) return;
|
||||
meshGenerator = new MeshGenerator();
|
||||
meshFilter = GetComponent<MeshFilter>();
|
||||
meshRenderer = GetComponent<MeshRenderer>();
|
||||
currentInstructions.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearMesh () {
|
||||
LazyIntialize();
|
||||
meshFilter.sharedMesh = null;
|
||||
}
|
||||
|
||||
public void RenderParts (ExposedList<SubmeshInstruction> instructions, int startSubmesh, int endSubmesh) {
|
||||
LazyIntialize();
|
||||
|
||||
// STEP 1: Create instruction
|
||||
var smartMesh = buffers.GetNextMesh();
|
||||
currentInstructions.SetWithSubset(instructions, startSubmesh, endSubmesh);
|
||||
bool updateTriangles = SkeletonRendererInstruction.GeometryNotEqual(currentInstructions, smartMesh.instructionUsed);
|
||||
|
||||
// STEP 2: Generate mesh buffers.
|
||||
var currentInstructionsSubmeshesItems = currentInstructions.submeshInstructions.Items;
|
||||
meshGenerator.Begin();
|
||||
if (currentInstructions.hasActiveClipping) {
|
||||
for (int i = 0; i < currentInstructions.submeshInstructions.Count; i++)
|
||||
meshGenerator.AddSubmesh(currentInstructionsSubmeshesItems[i], updateTriangles);
|
||||
} else {
|
||||
meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles);
|
||||
}
|
||||
|
||||
buffers.UpdateSharedMaterials(currentInstructions.submeshInstructions);
|
||||
|
||||
// STEP 3: modify mesh.
|
||||
var mesh = smartMesh.mesh;
|
||||
|
||||
if (meshGenerator.VertexCount <= 0) { // Clear an empty mesh
|
||||
updateTriangles = false;
|
||||
mesh.Clear();
|
||||
} else {
|
||||
meshGenerator.FillVertexData(mesh);
|
||||
if (updateTriangles) {
|
||||
meshGenerator.FillTriangles(mesh);
|
||||
meshRenderer.sharedMaterials = buffers.GetUpdatedSharedMaterialsArray();
|
||||
} else if (buffers.MaterialsChangedInLastUpdate()) {
|
||||
meshRenderer.sharedMaterials = buffers.GetUpdatedSharedMaterialsArray();
|
||||
}
|
||||
meshGenerator.FillLateVertexData(mesh);
|
||||
}
|
||||
|
||||
meshFilter.sharedMesh = mesh;
|
||||
smartMesh.instructionUsed.Set(currentInstructions);
|
||||
}
|
||||
|
||||
public void SetPropertyBlock (MaterialPropertyBlock block) {
|
||||
LazyIntialize();
|
||||
meshRenderer.SetPropertyBlock(block);
|
||||
}
|
||||
|
||||
public static SkeletonPartsRenderer NewPartsRendererGameObject (Transform parent, string name, int sortingOrder = 0) {
|
||||
var go = new GameObject(name, typeof(MeshFilter), typeof(MeshRenderer));
|
||||
go.transform.SetParent(parent, false);
|
||||
var returnComponent = go.AddComponent<SkeletonPartsRenderer>();
|
||||
returnComponent.MeshRenderer.sortingOrder = sortingOrder;
|
||||
|
||||
return returnComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c0b968d1e7333b499e347acb644f1c1
|
||||
timeCreated: 1458045480
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,254 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated May 1, 2019. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2019, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS
|
||||
* INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
|
||||
#define NEW_PREFAB_SYSTEM
|
||||
#endif
|
||||
#define SPINE_OPTIONAL_RENDEROVERRIDE
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spine.Unity.Modules {
|
||||
|
||||
#if NEW_PREFAB_SYSTEM
|
||||
[ExecuteAlways]
|
||||
#else
|
||||
[ExecuteInEditMode]
|
||||
#endif
|
||||
[HelpURL("http://esotericsoftware.com/spine-unity-skeletonrenderseparator")]
|
||||
public class SkeletonRenderSeparator : MonoBehaviour {
|
||||
public const int DefaultSortingOrderIncrement = 5;
|
||||
|
||||
#region Inspector
|
||||
[SerializeField]
|
||||
protected SkeletonRenderer skeletonRenderer;
|
||||
public SkeletonRenderer SkeletonRenderer {
|
||||
get { return skeletonRenderer; }
|
||||
set {
|
||||
#if SPINE_OPTIONAL_RENDEROVERRIDE
|
||||
if (skeletonRenderer != null)
|
||||
skeletonRenderer.GenerateMeshOverride -= HandleRender;
|
||||
#endif
|
||||
|
||||
skeletonRenderer = value;
|
||||
if (value == null)
|
||||
this.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
MeshRenderer mainMeshRenderer;
|
||||
public bool copyPropertyBlock = true;
|
||||
[Tooltip("Copies MeshRenderer flags into each parts renderer")]
|
||||
public bool copyMeshRendererFlags = true;
|
||||
public List<Spine.Unity.Modules.SkeletonPartsRenderer> partsRenderers = new List<SkeletonPartsRenderer>();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void Reset () {
|
||||
if (skeletonRenderer == null)
|
||||
skeletonRenderer = GetComponent<SkeletonRenderer>();
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Runtime Instantiation
|
||||
/// <summary>Adds a SkeletonRenderSeparator and child SkeletonPartsRenderer GameObjects to a given SkeletonRenderer.</summary>
|
||||
/// <returns>The to skeleton renderer.</returns>
|
||||
/// <param name="skeletonRenderer">The target SkeletonRenderer or SkeletonAnimation.</param>
|
||||
/// <param name="sortingLayerID">Sorting layer to be used for the parts renderers.</param>
|
||||
/// <param name="extraPartsRenderers">Number of additional SkeletonPartsRenderers on top of the ones determined by counting the number of separator slots.</param>
|
||||
/// <param name="sortingOrderIncrement">The integer to increment the sorting order per SkeletonPartsRenderer to separate them.</param>
|
||||
/// <param name="baseSortingOrder">The sorting order value of the first SkeletonPartsRenderer.</param>
|
||||
/// <param name="addMinimumPartsRenderers">If set to <c>true</c>, a minimum number of SkeletonPartsRenderer GameObjects (determined by separatorSlots.Count + 1) will be added.</param>
|
||||
public static SkeletonRenderSeparator AddToSkeletonRenderer (SkeletonRenderer skeletonRenderer, int sortingLayerID = 0, int extraPartsRenderers = 0, int sortingOrderIncrement = DefaultSortingOrderIncrement, int baseSortingOrder = 0, bool addMinimumPartsRenderers = true) {
|
||||
if (skeletonRenderer == null) {
|
||||
Debug.Log("Tried to add SkeletonRenderSeparator to a null SkeletonRenderer reference.");
|
||||
return null;
|
||||
}
|
||||
|
||||
var srs = skeletonRenderer.gameObject.AddComponent<SkeletonRenderSeparator>();
|
||||
srs.skeletonRenderer = skeletonRenderer;
|
||||
|
||||
skeletonRenderer.Initialize(false);
|
||||
int count = extraPartsRenderers;
|
||||
if (addMinimumPartsRenderers)
|
||||
count = extraPartsRenderers + skeletonRenderer.separatorSlots.Count + 1;
|
||||
|
||||
var skeletonRendererTransform = skeletonRenderer.transform;
|
||||
var componentRenderers = srs.partsRenderers;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
var spr = SkeletonPartsRenderer.NewPartsRendererGameObject(skeletonRendererTransform, i.ToString());
|
||||
var mr = spr.MeshRenderer;
|
||||
mr.sortingLayerID = sortingLayerID;
|
||||
mr.sortingOrder = baseSortingOrder + (i * sortingOrderIncrement);
|
||||
componentRenderers.Add(spr);
|
||||
}
|
||||
|
||||
srs.OnEnable();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Make sure editor updates properly in edit mode.
|
||||
if (!Application.isPlaying) {
|
||||
skeletonRenderer.enabled = false;
|
||||
skeletonRenderer.enabled = true;
|
||||
skeletonRenderer.LateUpdate();
|
||||
}
|
||||
#endif
|
||||
|
||||
return srs;
|
||||
}
|
||||
|
||||
/// <summary>Add a child SkeletonPartsRenderer GameObject to this SkeletonRenderSeparator.</summary>
|
||||
public SkeletonPartsRenderer AddPartsRenderer (int sortingOrderIncrement = DefaultSortingOrderIncrement, string name = null) {
|
||||
int sortingLayerID = 0;
|
||||
int sortingOrder = 0;
|
||||
if (partsRenderers.Count > 0) {
|
||||
var previous = partsRenderers[partsRenderers.Count - 1];
|
||||
var previousMeshRenderer = previous.MeshRenderer;
|
||||
sortingLayerID = previousMeshRenderer.sortingLayerID;
|
||||
sortingOrder = previousMeshRenderer.sortingOrder + sortingOrderIncrement;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
name = partsRenderers.Count.ToString();
|
||||
|
||||
var spr = SkeletonPartsRenderer.NewPartsRendererGameObject(skeletonRenderer.transform, name);
|
||||
partsRenderers.Add(spr);
|
||||
|
||||
var mr = spr.MeshRenderer;
|
||||
mr.sortingLayerID = sortingLayerID;
|
||||
mr.sortingOrder = sortingOrder;
|
||||
|
||||
return spr;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void OnEnable () {
|
||||
if (skeletonRenderer == null) return;
|
||||
if (copiedBlock == null) copiedBlock = new MaterialPropertyBlock();
|
||||
mainMeshRenderer = skeletonRenderer.GetComponent<MeshRenderer>();
|
||||
|
||||
#if SPINE_OPTIONAL_RENDEROVERRIDE
|
||||
skeletonRenderer.GenerateMeshOverride -= HandleRender;
|
||||
skeletonRenderer.GenerateMeshOverride += HandleRender;
|
||||
#endif
|
||||
|
||||
if (copyMeshRendererFlags) {
|
||||
var lightProbeUsage = mainMeshRenderer.lightProbeUsage;
|
||||
bool receiveShadows = mainMeshRenderer.receiveShadows;
|
||||
var reflectionProbeUsage = mainMeshRenderer.reflectionProbeUsage;
|
||||
var shadowCastingMode = mainMeshRenderer.shadowCastingMode;
|
||||
var motionVectorGenerationMode = mainMeshRenderer.motionVectorGenerationMode;
|
||||
var probeAnchor = mainMeshRenderer.probeAnchor;
|
||||
|
||||
for (int i = 0; i < partsRenderers.Count; i++) {
|
||||
var currentRenderer = partsRenderers[i];
|
||||
if (currentRenderer == null) continue; // skip null items.
|
||||
|
||||
var mr = currentRenderer.MeshRenderer;
|
||||
mr.lightProbeUsage = lightProbeUsage;
|
||||
mr.receiveShadows = receiveShadows;
|
||||
mr.reflectionProbeUsage = reflectionProbeUsage;
|
||||
mr.shadowCastingMode = shadowCastingMode;
|
||||
mr.motionVectorGenerationMode = motionVectorGenerationMode;
|
||||
mr.probeAnchor = probeAnchor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDisable () {
|
||||
if (skeletonRenderer == null) return;
|
||||
#if SPINE_OPTIONAL_RENDEROVERRIDE
|
||||
skeletonRenderer.GenerateMeshOverride -= HandleRender;
|
||||
#endif
|
||||
|
||||
skeletonRenderer.LateUpdate();
|
||||
|
||||
foreach (var s in partsRenderers)
|
||||
s.ClearMesh();
|
||||
}
|
||||
|
||||
MaterialPropertyBlock copiedBlock;
|
||||
|
||||
void HandleRender (SkeletonRendererInstruction instruction) {
|
||||
int rendererCount = partsRenderers.Count;
|
||||
if (rendererCount <= 0) return;
|
||||
|
||||
if (copyPropertyBlock)
|
||||
mainMeshRenderer.GetPropertyBlock(copiedBlock);
|
||||
|
||||
var settings = new MeshGenerator.Settings {
|
||||
addNormals = skeletonRenderer.addNormals,
|
||||
calculateTangents = skeletonRenderer.calculateTangents,
|
||||
immutableTriangles = false, // parts cannot do immutable triangles.
|
||||
pmaVertexColors = skeletonRenderer.pmaVertexColors,
|
||||
tintBlack = skeletonRenderer.tintBlack,
|
||||
useClipping = true,
|
||||
zSpacing = skeletonRenderer.zSpacing
|
||||
};
|
||||
|
||||
var submeshInstructions = instruction.submeshInstructions;
|
||||
var submeshInstructionsItems = submeshInstructions.Items;
|
||||
int lastSubmeshInstruction = submeshInstructions.Count - 1;
|
||||
|
||||
int rendererIndex = 0;
|
||||
var currentRenderer = partsRenderers[rendererIndex];
|
||||
for (int si = 0, start = 0; si <= lastSubmeshInstruction; si++) {
|
||||
if (submeshInstructionsItems[si].forceSeparate || si == lastSubmeshInstruction) {
|
||||
// Apply properties
|
||||
var meshGenerator = currentRenderer.MeshGenerator;
|
||||
meshGenerator.settings = settings;
|
||||
|
||||
if (copyPropertyBlock)
|
||||
currentRenderer.SetPropertyBlock(copiedBlock);
|
||||
|
||||
// Render
|
||||
currentRenderer.RenderParts(instruction.submeshInstructions, start, si + 1);
|
||||
|
||||
start = si + 1;
|
||||
rendererIndex++;
|
||||
if (rendererIndex < rendererCount) {
|
||||
currentRenderer = partsRenderers[rendererIndex];
|
||||
} else {
|
||||
// Not enough renderers. Skip the rest of the instructions.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear extra renderers if they exist.
|
||||
for (; rendererIndex < rendererCount; rendererIndex++) {
|
||||
partsRenderers[rendererIndex].ClearMesh();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c70a5b35f6ff2541aed8e8346b7e4d5
|
||||
timeCreated: 1457405791
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,6 @@
|
||||
SkeletonRenderSeparator
|
||||
=======================
|
||||
|
||||
Dependencies:
|
||||
- SkeletonPartsRenderer uses the `ArraysMeshGenerator` class in `Spine.Unity.MeshGeneration`
|
||||
- It requires `SPINE_OPTIONAL_RENDEROVERRIDE` to be #defined in `SkeletonRenderer.cs`.
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0e413eeb00eabc46bde6dbd7aaaa76c
|
||||
timeCreated: 1469110129
|
||||
licenseType: Free
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user