mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
Optimization to not render meshes. Better inspectors.
This commit is contained in:
parent
b316b8d3e1
commit
6983ec6fd3
@ -33,27 +33,24 @@ using UnityEditor;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
[CustomEditor(typeof(SkeletonAnimation))]
|
[CustomEditor(typeof(SkeletonAnimation))]
|
||||||
public class SkeletonAnimationInspector : Editor {
|
public class SkeletonAnimationInspector : SkeletonRendererInspector {
|
||||||
private SerializedProperty skeletonDataAsset, initialSkinName, timeScale, normals, tangents;
|
protected SerializedProperty animationName, loop, timeScale;
|
||||||
private SerializedProperty animationName, loop;
|
|
||||||
|
|
||||||
void OnEnable () {
|
protected override void OnEnable () {
|
||||||
skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset");
|
base.OnEnable();
|
||||||
animationName = serializedObject.FindProperty("_animationName");
|
animationName = serializedObject.FindProperty("_animationName");
|
||||||
loop = serializedObject.FindProperty("loop");
|
loop = serializedObject.FindProperty("loop");
|
||||||
initialSkinName = serializedObject.FindProperty("initialSkinName");
|
|
||||||
timeScale = serializedObject.FindProperty("timeScale");
|
timeScale = serializedObject.FindProperty("timeScale");
|
||||||
normals = serializedObject.FindProperty("calculateNormals");
|
|
||||||
tangents = serializedObject.FindProperty("calculateTangents");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override public void OnInspectorGUI () {
|
protected override void gui () {
|
||||||
serializedObject.Update();
|
base.gui();
|
||||||
|
|
||||||
SkeletonAnimation component = (SkeletonAnimation)target;
|
SkeletonAnimation component = (SkeletonAnimation)target;
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(skeletonDataAsset);
|
EditorGUILayout.PropertyField(skeletonDataAsset);
|
||||||
|
|
||||||
if (component.skeleton != null) {
|
if (component.valid) {
|
||||||
// Initial skin name.
|
// Initial skin name.
|
||||||
String[] skins = new String[component.skeleton.Data.Skins.Count];
|
String[] skins = new String[component.skeleton.Data.Skins.Count];
|
||||||
int skinIndex = 0;
|
int skinIndex = 0;
|
||||||
@ -98,17 +95,5 @@ public class SkeletonAnimationInspector : Editor {
|
|||||||
EditorGUILayout.LabelField("Loop");
|
EditorGUILayout.LabelField("Loop");
|
||||||
loop.boolValue = EditorGUILayout.Toggle(loop.boolValue);
|
loop.boolValue = EditorGUILayout.Toggle(loop.boolValue);
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(timeScale);
|
|
||||||
EditorGUILayout.PropertyField(normals);
|
|
||||||
EditorGUILayout.PropertyField(tangents);
|
|
||||||
|
|
||||||
if (serializedObject.ApplyModifiedProperties() ||
|
|
||||||
(Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed")
|
|
||||||
) {
|
|
||||||
if (!Application.isPlaying) {
|
|
||||||
component.Reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,23 +34,22 @@ using UnityEngine;
|
|||||||
|
|
||||||
[CustomEditor(typeof(SkeletonRenderer))]
|
[CustomEditor(typeof(SkeletonRenderer))]
|
||||||
public class SkeletonRendererInspector : Editor {
|
public class SkeletonRendererInspector : Editor {
|
||||||
private SerializedProperty skeletonDataAsset, initialSkinName, timeScale, normals, tangents;
|
protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes;
|
||||||
|
|
||||||
void OnEnable () {
|
protected virtual void OnEnable () {
|
||||||
skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset");
|
skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset");
|
||||||
initialSkinName = serializedObject.FindProperty("initialSkinName");
|
initialSkinName = serializedObject.FindProperty("initialSkinName");
|
||||||
timeScale = serializedObject.FindProperty("timeScale");
|
|
||||||
normals = serializedObject.FindProperty("calculateNormals");
|
normals = serializedObject.FindProperty("calculateNormals");
|
||||||
tangents = serializedObject.FindProperty("calculateTangents");
|
tangents = serializedObject.FindProperty("calculateTangents");
|
||||||
|
meshes = serializedObject.FindProperty("renderMeshes");
|
||||||
}
|
}
|
||||||
|
|
||||||
override public void OnInspectorGUI () {
|
protected virtual void gui () {
|
||||||
serializedObject.Update();
|
|
||||||
SkeletonRenderer component = (SkeletonRenderer)target;
|
SkeletonRenderer component = (SkeletonRenderer)target;
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(skeletonDataAsset);
|
EditorGUILayout.PropertyField(skeletonDataAsset);
|
||||||
|
|
||||||
if (component.skeleton != null) {
|
if (component.valid) {
|
||||||
// Initial skin name.
|
// Initial skin name.
|
||||||
String[] skins = new String[component.skeleton.Data.Skins.Count];
|
String[] skins = new String[component.skeleton.Data.Skins.Count];
|
||||||
int skinIndex = 0;
|
int skinIndex = 0;
|
||||||
@ -60,26 +59,28 @@ public class SkeletonRendererInspector : Editor {
|
|||||||
if (name == initialSkinName.stringValue)
|
if (name == initialSkinName.stringValue)
|
||||||
skinIndex = i;
|
skinIndex = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
EditorGUILayout.LabelField("Initial Skin");
|
EditorGUILayout.LabelField("Initial Skin");
|
||||||
EditorGUIUtility.LookLikeControls();
|
EditorGUIUtility.LookLikeControls();
|
||||||
skinIndex = EditorGUILayout.Popup(skinIndex, skins);
|
skinIndex = EditorGUILayout.Popup(skinIndex, skins);
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
initialSkinName.stringValue = skins[skinIndex];
|
initialSkinName.stringValue = skins[skinIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(timeScale);
|
EditorGUILayout.PropertyField(meshes);
|
||||||
EditorGUILayout.PropertyField(normals);
|
EditorGUILayout.PropertyField(normals);
|
||||||
EditorGUILayout.PropertyField(tangents);
|
EditorGUILayout.PropertyField(tangents);
|
||||||
|
}
|
||||||
|
|
||||||
|
override public void OnInspectorGUI () {
|
||||||
|
serializedObject.Update();
|
||||||
|
gui();
|
||||||
if (serializedObject.ApplyModifiedProperties() ||
|
if (serializedObject.ApplyModifiedProperties() ||
|
||||||
(Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed")
|
(Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed")
|
||||||
) {
|
) {
|
||||||
if (!Application.isPlaying) {
|
if (!Application.isPlaying) ((SkeletonRenderer)target).Reset();
|
||||||
component.Reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,6 +47,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
public bool calculateNormals;
|
public bool calculateNormals;
|
||||||
public bool calculateTangents;
|
public bool calculateTangents;
|
||||||
public float zSpacing;
|
public float zSpacing;
|
||||||
|
public bool renderMeshes;
|
||||||
|
|
||||||
private MeshFilter meshFilter;
|
private MeshFilter meshFilter;
|
||||||
private Mesh mesh, mesh1, mesh2;
|
private Mesh mesh, mesh1, mesh2;
|
||||||
@ -108,9 +109,9 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void OnWillRenderObject () {
|
public virtual void LateUpdate () {
|
||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
|
|
||||||
// Count vertices and submesh triangles.
|
// Count vertices and submesh triangles.
|
||||||
int vertexCount = 0;
|
int vertexCount = 0;
|
||||||
int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0;
|
int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0;
|
||||||
@ -118,6 +119,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
submeshMaterials.Clear();
|
submeshMaterials.Clear();
|
||||||
List<Slot> drawOrder = skeleton.DrawOrder;
|
List<Slot> drawOrder = skeleton.DrawOrder;
|
||||||
int drawOrderCount = drawOrder.Count;
|
int drawOrderCount = drawOrder.Count;
|
||||||
|
bool renderMeshes = this.renderMeshes;
|
||||||
for (int i = 0; i < drawOrderCount; i++) {
|
for (int i = 0; i < drawOrderCount; i++) {
|
||||||
Attachment attachment = drawOrder[i].attachment;
|
Attachment attachment = drawOrder[i].attachment;
|
||||||
|
|
||||||
@ -128,23 +130,26 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
rendererObject = ((RegionAttachment)attachment).RendererObject;
|
rendererObject = ((RegionAttachment)attachment).RendererObject;
|
||||||
attachmentVertexCount = 4;
|
attachmentVertexCount = 4;
|
||||||
attachmentTriangleCount = 6;
|
attachmentTriangleCount = 6;
|
||||||
} else if (attachment is MeshAttachment) {
|
} else {
|
||||||
MeshAttachment meshAttachment = (MeshAttachment)attachment;
|
if (!renderMeshes) continue;
|
||||||
rendererObject = meshAttachment.RendererObject;
|
if (attachment is MeshAttachment) {
|
||||||
attachmentVertexCount = meshAttachment.vertices.Length / 2;
|
MeshAttachment meshAttachment = (MeshAttachment)attachment;
|
||||||
attachmentTriangleCount = meshAttachment.triangles.Length;
|
rendererObject = meshAttachment.RendererObject;
|
||||||
} else if (attachment is SkinnedMeshAttachment) {
|
attachmentVertexCount = meshAttachment.vertices.Length >> 1;
|
||||||
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
|
attachmentTriangleCount = meshAttachment.triangles.Length;
|
||||||
rendererObject = meshAttachment.RendererObject;
|
} else if (attachment is SkinnedMeshAttachment) {
|
||||||
attachmentVertexCount = meshAttachment.uvs.Length / 2;
|
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
|
||||||
attachmentTriangleCount = meshAttachment.triangles.Length;
|
rendererObject = meshAttachment.RendererObject;
|
||||||
} else
|
attachmentVertexCount = meshAttachment.uvs.Length >> 1;
|
||||||
continue;
|
attachmentTriangleCount = meshAttachment.triangles.Length;
|
||||||
|
} else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Populate submesh when material changes.
|
// Populate submesh when material changes.
|
||||||
Material material = (Material)rendererObject;
|
Material material = (Material)rendererObject;
|
||||||
if (lastMaterial != material && lastMaterial != null) {
|
if (lastMaterial != material && lastMaterial != null) {
|
||||||
addSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false);
|
AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false);
|
||||||
submeshTriangleCount = 0;
|
submeshTriangleCount = 0;
|
||||||
submeshFirstVertex = vertexCount;
|
submeshFirstVertex = vertexCount;
|
||||||
submeshStartSlotIndex = i;
|
submeshStartSlotIndex = i;
|
||||||
@ -154,7 +159,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
submeshTriangleCount += attachmentTriangleCount;
|
submeshTriangleCount += attachmentTriangleCount;
|
||||||
vertexCount += attachmentVertexCount;
|
vertexCount += attachmentVertexCount;
|
||||||
}
|
}
|
||||||
addSubmesh(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true);
|
AddSubmesh(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true);
|
||||||
|
|
||||||
// Set materials.
|
// Set materials.
|
||||||
if (submeshMaterials.Count == sharedMaterials.Length)
|
if (submeshMaterials.Count == sharedMaterials.Length)
|
||||||
@ -219,43 +224,46 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
uvs[vertexIndex + 3] = new Vector2(regionUVs[RegionAttachment.X3], regionUVs[RegionAttachment.Y3]);
|
uvs[vertexIndex + 3] = new Vector2(regionUVs[RegionAttachment.X3], regionUVs[RegionAttachment.Y3]);
|
||||||
|
|
||||||
vertexIndex += 4;
|
vertexIndex += 4;
|
||||||
} else if (attachment is MeshAttachment) {
|
} else {
|
||||||
MeshAttachment meshAttachment = (MeshAttachment)attachment;
|
if (!renderMeshes) continue;
|
||||||
int meshVertexCount = meshAttachment.vertices.Length;
|
if (attachment is MeshAttachment) {
|
||||||
if (tempVertices.Length < meshVertexCount) tempVertices = new float[meshVertexCount];
|
MeshAttachment meshAttachment = (MeshAttachment)attachment;
|
||||||
meshAttachment.ComputeWorldVertices(x, y, slot, tempVertices);
|
int meshVertexCount = meshAttachment.vertices.Length;
|
||||||
|
if (tempVertices.Length < meshVertexCount) tempVertices = new float[meshVertexCount];
|
||||||
color.a = (byte)(a * slot.a * meshAttachment.a);
|
meshAttachment.ComputeWorldVertices(x, y, slot, tempVertices);
|
||||||
color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
|
|
||||||
color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
|
color.a = (byte)(a * slot.a * meshAttachment.a);
|
||||||
color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
|
color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
|
||||||
if (slot.data.additiveBlending) color.a = 0;
|
color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
|
||||||
|
color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
|
||||||
float[] meshUVs = meshAttachment.uvs;
|
if (slot.data.additiveBlending) color.a = 0;
|
||||||
float z = i * zSpacing;
|
|
||||||
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
|
float[] meshUVs = meshAttachment.uvs;
|
||||||
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z);
|
float z = i * zSpacing;
|
||||||
colors[vertexIndex] = color;
|
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
|
||||||
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]);
|
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z);
|
||||||
}
|
colors[vertexIndex] = color;
|
||||||
} else if (attachment is SkinnedMeshAttachment) {
|
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]);
|
||||||
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
|
}
|
||||||
int meshVertexCount = meshAttachment.uvs.Length;
|
} else if (attachment is SkinnedMeshAttachment) {
|
||||||
if (tempVertices.Length < meshVertexCount) tempVertices = new float[meshVertexCount];
|
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
|
||||||
meshAttachment.ComputeWorldVertices(x, y, slot, tempVertices);
|
int meshVertexCount = meshAttachment.uvs.Length;
|
||||||
|
if (tempVertices.Length < meshVertexCount) tempVertices = new float[meshVertexCount];
|
||||||
color.a = (byte)(a * slot.a * meshAttachment.a);
|
meshAttachment.ComputeWorldVertices(x, y, slot, tempVertices);
|
||||||
color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
|
|
||||||
color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
|
color.a = (byte)(a * slot.a * meshAttachment.a);
|
||||||
color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
|
color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
|
||||||
if (slot.data.additiveBlending) color.a = 0;
|
color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
|
||||||
|
color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
|
||||||
float[] meshUVs = meshAttachment.uvs;
|
if (slot.data.additiveBlending) color.a = 0;
|
||||||
float z = i * zSpacing;
|
|
||||||
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
|
float[] meshUVs = meshAttachment.uvs;
|
||||||
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z);
|
float z = i * zSpacing;
|
||||||
colors[vertexIndex] = color;
|
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
|
||||||
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]);
|
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z);
|
||||||
|
colors[vertexIndex] = color;
|
||||||
|
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -297,7 +305,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Stores vertices and triangles for a single material. */
|
/** Stores vertices and triangles for a single material. */
|
||||||
private void addSubmesh (Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh) {
|
private void AddSubmesh (Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh) {
|
||||||
int submeshIndex = submeshMaterials.Count;
|
int submeshIndex = submeshMaterials.Count;
|
||||||
submeshMaterials.Add(material);
|
submeshMaterials.Add(material);
|
||||||
|
|
||||||
@ -317,6 +325,24 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
submesh.triangleCount = 0;
|
submesh.triangleCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!renderMeshes) {
|
||||||
|
// Use stored triangles if possible.
|
||||||
|
if (submesh.firstVertex != firstVertex || submesh.triangleCount < triangleCount) {
|
||||||
|
submesh.triangleCount = triangleCount;
|
||||||
|
submesh.firstVertex = firstVertex;
|
||||||
|
for (int i = 0; i < triangleCount; i += 6, firstVertex += 4) {
|
||||||
|
triangles[i] = firstVertex;
|
||||||
|
triangles[i + 1] = firstVertex + 2;
|
||||||
|
triangles[i + 2] = firstVertex + 1;
|
||||||
|
triangles[i + 3] = firstVertex + 2;
|
||||||
|
triangles[i + 4] = firstVertex + 3;
|
||||||
|
triangles[i + 5] = firstVertex + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store triangles.
|
||||||
List<Slot> drawOrder = skeleton.DrawOrder;
|
List<Slot> drawOrder = skeleton.DrawOrder;
|
||||||
for (int i = startSlot, triangleIndex = 0; i < endSlot; i++) {
|
for (int i = startSlot, triangleIndex = 0; i < endSlot; i++) {
|
||||||
Attachment attachment = drawOrder[i].attachment;
|
Attachment attachment = drawOrder[i].attachment;
|
||||||
@ -327,11 +353,11 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
attachmentTriangles = quadTriangles;
|
attachmentTriangles = quadTriangles;
|
||||||
} else if (attachment is MeshAttachment) {
|
} else if (attachment is MeshAttachment) {
|
||||||
MeshAttachment meshAttachment = (MeshAttachment)attachment;
|
MeshAttachment meshAttachment = (MeshAttachment)attachment;
|
||||||
attachmentVertexCount = meshAttachment.vertices.Length / 2;
|
attachmentVertexCount = meshAttachment.vertices.Length >> 1;
|
||||||
attachmentTriangles = meshAttachment.triangles;
|
attachmentTriangles = meshAttachment.triangles;
|
||||||
} else if (attachment is SkinnedMeshAttachment) {
|
} else if (attachment is SkinnedMeshAttachment) {
|
||||||
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
|
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
|
||||||
attachmentVertexCount = meshAttachment.uvs.Length / 2;
|
attachmentVertexCount = meshAttachment.uvs.Length >> 1;
|
||||||
attachmentTriangles = meshAttachment.triangles;
|
attachmentTriangles = meshAttachment.triangles;
|
||||||
} else
|
} else
|
||||||
continue;
|
continue;
|
||||||
@ -367,4 +393,5 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
class Submesh {
|
class Submesh {
|
||||||
public int[] triangles = new int[0];
|
public int[] triangles = new int[0];
|
||||||
public int triangleCount;
|
public int triangleCount;
|
||||||
|
public int firstVertex = -1;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@ -33,27 +33,24 @@ using UnityEditor;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
[CustomEditor(typeof(SkeletonAnimation))]
|
[CustomEditor(typeof(SkeletonAnimation))]
|
||||||
public class SkeletonAnimationInspector : Editor {
|
public class SkeletonAnimationInspector : SkeletonRendererInspector {
|
||||||
private SerializedProperty skeletonDataAsset, initialSkinName, timeScale, normals, tangents;
|
protected SerializedProperty animationName, loop, timeScale;
|
||||||
private SerializedProperty animationName, loop;
|
|
||||||
|
|
||||||
void OnEnable () {
|
protected override void OnEnable () {
|
||||||
skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset");
|
base.OnEnable();
|
||||||
animationName = serializedObject.FindProperty("_animationName");
|
animationName = serializedObject.FindProperty("_animationName");
|
||||||
loop = serializedObject.FindProperty("loop");
|
loop = serializedObject.FindProperty("loop");
|
||||||
initialSkinName = serializedObject.FindProperty("initialSkinName");
|
|
||||||
timeScale = serializedObject.FindProperty("timeScale");
|
timeScale = serializedObject.FindProperty("timeScale");
|
||||||
normals = serializedObject.FindProperty("calculateNormals");
|
|
||||||
tangents = serializedObject.FindProperty("calculateTangents");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override public void OnInspectorGUI () {
|
protected override void gui () {
|
||||||
serializedObject.Update();
|
base.gui();
|
||||||
|
|
||||||
SkeletonAnimation component = (SkeletonAnimation)target;
|
SkeletonAnimation component = (SkeletonAnimation)target;
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(skeletonDataAsset);
|
EditorGUILayout.PropertyField(skeletonDataAsset);
|
||||||
|
|
||||||
if (component.skeleton != null) {
|
if (component.valid) {
|
||||||
// Initial skin name.
|
// Initial skin name.
|
||||||
String[] skins = new String[component.skeleton.Data.Skins.Count];
|
String[] skins = new String[component.skeleton.Data.Skins.Count];
|
||||||
int skinIndex = 0;
|
int skinIndex = 0;
|
||||||
@ -98,17 +95,5 @@ public class SkeletonAnimationInspector : Editor {
|
|||||||
EditorGUILayout.LabelField("Loop");
|
EditorGUILayout.LabelField("Loop");
|
||||||
loop.boolValue = EditorGUILayout.Toggle(loop.boolValue);
|
loop.boolValue = EditorGUILayout.Toggle(loop.boolValue);
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(timeScale);
|
|
||||||
EditorGUILayout.PropertyField(normals);
|
|
||||||
EditorGUILayout.PropertyField(tangents);
|
|
||||||
|
|
||||||
if (serializedObject.ApplyModifiedProperties() ||
|
|
||||||
(Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed")
|
|
||||||
) {
|
|
||||||
if (!Application.isPlaying) {
|
|
||||||
component.Reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,23 +34,22 @@ using UnityEngine;
|
|||||||
|
|
||||||
[CustomEditor(typeof(SkeletonRenderer))]
|
[CustomEditor(typeof(SkeletonRenderer))]
|
||||||
public class SkeletonRendererInspector : Editor {
|
public class SkeletonRendererInspector : Editor {
|
||||||
private SerializedProperty skeletonDataAsset, initialSkinName, timeScale, normals, tangents;
|
protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes;
|
||||||
|
|
||||||
void OnEnable () {
|
protected virtual void OnEnable () {
|
||||||
skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset");
|
skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset");
|
||||||
initialSkinName = serializedObject.FindProperty("initialSkinName");
|
initialSkinName = serializedObject.FindProperty("initialSkinName");
|
||||||
timeScale = serializedObject.FindProperty("timeScale");
|
|
||||||
normals = serializedObject.FindProperty("calculateNormals");
|
normals = serializedObject.FindProperty("calculateNormals");
|
||||||
tangents = serializedObject.FindProperty("calculateTangents");
|
tangents = serializedObject.FindProperty("calculateTangents");
|
||||||
|
meshes = serializedObject.FindProperty("renderMeshes");
|
||||||
}
|
}
|
||||||
|
|
||||||
override public void OnInspectorGUI () {
|
protected virtual void gui () {
|
||||||
serializedObject.Update();
|
|
||||||
SkeletonRenderer component = (SkeletonRenderer)target;
|
SkeletonRenderer component = (SkeletonRenderer)target;
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(skeletonDataAsset);
|
EditorGUILayout.PropertyField(skeletonDataAsset);
|
||||||
|
|
||||||
if (component.skeleton != null) {
|
if (component.valid) {
|
||||||
// Initial skin name.
|
// Initial skin name.
|
||||||
String[] skins = new String[component.skeleton.Data.Skins.Count];
|
String[] skins = new String[component.skeleton.Data.Skins.Count];
|
||||||
int skinIndex = 0;
|
int skinIndex = 0;
|
||||||
@ -60,26 +59,28 @@ public class SkeletonRendererInspector : Editor {
|
|||||||
if (name == initialSkinName.stringValue)
|
if (name == initialSkinName.stringValue)
|
||||||
skinIndex = i;
|
skinIndex = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
EditorGUILayout.LabelField("Initial Skin");
|
EditorGUILayout.LabelField("Initial Skin");
|
||||||
EditorGUIUtility.LookLikeControls();
|
EditorGUIUtility.LookLikeControls();
|
||||||
skinIndex = EditorGUILayout.Popup(skinIndex, skins);
|
skinIndex = EditorGUILayout.Popup(skinIndex, skins);
|
||||||
EditorGUILayout.EndHorizontal();
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
initialSkinName.stringValue = skins[skinIndex];
|
initialSkinName.stringValue = skins[skinIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(timeScale);
|
EditorGUILayout.PropertyField(meshes);
|
||||||
EditorGUILayout.PropertyField(normals);
|
EditorGUILayout.PropertyField(normals);
|
||||||
EditorGUILayout.PropertyField(tangents);
|
EditorGUILayout.PropertyField(tangents);
|
||||||
|
}
|
||||||
|
|
||||||
|
override public void OnInspectorGUI () {
|
||||||
|
serializedObject.Update();
|
||||||
|
gui();
|
||||||
if (serializedObject.ApplyModifiedProperties() ||
|
if (serializedObject.ApplyModifiedProperties() ||
|
||||||
(Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed")
|
(Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed")
|
||||||
) {
|
) {
|
||||||
if (!Application.isPlaying) {
|
if (!Application.isPlaying) ((SkeletonRenderer)target).Reset();
|
||||||
component.Reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,12 +41,13 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
public bool valid;
|
public bool valid;
|
||||||
[System.NonSerialized]
|
[System.NonSerialized]
|
||||||
public Skeleton skeleton;
|
public Skeleton skeleton;
|
||||||
|
|
||||||
public SkeletonDataAsset skeletonDataAsset;
|
public SkeletonDataAsset skeletonDataAsset;
|
||||||
public String initialSkinName;
|
public String initialSkinName;
|
||||||
public bool calculateNormals;
|
public bool calculateNormals;
|
||||||
public bool calculateTangents;
|
public bool calculateTangents;
|
||||||
public float zSpacing;
|
public float zSpacing;
|
||||||
|
public bool renderMeshes;
|
||||||
|
|
||||||
private MeshFilter meshFilter;
|
private MeshFilter meshFilter;
|
||||||
private Mesh mesh, mesh1, mesh2;
|
private Mesh mesh, mesh1, mesh2;
|
||||||
@ -76,7 +77,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
submeshMaterials.Clear();
|
submeshMaterials.Clear();
|
||||||
submeshes.Clear();
|
submeshes.Clear();
|
||||||
skeleton = null;
|
skeleton = null;
|
||||||
|
|
||||||
valid = false;
|
valid = false;
|
||||||
if (!skeletonDataAsset) {
|
if (!skeletonDataAsset) {
|
||||||
Debug.LogError("Missing SkeletonData asset.", this);
|
Debug.LogError("Missing SkeletonData asset.", this);
|
||||||
@ -84,7 +85,8 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
}
|
}
|
||||||
SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(false);
|
SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(false);
|
||||||
if (skeletonData == null) return;
|
if (skeletonData == null) return;
|
||||||
|
valid = true;
|
||||||
|
|
||||||
meshFilter = GetComponent<MeshFilter>();
|
meshFilter = GetComponent<MeshFilter>();
|
||||||
mesh1 = newMesh();
|
mesh1 = newMesh();
|
||||||
mesh2 = newMesh();
|
mesh2 = newMesh();
|
||||||
@ -107,7 +109,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void OnWillRenderObject () {
|
public virtual void LateUpdate () {
|
||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
|
|
||||||
// Count vertices and submesh triangles.
|
// Count vertices and submesh triangles.
|
||||||
@ -117,6 +119,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
submeshMaterials.Clear();
|
submeshMaterials.Clear();
|
||||||
List<Slot> drawOrder = skeleton.DrawOrder;
|
List<Slot> drawOrder = skeleton.DrawOrder;
|
||||||
int drawOrderCount = drawOrder.Count;
|
int drawOrderCount = drawOrder.Count;
|
||||||
|
bool renderMeshes = this.renderMeshes;
|
||||||
for (int i = 0; i < drawOrderCount; i++) {
|
for (int i = 0; i < drawOrderCount; i++) {
|
||||||
Attachment attachment = drawOrder[i].attachment;
|
Attachment attachment = drawOrder[i].attachment;
|
||||||
|
|
||||||
@ -127,23 +130,26 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
rendererObject = ((RegionAttachment)attachment).RendererObject;
|
rendererObject = ((RegionAttachment)attachment).RendererObject;
|
||||||
attachmentVertexCount = 4;
|
attachmentVertexCount = 4;
|
||||||
attachmentTriangleCount = 6;
|
attachmentTriangleCount = 6;
|
||||||
} else if (attachment is MeshAttachment) {
|
} else {
|
||||||
MeshAttachment meshAttachment = (MeshAttachment)attachment;
|
if (!renderMeshes) continue;
|
||||||
rendererObject = meshAttachment.RendererObject;
|
if (attachment is MeshAttachment) {
|
||||||
attachmentVertexCount = meshAttachment.vertices.Length / 2;
|
MeshAttachment meshAttachment = (MeshAttachment)attachment;
|
||||||
attachmentTriangleCount = meshAttachment.triangles.Length;
|
rendererObject = meshAttachment.RendererObject;
|
||||||
} else if (attachment is SkinnedMeshAttachment) {
|
attachmentVertexCount = meshAttachment.vertices.Length >> 1;
|
||||||
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
|
attachmentTriangleCount = meshAttachment.triangles.Length;
|
||||||
rendererObject = meshAttachment.RendererObject;
|
} else if (attachment is SkinnedMeshAttachment) {
|
||||||
attachmentVertexCount = meshAttachment.uvs.Length / 2;
|
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
|
||||||
attachmentTriangleCount = meshAttachment.triangles.Length;
|
rendererObject = meshAttachment.RendererObject;
|
||||||
} else
|
attachmentVertexCount = meshAttachment.uvs.Length >> 1;
|
||||||
continue;
|
attachmentTriangleCount = meshAttachment.triangles.Length;
|
||||||
|
} else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Populate submesh when material changes.
|
// Populate submesh when material changes.
|
||||||
Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject;
|
Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject;
|
||||||
if (lastMaterial != material && lastMaterial != null) {
|
if (lastMaterial != material && lastMaterial != null) {
|
||||||
addSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false);
|
AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false);
|
||||||
submeshTriangleCount = 0;
|
submeshTriangleCount = 0;
|
||||||
submeshFirstVertex = vertexCount;
|
submeshFirstVertex = vertexCount;
|
||||||
submeshStartSlotIndex = i;
|
submeshStartSlotIndex = i;
|
||||||
@ -153,7 +159,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
submeshTriangleCount += attachmentTriangleCount;
|
submeshTriangleCount += attachmentTriangleCount;
|
||||||
vertexCount += attachmentVertexCount;
|
vertexCount += attachmentVertexCount;
|
||||||
}
|
}
|
||||||
addSubmesh(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true);
|
AddSubmesh(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true);
|
||||||
|
|
||||||
// Set materials.
|
// Set materials.
|
||||||
if (submeshMaterials.Count == sharedMaterials.Length)
|
if (submeshMaterials.Count == sharedMaterials.Length)
|
||||||
@ -218,43 +224,46 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
uvs[vertexIndex + 3] = new Vector2(regionUVs[RegionAttachment.X3], regionUVs[RegionAttachment.Y3]);
|
uvs[vertexIndex + 3] = new Vector2(regionUVs[RegionAttachment.X3], regionUVs[RegionAttachment.Y3]);
|
||||||
|
|
||||||
vertexIndex += 4;
|
vertexIndex += 4;
|
||||||
} else if (attachment is MeshAttachment) {
|
} else {
|
||||||
MeshAttachment meshAttachment = (MeshAttachment)attachment;
|
if (!renderMeshes) continue;
|
||||||
int meshVertexCount = meshAttachment.vertices.Length;
|
if (attachment is MeshAttachment) {
|
||||||
if (tempVertices.Length < meshVertexCount) tempVertices = new float[meshVertexCount];
|
MeshAttachment meshAttachment = (MeshAttachment)attachment;
|
||||||
meshAttachment.ComputeWorldVertices(x, y, slot, tempVertices);
|
int meshVertexCount = meshAttachment.vertices.Length;
|
||||||
|
if (tempVertices.Length < meshVertexCount) tempVertices = new float[meshVertexCount];
|
||||||
color.a = (byte)(a * slot.a * meshAttachment.a);
|
meshAttachment.ComputeWorldVertices(x, y, slot, tempVertices);
|
||||||
color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
|
|
||||||
color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
|
color.a = (byte)(a * slot.a * meshAttachment.a);
|
||||||
color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
|
color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
|
||||||
if (slot.data.additiveBlending) color.a = 0;
|
color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
|
||||||
|
color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
|
||||||
float[] meshUVs = meshAttachment.uvs;
|
if (slot.data.additiveBlending) color.a = 0;
|
||||||
float z = i * zSpacing;
|
|
||||||
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
|
float[] meshUVs = meshAttachment.uvs;
|
||||||
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z);
|
float z = i * zSpacing;
|
||||||
colors[vertexIndex] = color;
|
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
|
||||||
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]);
|
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z);
|
||||||
}
|
colors[vertexIndex] = color;
|
||||||
} else if (attachment is SkinnedMeshAttachment) {
|
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]);
|
||||||
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
|
}
|
||||||
int meshVertexCount = meshAttachment.uvs.Length;
|
} else if (attachment is SkinnedMeshAttachment) {
|
||||||
if (tempVertices.Length < meshVertexCount) tempVertices = new float[meshVertexCount];
|
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
|
||||||
meshAttachment.ComputeWorldVertices(x, y, slot, tempVertices);
|
int meshVertexCount = meshAttachment.uvs.Length;
|
||||||
|
if (tempVertices.Length < meshVertexCount) tempVertices = new float[meshVertexCount];
|
||||||
color.a = (byte)(a * slot.a * meshAttachment.a);
|
meshAttachment.ComputeWorldVertices(x, y, slot, tempVertices);
|
||||||
color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
|
|
||||||
color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
|
color.a = (byte)(a * slot.a * meshAttachment.a);
|
||||||
color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
|
color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
|
||||||
if (slot.data.additiveBlending) color.a = 0;
|
color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
|
||||||
|
color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
|
||||||
float[] meshUVs = meshAttachment.uvs;
|
if (slot.data.additiveBlending) color.a = 0;
|
||||||
float z = i * zSpacing;
|
|
||||||
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
|
float[] meshUVs = meshAttachment.uvs;
|
||||||
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z);
|
float z = i * zSpacing;
|
||||||
colors[vertexIndex] = color;
|
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
|
||||||
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]);
|
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z);
|
||||||
|
colors[vertexIndex] = color;
|
||||||
|
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -296,7 +305,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Stores vertices and triangles for a single material. */
|
/** Stores vertices and triangles for a single material. */
|
||||||
private void addSubmesh (Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh) {
|
private void AddSubmesh (Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh) {
|
||||||
int submeshIndex = submeshMaterials.Count;
|
int submeshIndex = submeshMaterials.Count;
|
||||||
submeshMaterials.Add(material);
|
submeshMaterials.Add(material);
|
||||||
|
|
||||||
@ -316,6 +325,24 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
submesh.triangleCount = 0;
|
submesh.triangleCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!renderMeshes) {
|
||||||
|
// Use stored triangles if possible.
|
||||||
|
if (submesh.firstVertex != firstVertex || submesh.triangleCount < triangleCount) {
|
||||||
|
submesh.triangleCount = triangleCount;
|
||||||
|
submesh.firstVertex = firstVertex;
|
||||||
|
for (int i = 0; i < triangleCount; i += 6, firstVertex += 4) {
|
||||||
|
triangles[i] = firstVertex;
|
||||||
|
triangles[i + 1] = firstVertex + 2;
|
||||||
|
triangles[i + 2] = firstVertex + 1;
|
||||||
|
triangles[i + 3] = firstVertex + 2;
|
||||||
|
triangles[i + 4] = firstVertex + 3;
|
||||||
|
triangles[i + 5] = firstVertex + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store triangles.
|
||||||
List<Slot> drawOrder = skeleton.DrawOrder;
|
List<Slot> drawOrder = skeleton.DrawOrder;
|
||||||
for (int i = startSlot, triangleIndex = 0; i < endSlot; i++) {
|
for (int i = startSlot, triangleIndex = 0; i < endSlot; i++) {
|
||||||
Attachment attachment = drawOrder[i].attachment;
|
Attachment attachment = drawOrder[i].attachment;
|
||||||
@ -326,11 +353,11 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
attachmentTriangles = quadTriangles;
|
attachmentTriangles = quadTriangles;
|
||||||
} else if (attachment is MeshAttachment) {
|
} else if (attachment is MeshAttachment) {
|
||||||
MeshAttachment meshAttachment = (MeshAttachment)attachment;
|
MeshAttachment meshAttachment = (MeshAttachment)attachment;
|
||||||
attachmentVertexCount = meshAttachment.vertices.Length / 2;
|
attachmentVertexCount = meshAttachment.vertices.Length >> 1;
|
||||||
attachmentTriangles = meshAttachment.triangles;
|
attachmentTriangles = meshAttachment.triangles;
|
||||||
} else if (attachment is SkinnedMeshAttachment) {
|
} else if (attachment is SkinnedMeshAttachment) {
|
||||||
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
|
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
|
||||||
attachmentVertexCount = meshAttachment.uvs.Length / 2;
|
attachmentVertexCount = meshAttachment.uvs.Length >> 1;
|
||||||
attachmentTriangles = meshAttachment.triangles;
|
attachmentTriangles = meshAttachment.triangles;
|
||||||
} else
|
} else
|
||||||
continue;
|
continue;
|
||||||
@ -366,4 +393,5 @@ public class SkeletonRenderer : MonoBehaviour {
|
|||||||
class Submesh {
|
class Submesh {
|
||||||
public int[] triangles = new int[0];
|
public int[] triangles = new int[0];
|
||||||
public int triangleCount;
|
public int triangleCount;
|
||||||
|
public int firstVertex = -1;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user