diff --git a/CHANGELOG.md b/CHANGELOG.md
index 72e4e19d2..223e4d9bf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -316,6 +316,8 @@
* Added example component `SkeletonRenderTexture` to render a `SkeletonRenderer` to a `RenderTexture`, mainly for proper transparency. Added an example scene named `RenderTexture FadeOut Transparency` that demonstrates usage for a fadeout transparency effect.
* Added another fadeout example component named `SkeletonRenderTextureFadeout` which takes over transparency fadeout when enabled. You can use this component as-is, attach it in disabled state and enable it to start a fadeout effect.
* Timeline clips now offer an additional `Alpha` parameter for setting a custom constant mix alpha value other than 1.0, just as `TrackEntry.Alpha`. Defaults to 1.0.
+ * `SkeletonGraphic` now provides additional render callback delegates `OnInstructionsPrepared`, `AssignMeshOverrideSingleRenderer` and `AssignMeshOverrideMultipleRenderers`. `OnInstructionsPrepared` is raised at the end of LateUpdate after render instructions are done, target renderers are prepared, and the mesh is ready to be generated. The two `AssignMeshOverride` delegates allow separate code to take over mesh and material assignment of a `SkeletonGraphic` component.
+ * Added example component `SkeletonGraphicRenderTexture` to render a `SkeletonGraphic` to a `RenderTexture` (similar as `SkeletonRenderTexture`), mainly for proper transparency. Extended example scene `RenderTexture FadeOut Transparency` accordingly.
* **Changes of default values**
diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp
index 8184ff13b..80a88c8d0 100644
--- a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp
+++ b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp
@@ -967,7 +967,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
toColor(color2, Json::getString(keyMap, "dark", 0), false);
for (frame = 0, bezier = 0;; ++frame) {
- timeline->setFrame(frame, time, color.r, color.g, color.b, color.a, color2.g, color2.g, color2.b);
+ timeline->setFrame(frame, time, color.r, color.g, color.b, color.a, color2.r, color2.g, color2.b);
nextMap = keyMap->_next;
if (!nextMap) {
// timeline.shrink(); // BOZO
diff --git a/spine-godot/README.md b/spine-godot/README.md
index bb4609b03..4a987cbf5 100644
--- a/spine-godot/README.md
+++ b/spine-godot/README.md
@@ -2,7 +2,7 @@
The spine-godot runtime provides functionality to load, manipulate and render [Spine](http://esotericsoftware.com) skeletal animation data using [Godot](https://godotengine.org/). spine-godot is based on [spine-cpp](../spine-cpp).
-# See the [spine-godot documentation](http://esotericsoftware.com/spine-godot]) for in-depth information.
+# See the [spine-godot documentation](http://esotericsoftware.com/spine-godot) for in-depth information.
## Licensing
diff --git a/spine-sdl/example/main.c b/spine-sdl/example/main.c
index 77512e131..deaaf7238 100644
--- a/spine-sdl/example/main.c
+++ b/spine-sdl/example/main.c
@@ -52,14 +52,14 @@ int main() {
json->scale = 0.5f;
spSkeletonData *skeletonData = spSkeletonJson_readSkeletonDataFile(json, "data/spineboy-pro.json");
spAnimationStateData *animationStateData = spAnimationStateData_create(skeletonData);
- animationStateData->defaultMix = 0.2f;
+ animationStateData->defaultMix = 0.2f;
spSkeletonDrawable *drawable = spSkeletonDrawable_create(skeletonData, animationStateData);
drawable->skeleton->x = 400;
drawable->skeleton->y = 500;
spSkeleton_setToSetupPose(drawable->skeleton);
spSkeletonDrawable_update(drawable, 0);
spAnimationState_setAnimationByName(drawable->animationState, 0, "portal", 0);
- spAnimationState_addAnimationByName(drawable->animationState, 0, "run", -1, 0);
+ spAnimationState_addAnimationByName(drawable->animationState, 0, "run", -1, 0);
int quit = 0;
uint64_t lastFrameTime = SDL_GetPerformanceCounter();
diff --git a/spine-sdl/example/main.cpp b/spine-sdl/example/main.cpp
index 18c3052f0..af8f08ec6 100644
--- a/spine-sdl/example/main.cpp
+++ b/spine-sdl/example/main.cpp
@@ -54,11 +54,11 @@ int main(int argc, char **argv) {
json.setScale(0.5f);
spine::SkeletonData *skeletonData = json.readSkeletonDataFile("data/spineboy-pro.json");
spine::SkeletonDrawable drawable(skeletonData);
- drawable.animationState->getData()->setDefaultMix(0.2f);
+ drawable.animationState->getData()->setDefaultMix(0.2f);
drawable.skeleton->setPosition(400, 500);
drawable.skeleton->setToSetupPose();
drawable.update(0);
- drawable.animationState->setAnimation(0, "portal", true);
+ drawable.animationState->setAnimation(0, "portal", true);
drawable.animationState->addAnimation(0, "run", true, 0);
bool quit = false;
diff --git a/spine-ts/package-lock.json b/spine-ts/package-lock.json
index 1699c752f..93b24fe59 100644
--- a/spine-ts/package-lock.json
+++ b/spine-ts/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@esotericsoftware/spine-ts",
- "version": "4.1.19",
+ "version": "4.1.20",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@esotericsoftware/spine-ts",
- "version": "4.1.19",
+ "version": "4.1.20",
"license": "LicenseRef-LICENSE",
"workspaces": [
"spine-core",
@@ -603,9 +603,9 @@
}
},
"node_modules/date-fns": {
- "version": "2.28.0",
- "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz",
- "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==",
+ "version": "2.29.1",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.1.tgz",
+ "integrity": "sha512-dlLD5rKaKxpFdnjrs+5azHDFOPEu4ANy/LTh04A1DTzMM7qoajmKCBc8pkKRFT41CNzw+4gQh79X5C+Jq27HAw==",
"dev": true,
"engines": {
"node": ">=0.11"
@@ -1129,9 +1129,9 @@
}
},
"node_modules/http-parser-js": {
- "version": "0.5.6",
- "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz",
- "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==",
+ "version": "0.5.8",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
+ "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==",
"dev": true
},
"node_modules/inflight": {
@@ -7967,41 +7967,41 @@
},
"spine-canvas": {
"name": "@esotericsoftware/spine-canvas",
- "version": "4.1.19",
+ "version": "4.1.20",
"license": "LicenseRef-LICENSE",
"dependencies": {
- "@esotericsoftware/spine-core": "^4.1.19"
+ "@esotericsoftware/spine-core": "^4.1.20"
}
},
"spine-core": {
"name": "@esotericsoftware/spine-core",
- "version": "4.1.19",
+ "version": "4.1.20",
"license": "LicenseRef-LICENSE"
},
"spine-player": {
"name": "@esotericsoftware/spine-player",
- "version": "4.1.19",
+ "version": "4.1.20",
"license": "LicenseRef-LICENSE",
"dependencies": {
- "@esotericsoftware/spine-webgl": "^4.1.19"
+ "@esotericsoftware/spine-webgl": "^4.1.20"
}
},
"spine-threejs": {
"name": "@esotericsoftware/spine-threejs",
- "version": "4.1.19",
+ "version": "4.1.20",
"license": "LicenseRef-LICENSE",
"dependencies": {
- "@esotericsoftware/spine-core": "^4.1.19",
+ "@esotericsoftware/spine-core": "^4.1.20",
"@types/three": "^0.140.0",
"three": "^0.140.0"
}
},
"spine-webgl": {
"name": "@esotericsoftware/spine-webgl",
- "version": "4.1.19",
+ "version": "4.1.20",
"license": "LicenseRef-LICENSE",
"dependencies": {
- "@esotericsoftware/spine-core": "^4.1.19"
+ "@esotericsoftware/spine-core": "^4.1.20"
}
}
},
@@ -8009,7 +8009,7 @@
"@esotericsoftware/spine-canvas": {
"version": "file:spine-canvas",
"requires": {
- "@esotericsoftware/spine-core": "^4.1.19"
+ "@esotericsoftware/spine-core": "^4.1.20"
}
},
"@esotericsoftware/spine-core": {
@@ -8018,13 +8018,13 @@
"@esotericsoftware/spine-player": {
"version": "file:spine-player",
"requires": {
- "@esotericsoftware/spine-webgl": "^4.1.19"
+ "@esotericsoftware/spine-webgl": "^4.1.20"
}
},
"@esotericsoftware/spine-threejs": {
"version": "file:spine-threejs",
"requires": {
- "@esotericsoftware/spine-core": "^4.1.19",
+ "@esotericsoftware/spine-core": "^4.1.20",
"@types/three": "^0.140.0",
"three": "^0.140.0"
}
@@ -8032,7 +8032,7 @@
"@esotericsoftware/spine-webgl": {
"version": "file:spine-webgl",
"requires": {
- "@esotericsoftware/spine-core": "^4.1.19"
+ "@esotericsoftware/spine-core": "^4.1.20"
}
},
"@types/offscreencanvas": {
@@ -8484,9 +8484,9 @@
}
},
"date-fns": {
- "version": "2.28.0",
- "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz",
- "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==",
+ "version": "2.29.1",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.1.tgz",
+ "integrity": "sha512-dlLD5rKaKxpFdnjrs+5azHDFOPEu4ANy/LTh04A1DTzMM7qoajmKCBc8pkKRFT41CNzw+4gQh79X5C+Jq27HAw==",
"dev": true
},
"debug": {
@@ -8900,9 +8900,9 @@
}
},
"http-parser-js": {
- "version": "0.5.6",
- "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz",
- "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==",
+ "version": "0.5.8",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
+ "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==",
"dev": true
},
"inflight": {
diff --git a/spine-ts/package.json b/spine-ts/package.json
index dcd0b7f75..df1b7aeef 100644
--- a/spine-ts/package.json
+++ b/spine-ts/package.json
@@ -1,6 +1,6 @@
{
"name": "@esotericsoftware/spine-ts",
- "version": "4.1.19",
+ "version": "4.1.20",
"description": "The official Spine Runtimes for the web.",
"files": [
"README.md"
diff --git a/spine-ts/spine-canvas/package.json b/spine-ts/spine-canvas/package.json
index 5f0cf533d..4e70671e0 100644
--- a/spine-ts/spine-canvas/package.json
+++ b/spine-ts/spine-canvas/package.json
@@ -1,6 +1,6 @@
{
"name": "@esotericsoftware/spine-canvas",
- "version": "4.1.19",
+ "version": "4.1.20",
"description": "The official Spine Runtimes for the web.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -30,6 +30,6 @@
},
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
"dependencies": {
- "@esotericsoftware/spine-core": "^4.1.19"
+ "@esotericsoftware/spine-core": "^4.1.20"
}
}
\ No newline at end of file
diff --git a/spine-ts/spine-core/package.json b/spine-ts/spine-core/package.json
index d924a7fe2..6cfcd02c3 100644
--- a/spine-ts/spine-core/package.json
+++ b/spine-ts/spine-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@esotericsoftware/spine-core",
- "version": "4.1.19",
+ "version": "4.1.20",
"description": "The official Spine Runtimes for the web.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
diff --git a/spine-ts/spine-player/package.json b/spine-ts/spine-player/package.json
index b64718b6a..5ba5ada69 100644
--- a/spine-ts/spine-player/package.json
+++ b/spine-ts/spine-player/package.json
@@ -1,6 +1,6 @@
{
"name": "@esotericsoftware/spine-player",
- "version": "4.1.19",
+ "version": "4.1.20",
"description": "The official Spine Runtimes for the web.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -30,6 +30,6 @@
},
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
"dependencies": {
- "@esotericsoftware/spine-webgl": "^4.1.19"
+ "@esotericsoftware/spine-webgl": "^4.1.20"
}
}
\ No newline at end of file
diff --git a/spine-ts/spine-threejs/package.json b/spine-ts/spine-threejs/package.json
index 7d6265c91..a50b9746e 100644
--- a/spine-ts/spine-threejs/package.json
+++ b/spine-ts/spine-threejs/package.json
@@ -1,6 +1,6 @@
{
"name": "@esotericsoftware/spine-threejs",
- "version": "4.1.19",
+ "version": "4.1.20",
"description": "The official Spine Runtimes for the web.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -32,6 +32,6 @@
"dependencies": {
"@types/three": "^0.140.0",
"three": "^0.140.0",
- "@esotericsoftware/spine-core": "^4.1.19"
+ "@esotericsoftware/spine-core": "^4.1.20"
}
}
\ No newline at end of file
diff --git a/spine-ts/spine-threejs/src/ThreeJsTexture.ts b/spine-ts/spine-threejs/src/ThreeJsTexture.ts
index aef066548..be48c3013 100644
--- a/spine-ts/spine-threejs/src/ThreeJsTexture.ts
+++ b/spine-ts/spine-threejs/src/ThreeJsTexture.ts
@@ -35,8 +35,10 @@ export class ThreeJsTexture extends Texture {
constructor (image: HTMLImageElement | ImageBitmap) {
super(image);
- if (image instanceof ImageBitmap) throw new Error("ImageBitmap not supported.");
- this.texture = new THREE.Texture(image);
+ if (image instanceof ImageBitmap)
+ this.texture = new THREE.CanvasTexture(image);
+ else
+ this.texture = new THREE.Texture(image);
this.texture.flipY = false;
this.texture.needsUpdate = true;
}
diff --git a/spine-ts/spine-webgl/package.json b/spine-ts/spine-webgl/package.json
index 7a9f57201..f4ad4e80b 100644
--- a/spine-ts/spine-webgl/package.json
+++ b/spine-ts/spine-webgl/package.json
@@ -1,6 +1,6 @@
{
"name": "@esotericsoftware/spine-webgl",
- "version": "4.1.19",
+ "version": "4.1.20",
"description": "The official Spine Runtimes for the web.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -30,6 +30,6 @@
},
"homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
"dependencies": {
- "@esotericsoftware/spine-core": "^4.1.19"
+ "@esotericsoftware/spine-core": "^4.1.20"
}
}
\ No newline at end of file
diff --git a/spine-unity/Assets/Spine Examples/Other Examples/RenderTexture FadeOut Transparency.unity b/spine-unity/Assets/Spine Examples/Other Examples/RenderTexture FadeOut Transparency.unity
index c5ae69f86..93acf07d8 100644
--- a/spine-unity/Assets/Spine Examples/Other Examples/RenderTexture FadeOut Transparency.unity
+++ b/spine-unity/Assets/Spine Examples/Other Examples/RenderTexture FadeOut Transparency.unity
@@ -153,7 +153,7 @@ RectTransform:
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 592567554}
- m_RootOrder: 0
+ m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 1, y: 1}
m_AnchorMax: {x: 1, y: 1}
@@ -256,6 +256,8 @@ MonoBehaviour:
materialsInsideMask: []
materialsOutsideMask: []
disableRenderingOnOverride: 1
+ updateTiming: 1
+ unscaledTime: 0
_animationName: run
loop: 1
timeScale: 1
@@ -316,11 +318,11 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 334034152}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: -5.93, y: 0, z: 5.66}
+ m_LocalPosition: {x: -7.83, y: 0, z: 5.66}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
- m_RootOrder: 4
+ m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &541830406
GameObject:
@@ -352,7 +354,7 @@ RectTransform:
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 592567554}
- m_RootOrder: 1
+ m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 1, y: 1}
m_AnchorMax: {x: 1, y: 1}
@@ -433,9 +435,11 @@ RectTransform:
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_Children:
+ - {fileID: 1911967440}
- {fileID: 71621967}
- {fileID: 541830407}
- {fileID: 1682675646}
+ - {fileID: 1735507358}
m_Father: {fileID: 1799507978}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -488,6 +492,41 @@ Canvas:
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
+--- !u!1 &1089682726
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1089682727}
+ m_Layer: 0
+ m_Name: CustomRenderRect
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1089682727
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1089682726}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 1911967440}
+ m_RootOrder: 0
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0.5, y: 0.5}
+ m_AnchorMax: {x: 0.5, y: 0.5}
+ m_AnchoredPosition: {x: 126.27, y: 7.130005}
+ m_SizeDelta: {x: 1893.1, y: 1654.617}
+ m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &1368805070
GameObject:
m_ObjectHideFlags: 0
@@ -532,6 +571,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
renderTextureFadeout: {fileID: 1786065619}
+ renderTextureFadeoutCanvas: {fileID: 1911967443}
normalSkeletonRenderer: {fileID: 334034153}
--- !u!1 &1369381599
GameObject:
@@ -805,12 +845,12 @@ RectTransform:
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 592567554}
- m_RootOrder: 2
+ m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
- m_AnchorMin: {x: 0.5, y: 0}
- m_AnchorMax: {x: 0.5, y: 0.5}
- m_AnchoredPosition: {x: -331.4, y: -186}
- m_SizeDelta: {x: 1176.1, y: -365}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0.6932292, y: 0.18750001}
+ m_AnchoredPosition: {x: 18.079224, y: 1.5001221}
+ m_SizeDelta: {x: -44.942017, y: 10}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1682675647
MonoBehaviour:
@@ -847,12 +887,13 @@ MonoBehaviour:
m_LineSpacing: 1
m_Text: 'This scene demonstrates the problems of using conventional alpha transparency
for a fadeout effect (left), and how this problem can be fixed by using a RenderTexture
- (right).
+ (center and right).
- Spineboy on the right uses a SkeletonRenderTexture component to
- render the overlapping mesh to a RenderTexture first and then draw this texture
- to the scene at once using a single quad.'
+ The two Spineboys on the right use SkeletonRenderTexture
+ and SkeletonGraphicRenderTexture components to render the overlapping mesh to
+ a RenderTexture first and then draw this texture to the scene at once using a
+ single quad.'
--- !u!222 &1682675648
CanvasRenderer:
m_ObjectHideFlags: 0
@@ -861,6 +902,87 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1682675645}
m_CullTransparentMesh: 1
+--- !u!1 &1735507357
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1735507358}
+ - component: {fileID: 1735507360}
+ - component: {fileID: 1735507359}
+ m_Layer: 5
+ m_Name: SkeletonGraphic Notes
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1735507358
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1735507357}
+ m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 592567554}
+ m_RootOrder: 4
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0.6932292, y: 0}
+ m_AnchorMax: {x: 1, y: 0.18750001}
+ m_AnchoredPosition: {x: 6.5009766, y: -2.5753784}
+ m_SizeDelta: {x: -49.462, y: 1.8482}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1735507359
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1735507357}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_FontData:
+ m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+ m_FontSize: 26
+ m_FontStyle: 0
+ m_BestFit: 0
+ m_MinSize: 2
+ m_MaxSize: 40
+ m_Alignment: 2
+ m_AlignByGeometry: 0
+ m_RichText: 1
+ m_HorizontalOverflow: 0
+ m_VerticalOverflow: 1
+ m_LineSpacing: 1
+ m_Text: SkeletonGraphicRenderTexture supports setting a RectTransform as 'Custom
+ Render Rect' to define render texture bounds different from the SkeletonGraphic
+ rect.
+--- !u!222 &1735507360
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1735507357}
+ m_CullTransparentMesh: 1
--- !u!1 &1786065613
GameObject:
m_ObjectHideFlags: 0
@@ -895,11 +1017,11 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
color: {r: 1, g: 1, b: 1, a: 1}
- quadMaterial: {fileID: 2100000, guid: 4c507f887c6274a44a603d96e0eabf2a, type: 2}
- targetCamera: {fileID: 0}
maxRenderTextureSize: 1024
quad: {fileID: 0}
renderTexture: {fileID: 0}
+ targetCamera: {fileID: 0}
+ quadMaterial: {fileID: 2100000, guid: 4c507f887c6274a44a603d96e0eabf2a, type: 2}
--- !u!114 &1786065615
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -935,6 +1057,8 @@ MonoBehaviour:
materialsInsideMask: []
materialsOutsideMask: []
disableRenderingOnOverride: 1
+ updateTiming: 1
+ unscaledTime: 0
_animationName: run
loop: 1
timeScale: 1
@@ -995,11 +1119,11 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1786065613}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
- m_LocalPosition: {x: 3.32, y: 0, z: 5.66}
+ m_LocalPosition: {x: 2.38, y: 0, z: 5.66}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
- m_RootOrder: 3
+ m_RootOrder: 4
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1786065619
MonoBehaviour:
@@ -1045,3 +1169,136 @@ Transform:
m_Father: {fileID: 0}
m_RootOrder: 6
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1911967439
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1911967440}
+ - component: {fileID: 1911967442}
+ - component: {fileID: 1911967441}
+ - component: {fileID: 1911967444}
+ - component: {fileID: 1911967443}
+ m_Layer: 0
+ m_Name: SkeletonGraphic (spineboy-pro)
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &1911967440
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1911967439}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 0.3, y: 0.3, z: 0.3}
+ m_Children:
+ - {fileID: 1089682727}
+ m_Father: {fileID: 592567554}
+ m_RootOrder: 0
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0.5, y: 0.5}
+ m_AnchorMax: {x: 1, y: 0.5}
+ m_AnchoredPosition: {x: 84, y: -317.51}
+ m_SizeDelta: {x: 1185.6, y: 1302.059}
+ m_Pivot: {x: 0.63858336, y: 0.010301443}
+--- !u!114 &1911967441
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1911967439}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: d85b887af7e6c3f45a2e2d2920d641bc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 2100000, guid: b66cf7a186d13054989b33a5c90044e4, type: 2}
+ m_Color: {r: 1, g: 1, b: 1, a: 1}
+ m_RaycastTarget: 1
+ m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+ m_Maskable: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ skeletonDataAsset: {fileID: 11400000, guid: af38a3de26ed9b84abc2fe7c7f3b209d, type: 2}
+ additiveMaterial: {fileID: 2100000, guid: 2e8245019faeb8c43b75f9ca3ac8ee34, type: 2}
+ multiplyMaterial: {fileID: 2100000, guid: e74a1f8978a7da348a721508d0d58834, type: 2}
+ screenMaterial: {fileID: 2100000, guid: bab24c479f34eec45be6ea8595891569, type: 2}
+ initialSkinName: default
+ initialFlipX: 0
+ initialFlipY: 0
+ startingAnimation: run
+ startingLoop: 1
+ timeScale: 1
+ freeze: 0
+ updateWhenInvisible: 3
+ allowMultipleCanvasRenderers: 0
+ canvasRenderers: []
+ separatorSlotNames: []
+ enableSeparatorSlots: 0
+ separatorParts: []
+ updateSeparatorPartLocation: 1
+ disableMeshAssignmentOnOverride: 1
+ meshGenerator:
+ settings:
+ useClipping: 1
+ zSpacing: 0
+ pmaVertexColors: 1
+ tintBlack: 0
+ canvasGroupTintBlack: 0
+ calculateTangents: 0
+ addNormals: 0
+ immutableTriangles: 0
+ updateTiming: 1
+ unscaledTime: 0
+--- !u!222 &1911967442
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1911967439}
+ m_CullTransparentMesh: 0
+--- !u!114 &1911967443
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1911967439}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 5fc94f89310427643babb41e000a8462, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ fadeoutSeconds: 2
+--- !u!114 &1911967444
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1911967439}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 6cbe1f11426513d49ad8e21e9d6643f7, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ color: {r: 1, g: 1, b: 1, a: 1}
+ maxRenderTextureSize: 1024
+ quad: {fileID: 0}
+ renderTexture: {fileID: 0}
+ targetCamera: {fileID: 0}
+ customRenderRect: {fileID: 1089682727}
+ meshRendererMaterialForTexture:
+ - texture: {fileID: 2800000, guid: 4ea2c33e839afb34c98f66e892b3b2d2, type: 3}
+ material: {fileID: 2100000, guid: f89bbf05902e77242a3ad20f3c927353, type: 2}
diff --git a/spine-unity/Assets/Spine Examples/Scripts/RenderTextureFadeoutExample.cs b/spine-unity/Assets/Spine Examples/Scripts/RenderTextureFadeoutExample.cs
index 19b67376d..4e5babaf2 100644
--- a/spine-unity/Assets/Spine Examples/Scripts/RenderTextureFadeoutExample.cs
+++ b/spine-unity/Assets/Spine Examples/Scripts/RenderTextureFadeoutExample.cs
@@ -39,6 +39,7 @@ namespace Spine.Unity.Examples {
public class RenderTextureFadeoutExample : MonoBehaviour {
public SkeletonRenderTextureFadeout renderTextureFadeout;
+ public SkeletonRenderTextureFadeout renderTextureFadeoutCanvas;
public SkeletonRenderer normalSkeletonRenderer;
float fadeoutSeconds = 2.0f;
@@ -47,8 +48,9 @@ namespace Spine.Unity.Examples {
IEnumerator Start () {
while (true) {
StartFadeoutBad();
- StartFadeoutGood();
- yield return new WaitForSeconds(5.0f);
+ StartFadeoutGood(renderTextureFadeout);
+ StartFadeoutGood(renderTextureFadeoutCanvas);
+ yield return new WaitForSeconds(fadeoutSeconds + 1.0f);
}
}
void Update () {
@@ -75,12 +77,12 @@ namespace Spine.Unity.Examples {
fadeoutSecondsRemaining = fadeoutSeconds;
}
- void StartFadeoutGood () {
- renderTextureFadeout.gameObject.SetActive(true);
+ void StartFadeoutGood (SkeletonRenderTextureFadeout fadeoutComponent) {
+ fadeoutComponent.gameObject.SetActive(true);
// enabling the SkeletonRenderTextureFadeout component starts the fadeout.
- renderTextureFadeout.enabled = true;
- renderTextureFadeout.OnFadeoutComplete -= DisableGameObject;
- renderTextureFadeout.OnFadeoutComplete += DisableGameObject;
+ fadeoutComponent.enabled = true;
+ fadeoutComponent.OnFadeoutComplete -= DisableGameObject;
+ fadeoutComponent.OnFadeoutComplete += DisableGameObject;
}
void DisableGameObject (SkeletonRenderTextureFadeout target) {
diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs
new file mode 100644
index 000000000..5587bced2
--- /dev/null
+++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs
@@ -0,0 +1,259 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2022, 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.
+ *
+ * THE SPINE RUNTIMES ARE 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
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#if UNITY_2017_2_OR_NEWER
+#define HAS_VECTOR2INT
+#endif
+
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Rendering;
+using UnityEngine.UI;
+
+namespace Spine.Unity.Examples {
+
+ ///
+ /// When enabled, this component renders a skeleton to a RenderTexture and
+ /// then draws this RenderTexture at a UI RawImage quad of the same size.
+ /// This allows changing transparency at a single quad, which produces a more
+ /// natural fadeout effect.
+ /// Note: It is recommended to keep this component disabled as much as possible
+ /// because of the additional rendering overhead. Only enable it when alpha blending is required.
+ ///
+ [RequireComponent(typeof(SkeletonGraphic))]
+ public class SkeletonGraphicRenderTexture : SkeletonRenderTextureBase {
+#if HAS_VECTOR2INT
+ [System.Serializable]
+ public struct TextureMaterialPair {
+ public Texture texture;
+ public Material material;
+
+ public TextureMaterialPair (Texture texture, Material material) {
+ this.texture = texture;
+ this.material = material;
+ }
+ }
+
+ public RectTransform customRenderRect;
+ protected SkeletonGraphic skeletonGraphic;
+ public List meshRendererMaterialForTexture = new List();
+ protected CanvasRenderer quadCanvasRenderer;
+ protected RawImage quadRawImage;
+ protected readonly Vector3[] worldCorners = new Vector3[4];
+
+ protected override void Awake () {
+ base.Awake();
+ skeletonGraphic = this.GetComponent();
+ if (targetCamera == null) {
+ targetCamera = skeletonGraphic.canvas.worldCamera;
+ if (targetCamera == null)
+ targetCamera = Camera.main;
+ }
+ CreateQuadChild();
+ }
+
+ void CreateQuadChild () {
+ quad = new GameObject(this.name + " RenderTexture", typeof(CanvasRenderer), typeof(RawImage));
+ quad.transform.SetParent(this.transform.parent, false);
+ quadCanvasRenderer = quad.GetComponent();
+ quadRawImage = quad.GetComponent();
+
+ quadMesh = new Mesh();
+ quadMesh.MarkDynamic();
+ quadMesh.name = "RenderTexture Quad";
+ quadMesh.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor;
+ }
+
+ void Reset () {
+ skeletonGraphic = this.GetComponent();
+ AtlasAssetBase[] atlasAssets = skeletonGraphic.SkeletonDataAsset.atlasAssets;
+ for (int i = 0; i < atlasAssets.Length; ++i) {
+ foreach (var material in atlasAssets[i].Materials) {
+ if (material.mainTexture != null) {
+ meshRendererMaterialForTexture.Add(
+ new TextureMaterialPair(material.mainTexture, material));
+ }
+ }
+ }
+ }
+
+ void OnEnable () {
+ skeletonGraphic.OnInstructionsPrepared += PrepareQuad;
+ skeletonGraphic.AssignMeshOverrideSingleRenderer += RenderSingleMeshToRenderTexture;
+ skeletonGraphic.AssignMeshOverrideMultipleRenderers += RenderMultipleMeshesToRenderTexture;
+ skeletonGraphic.disableMeshAssignmentOnOverride = true;
+ skeletonGraphic.OnMeshAndMaterialsUpdated += RenderOntoQuad;
+ var canvasRenderers = skeletonGraphic.canvasRenderers;
+ for (int i = 0; i < canvasRenderers.Count; ++i)
+ canvasRenderers[i].cull = true;
+
+ if (quadCanvasRenderer)
+ quadCanvasRenderer.gameObject.SetActive(true);
+ }
+
+ void OnDisable () {
+ skeletonGraphic.OnInstructionsPrepared -= PrepareQuad;
+ skeletonGraphic.AssignMeshOverrideSingleRenderer -= RenderSingleMeshToRenderTexture;
+ skeletonGraphic.AssignMeshOverrideMultipleRenderers -= RenderMultipleMeshesToRenderTexture;
+ skeletonGraphic.disableMeshAssignmentOnOverride = false;
+ skeletonGraphic.OnMeshAndMaterialsUpdated -= RenderOntoQuad;
+ var canvasRenderers = skeletonGraphic.canvasRenderers;
+ for (int i = 0; i < canvasRenderers.Count; ++i)
+ canvasRenderers[i].cull = false;
+
+ if (quadCanvasRenderer)
+ quadCanvasRenderer.gameObject.SetActive(false);
+ if (renderTexture)
+ RenderTexture.ReleaseTemporary(renderTexture);
+ allocatedRenderTextureSize = Vector2Int.zero;
+ }
+
+ void PrepareQuad (SkeletonRendererInstruction instruction) {
+ PrepareForMesh();
+ SetupQuad();
+ }
+
+ void RenderOntoQuad (SkeletonGraphic skeletonRenderer) {
+ AssignAtQuad();
+ }
+
+ protected void PrepareForMesh () {
+ // We need to get the min/max of all four corners, rotation of the skeleton
+ // in combination with perspective projection otherwise might lead to incorrect
+ // screen space min/max.
+ RectTransform rectTransform = customRenderRect ? customRenderRect : skeletonGraphic.rectTransform;
+ rectTransform.GetWorldCorners(worldCorners);
+
+ RenderMode canvasRenderMode = skeletonGraphic.canvas.renderMode;
+ Vector3 screenCorner0, screenCorner1, screenCorner2, screenCorner3;
+ // note: world corners are ordered bottom left, top left, top right, bottom right.
+ // This corresponds to 0, 3, 1, 2 in our desired order.
+ if (canvasRenderMode == RenderMode.ScreenSpaceOverlay) {
+ screenCorner0 = worldCorners[0];
+ screenCorner1 = worldCorners[3];
+ screenCorner2 = worldCorners[1];
+ screenCorner3 = worldCorners[2];
+ } else {
+ screenCorner0 = targetCamera.WorldToScreenPoint(worldCorners[0]);
+ screenCorner1 = targetCamera.WorldToScreenPoint(worldCorners[3]);
+ screenCorner2 = targetCamera.WorldToScreenPoint(worldCorners[1]);
+ screenCorner3 = targetCamera.WorldToScreenPoint(worldCorners[2]);
+ }
+
+ // To avoid perspective distortion when rotated, we project all vertices
+ // onto a plane parallel to the view frustum near plane.
+ // Avoids the requirement of 'noperspective' vertex attribute interpolation modifier in shaders.
+ float averageScreenDepth = (screenCorner0.z + screenCorner1.z + screenCorner2.z + screenCorner3.z) / 4.0f;
+ screenCorner0.z = screenCorner1.z = screenCorner2.z = screenCorner3.z = averageScreenDepth;
+
+ if (canvasRenderMode == RenderMode.ScreenSpaceOverlay) {
+ worldCornerNoDistortion0 = screenCorner0;
+ worldCornerNoDistortion1 = screenCorner1;
+ worldCornerNoDistortion2 = screenCorner2;
+ worldCornerNoDistortion3 = screenCorner3;
+ } else {
+ worldCornerNoDistortion0 = targetCamera.ScreenToWorldPoint(screenCorner0);
+ worldCornerNoDistortion1 = targetCamera.ScreenToWorldPoint(screenCorner1);
+ worldCornerNoDistortion2 = targetCamera.ScreenToWorldPoint(screenCorner2);
+ worldCornerNoDistortion3 = targetCamera.ScreenToWorldPoint(screenCorner3);
+ }
+ Vector3 screenSpaceMin, screenSpaceMax;
+ PrepareTextureMapping(out screenSpaceMin, out screenSpaceMax,
+ screenCorner0, screenCorner1, screenCorner2, screenCorner3);
+ PrepareCommandBuffer(targetCamera, screenSpaceMin, screenSpaceMax);
+ }
+
+ protected Material MeshRendererMaterialForTexture (Texture texture) {
+ return meshRendererMaterialForTexture.Find(x => x.texture == texture).material;
+ }
+
+ protected void RenderSingleMeshToRenderTexture (Mesh mesh, Material graphicMaterial, Texture texture) {
+ Material meshRendererMaterial = MeshRendererMaterialForTexture(texture);
+ commandBuffer.DrawMesh(mesh, transform.localToWorldMatrix, meshRendererMaterial, 0, -1);
+ Graphics.ExecuteCommandBuffer(commandBuffer);
+ }
+
+ protected void RenderMultipleMeshesToRenderTexture (int meshCount,
+ Mesh[] meshes, Material[] graphicMaterials, Texture[] textures) {
+
+ for (int i = 0; i < meshCount; ++i) {
+ Material meshRendererMaterial = MeshRendererMaterialForTexture(textures[i]);
+ commandBuffer.DrawMesh(meshes[i], transform.localToWorldMatrix, meshRendererMaterial, 0, -1);
+ }
+ Graphics.ExecuteCommandBuffer(commandBuffer);
+ }
+
+ protected void SetupQuad () {
+ quadRawImage.texture = this.renderTexture;
+ quadRawImage.color = color;
+ quadCanvasRenderer.SetColor(color);
+
+ var srcRectTransform = skeletonGraphic.rectTransform;
+ var dstRectTransform = quadRawImage.rectTransform;
+
+ dstRectTransform.anchorMin = srcRectTransform.anchorMin;
+ dstRectTransform.anchorMax = srcRectTransform.anchorMax;
+ dstRectTransform.anchoredPosition = srcRectTransform.anchoredPosition;
+ dstRectTransform.pivot = srcRectTransform.pivot;
+ dstRectTransform.localScale = srcRectTransform.localScale;
+ dstRectTransform.sizeDelta = srcRectTransform.sizeDelta;
+ dstRectTransform.rotation = srcRectTransform.rotation;
+ }
+
+ protected void PrepareCommandBuffer (Camera targetCamera, Vector3 screenSpaceMin, Vector3 screenSpaceMax) {
+ commandBuffer.Clear();
+ commandBuffer.SetRenderTarget(renderTexture);
+ commandBuffer.ClearRenderTarget(true, true, Color.clear);
+
+ Rect canvasRect = skeletonGraphic.canvas.pixelRect;
+
+ Matrix4x4 projectionMatrix = Matrix4x4.Ortho(
+ canvasRect.x, canvasRect.x + canvasRect.width,
+ canvasRect.y, canvasRect.y + canvasRect.height,
+ float.MinValue, float.MaxValue);
+
+ RenderMode canvasRenderMode = skeletonGraphic.canvas.renderMode;
+ if (canvasRenderMode == RenderMode.ScreenSpaceOverlay) {
+ commandBuffer.SetViewMatrix(Matrix4x4.identity);
+ commandBuffer.SetProjectionMatrix(projectionMatrix);
+ } else {
+ commandBuffer.SetViewMatrix(targetCamera.worldToCameraMatrix);
+ commandBuffer.SetProjectionMatrix(targetCamera.projectionMatrix);
+ }
+
+ Vector2 targetCameraViewportSize = targetCamera.pixelRect.size;
+ commandBuffer.SetViewport(new Rect(-screenSpaceMin, targetCameraViewportSize));
+ }
+
+ protected override void AssignMeshAtRenderer () {
+ quadCanvasRenderer.SetMesh(quadMesh);
+ }
+#endif // HAS_VECTOR2INT
+ }
+}
diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs.meta b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs.meta
new file mode 100644
index 000000000..7d3e6d8ed
--- /dev/null
+++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonGraphicRenderTexture.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6cbe1f11426513d49ad8e21e9d6643f7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTexture.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTexture.cs
index 19c814c04..4ded9af01 100644
--- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTexture.cs
+++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTexture.cs
@@ -35,7 +35,6 @@
#define HAS_GET_SHARED_MATERIALS
#endif
-using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
@@ -54,20 +53,11 @@ namespace Spine.Unity.Examples {
public class SkeletonRenderTexture : SkeletonRenderTextureBase {
#if HAS_GET_SHARED_MATERIALS
public Material quadMaterial;
- public Camera targetCamera;
protected SkeletonRenderer skeletonRenderer;
protected MeshRenderer meshRenderer;
protected MeshFilter meshFilter;
protected MeshRenderer quadMeshRenderer;
protected MeshFilter quadMeshFilter;
- protected Vector3 worldCornerNoDistortion0;
- protected Vector3 worldCornerNoDistortion1;
- protected Vector3 worldCornerNoDistortion2;
- protected Vector3 worldCornerNoDistortion3;
- protected Vector2 uvCorner0;
- protected Vector2 uvCorner1;
- protected Vector2 uvCorner2;
- protected Vector2 uvCorner3;
private MaterialPropertyBlock propertyBlock;
private readonly List materials = new List();
@@ -160,40 +150,13 @@ namespace Spine.Unity.Examples {
worldCornerNoDistortion2 = targetCamera.ScreenToWorldPoint(screenCorner2);
worldCornerNoDistortion3 = targetCamera.ScreenToWorldPoint(screenCorner3);
- Vector3 screenSpaceMin =
- Vector3.Min(screenCorner0, Vector3.Min(screenCorner1,
- Vector3.Min(screenCorner2, screenCorner3)));
- Vector3 screenSpaceMax =
- Vector3.Max(screenCorner0, Vector3.Max(screenCorner1,
- Vector3.Max(screenCorner2, screenCorner3)));
- // ensure we are on whole pixel borders
- screenSpaceMin.x = Mathf.Floor(screenSpaceMin.x);
- screenSpaceMin.y = Mathf.Floor(screenSpaceMin.y);
- screenSpaceMax.x = Mathf.Ceil(screenSpaceMax.x);
- screenSpaceMax.y = Mathf.Ceil(screenSpaceMax.y);
-
- // inverse-map screenCornerN to screenSpaceMin/screenSpaceMax area to get UV coordinates
- uvCorner0 = InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner0);
- uvCorner1 = InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner1);
- uvCorner2 = InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner2);
- uvCorner3 = InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner3);
-
- requiredRenderTextureSize = new Vector2Int(
- Math.Min(maxRenderTextureSize, Math.Abs((int)screenSpaceMax.x - (int)screenSpaceMin.x)),
- Math.Min(maxRenderTextureSize, Math.Abs((int)screenSpaceMax.y - (int)screenSpaceMin.y)));
-
- PrepareRenderTexture();
+ Vector3 screenSpaceMin, screenSpaceMax;
+ PrepareTextureMapping(out screenSpaceMin, out screenSpaceMax,
+ screenCorner0, screenCorner1, screenCorner2, screenCorner3);
PrepareCommandBuffer(targetCamera, screenSpaceMin, screenSpaceMax);
}
- protected Vector2 InverseLerp (Vector2 a, Vector2 b, Vector2 value) {
- return new Vector2(
- (value.x - a.x) / (b.x - a.x),
- (value.y - a.y) / (b.y - a.y));
- }
-
protected void PrepareCommandBuffer (Camera targetCamera, Vector3 screenSpaceMin, Vector3 screenSpaceMax) {
-
commandBuffer.Clear();
commandBuffer.SetRenderTarget(renderTexture);
commandBuffer.ClearRenderTarget(true, true, Color.clear);
@@ -214,40 +177,7 @@ namespace Spine.Unity.Examples {
Graphics.ExecuteCommandBuffer(commandBuffer);
}
- protected void AssignAtQuad () {
- Transform quadTransform = quadMeshRenderer.transform;
- quadTransform.position = this.transform.position;
- quadTransform.rotation = this.transform.rotation;
- quadTransform.localScale = this.transform.localScale;
-
- Vector3 v0 = quadTransform.InverseTransformPoint(worldCornerNoDistortion0);
- Vector3 v1 = quadTransform.InverseTransformPoint(worldCornerNoDistortion1);
- Vector3 v2 = quadTransform.InverseTransformPoint(worldCornerNoDistortion2);
- Vector3 v3 = quadTransform.InverseTransformPoint(worldCornerNoDistortion3);
- Vector3[] vertices = new Vector3[4] { v0, v1, v2, v3 };
-
- quadMesh.vertices = vertices;
-
- int[] indices = new int[6] { 0, 2, 1, 2, 3, 1 };
- quadMesh.triangles = indices;
-
- Vector3[] normals = new Vector3[4] {
- -Vector3.forward,
- -Vector3.forward,
- -Vector3.forward,
- -Vector3.forward
- };
- quadMesh.normals = normals;
-
- float maxU = (float)requiredRenderTextureSize.x / (float)allocatedRenderTextureSize.x;
- float maxV = (float)requiredRenderTextureSize.y / (float)allocatedRenderTextureSize.y;
- Vector2[] uv = new Vector2[4] {
- new Vector2(uvCorner0.x * maxU, uvCorner0.y * maxV),
- new Vector2(uvCorner1.x * maxU, uvCorner1.y * maxV),
- new Vector2(uvCorner2.x * maxU, uvCorner2.y * maxV),
- new Vector2(uvCorner3.x * maxU, uvCorner3.y * maxV),
- };
- quadMesh.uv = uv;
+ protected override void AssignMeshAtRenderer () {
quadMeshFilter.mesh = quadMesh;
quadMeshRenderer.sharedMaterial.mainTexture = this.renderTexture;
quadMeshRenderer.sharedMaterial.color = color;
diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs
index 9a6e13959..0413d8b4a 100644
--- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs
+++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs
@@ -27,31 +27,38 @@
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
-#if UNITY_2019_3_OR_NEWER
-#define HAS_FORCE_RENDER_OFF
-#endif
-
-#if UNITY_2018_2_OR_NEWER
-#define HAS_GET_SHARED_MATERIALS
+#if UNITY_2017_2_OR_NEWER
+#define HAS_VECTOR2INT
#endif
+using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace Spine.Unity.Examples {
public abstract class SkeletonRenderTextureBase : MonoBehaviour {
-#if HAS_GET_SHARED_MATERIALS
+#if HAS_VECTOR2INT
public Color color = Color.white;
public int maxRenderTextureSize = 1024;
public GameObject quad;
protected Mesh quadMesh;
public RenderTexture renderTexture;
+ public Camera targetCamera;
protected CommandBuffer commandBuffer;
protected Vector2Int requiredRenderTextureSize;
protected Vector2Int allocatedRenderTextureSize;
+ protected Vector3 worldCornerNoDistortion0;
+ protected Vector3 worldCornerNoDistortion1;
+ protected Vector3 worldCornerNoDistortion2;
+ protected Vector3 worldCornerNoDistortion3;
+ protected Vector2 uvCorner0;
+ protected Vector2 uvCorner1;
+ protected Vector2 uvCorner2;
+ protected Vector2 uvCorner3;
+
protected virtual void Awake () {
commandBuffer = new CommandBuffer();
}
@@ -61,6 +68,34 @@ namespace Spine.Unity.Examples {
RenderTexture.ReleaseTemporary(renderTexture);
}
+ protected void PrepareTextureMapping (out Vector3 screenSpaceMin, out Vector3 screenSpaceMax,
+ Vector3 screenCorner0, Vector3 screenCorner1, Vector3 screenCorner2, Vector3 screenCorner3) {
+
+ screenSpaceMin =
+ Vector3.Min(screenCorner0, Vector3.Min(screenCorner1,
+ Vector3.Min(screenCorner2, screenCorner3)));
+ screenSpaceMax =
+ Vector3.Max(screenCorner0, Vector3.Max(screenCorner1,
+ Vector3.Max(screenCorner2, screenCorner3)));
+ // ensure we are on whole pixel borders
+ screenSpaceMin.x = Mathf.Floor(screenSpaceMin.x);
+ screenSpaceMin.y = Mathf.Floor(screenSpaceMin.y);
+ screenSpaceMax.x = Mathf.Ceil(screenSpaceMax.x);
+ screenSpaceMax.y = Mathf.Ceil(screenSpaceMax.y);
+
+ // inverse-map screenCornerN to screenSpaceMin/screenSpaceMax area to get UV coordinates
+ uvCorner0 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner0);
+ uvCorner1 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner1);
+ uvCorner2 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner2);
+ uvCorner3 = MathUtilities.InverseLerp(screenSpaceMin, screenSpaceMax, screenCorner3);
+
+ requiredRenderTextureSize = new Vector2Int(
+ Math.Min(maxRenderTextureSize, Math.Abs((int)screenSpaceMax.x - (int)screenSpaceMin.x)),
+ Math.Min(maxRenderTextureSize, Math.Abs((int)screenSpaceMax.y - (int)screenSpaceMin.y)));
+
+ PrepareRenderTexture();
+ }
+
protected void PrepareRenderTexture () {
Vector2Int textureSize = new Vector2Int(
Mathf.NextPowerOfTwo(requiredRenderTextureSize.x),
@@ -74,6 +109,45 @@ namespace Spine.Unity.Examples {
allocatedRenderTextureSize = textureSize;
}
}
-#endif
+
+ protected void AssignAtQuad () {
+ Transform quadTransform = quad.transform;
+ quadTransform.position = this.transform.position;
+ quadTransform.rotation = this.transform.rotation;
+ quadTransform.localScale = this.transform.localScale;
+
+ Vector3 v0 = quadTransform.InverseTransformPoint(worldCornerNoDistortion0);
+ Vector3 v1 = quadTransform.InverseTransformPoint(worldCornerNoDistortion1);
+ Vector3 v2 = quadTransform.InverseTransformPoint(worldCornerNoDistortion2);
+ Vector3 v3 = quadTransform.InverseTransformPoint(worldCornerNoDistortion3);
+ Vector3[] vertices = new Vector3[4] { v0, v1, v2, v3 };
+
+ quadMesh.vertices = vertices;
+
+ int[] indices = new int[6] { 0, 1, 2, 2, 1, 3 };
+ quadMesh.triangles = indices;
+
+ Vector3[] normals = new Vector3[4] {
+ -Vector3.forward,
+ -Vector3.forward,
+ -Vector3.forward,
+ -Vector3.forward
+ };
+ quadMesh.normals = normals;
+
+ float maxU = (float)requiredRenderTextureSize.x / (float)allocatedRenderTextureSize.x;
+ float maxV = (float)requiredRenderTextureSize.y / (float)allocatedRenderTextureSize.y;
+ Vector2[] uv = new Vector2[4] {
+ new Vector2(uvCorner0.x * maxU, uvCorner0.y * maxV),
+ new Vector2(uvCorner1.x * maxU, uvCorner1.y * maxV),
+ new Vector2(uvCorner2.x * maxU, uvCorner2.y * maxV),
+ new Vector2(uvCorner3.x * maxU, uvCorner3.y * maxV),
+ };
+ quadMesh.uv = uv;
+ AssignMeshAtRenderer();
+ }
+
+ protected abstract void AssignMeshAtRenderer ();
+#endif // HAS_VECTOR2INT
}
}
diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs.meta b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs.meta
new file mode 100644
index 000000000..e63c652b4
--- /dev/null
+++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonRenderTexture/SkeletonRenderTextureBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ccf9b5e5034b0ea45962f9cf32168dd9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs
index fdadf6a72..64dd609f8 100644
--- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs
+++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs
@@ -183,6 +183,59 @@ namespace Spine.Unity {
#endregion
#region Overrides
+ // API for taking over rendering.
+ /// When true, no meshes and materials are assigned at CanvasRenderers if the used override
+ /// AssignMeshOverrideSingleRenderer or AssignMeshOverrideMultipleRenderers is non-null.
+ public bool disableMeshAssignmentOnOverride = true;
+ /// Delegate type for overriding mesh and material assignment,
+ /// used when allowMultipleCanvasRenderers is false.
+ /// Mesh normally assigned at the main CanvasRenderer.
+ /// Material normally assigned at the main CanvasRenderer.
+ /// Texture normally assigned at the main CanvasRenderer.
+ public delegate void MeshAssignmentDelegateSingle (Mesh mesh, Material graphicMaterial, Texture texture);
+ /// Number of meshes. Don't use meshes.Length as this might be higher
+ /// due to pre-allocated entries.
+ /// Mesh array where each element is normally assigned to one of the canvasRenderers.
+ /// Material array where each element is normally assigned to one of the canvasRenderers.
+ /// Texture array where each element is normally assigned to one of the canvasRenderers.
+ public delegate void MeshAssignmentDelegateMultiple (int meshCount, Mesh[] meshes, Material[] graphicMaterials, Texture[] textures);
+ event MeshAssignmentDelegateSingle assignMeshOverrideSingle;
+ event MeshAssignmentDelegateMultiple assignMeshOverrideMultiple;
+
+ /// Allows separate code to take over mesh and material assignment for this SkeletonGraphic component.
+ /// Used when allowMultipleCanvasRenderers is false.
+ public event MeshAssignmentDelegateSingle AssignMeshOverrideSingleRenderer {
+ add {
+ assignMeshOverrideSingle += value;
+ if (disableMeshAssignmentOnOverride && assignMeshOverrideSingle != null) {
+ Initialize(false);
+ }
+ }
+ remove {
+ assignMeshOverrideSingle -= value;
+ if (disableMeshAssignmentOnOverride && assignMeshOverrideSingle == null) {
+ Initialize(false);
+ }
+ }
+ }
+ /// Allows separate code to take over mesh and material assignment for this SkeletonGraphic component.
+ /// Used when allowMultipleCanvasRenderers is true.
+ public event MeshAssignmentDelegateMultiple AssignMeshOverrideMultipleRenderers {
+ add {
+ assignMeshOverrideMultiple += value;
+ if (disableMeshAssignmentOnOverride && assignMeshOverrideMultiple != null) {
+ Initialize(false);
+ }
+ }
+ remove {
+ assignMeshOverrideMultiple -= value;
+ if (disableMeshAssignmentOnOverride && assignMeshOverrideMultiple == null) {
+ Initialize(false);
+ }
+ }
+ }
+
+
[System.NonSerialized] readonly Dictionary customTextureOverride = new Dictionary();
/// Use this Dictionary to override a Texture with a different Texture.
public Dictionary CustomTextureOverride { get { return customTextureOverride; } }
@@ -334,6 +387,8 @@ namespace Spine.Unity {
if (updateMode != UpdateMode.FullUpdate) return;
PrepareInstructionsAndRenderers();
+ if (OnInstructionsPrepared != null)
+ OnInstructionsPrepared(this.currentInstructions);
SetVerticesDirty(); // triggers Rebuild and avoids potential double-update in a single frame
}
@@ -390,12 +445,19 @@ namespace Spine.Unity {
public bool IsValid { get { return skeleton != null; } }
public delegate void SkeletonRendererDelegate (SkeletonGraphic skeletonGraphic);
+ public delegate void InstructionDelegate (SkeletonRendererInstruction instruction);
/// OnRebuild is raised after the Skeleton is successfully initialized.
public event SkeletonRendererDelegate OnRebuild;
- /// OnMeshAndMaterialsUpdated is at the end of LateUpdate after the Mesh and
- /// all materials have been updated.
+ /// OnInstructionsPrepared is raised at the end of LateUpdate after render instructions
+ /// are done, target renderers are prepared, and the mesh is ready to be generated.
+ public event InstructionDelegate OnInstructionsPrepared;
+
+ /// OnMeshAndMaterialsUpdated is raised at the end of Rebuild after the Mesh and
+ /// all materials have been updated. Note that some Unity API calls are not permitted to be issued from
+ /// Rebuild, so you may want to subscribe to instead
+ /// from where you can issue such preparation calls.
public event SkeletonRendererDelegate OnMeshAndMaterialsUpdated;
protected Spine.AnimationState state;
@@ -411,6 +473,12 @@ namespace Spine.Unity {
DoubleBuffered meshBuffers;
SkeletonRendererInstruction currentInstructions = new SkeletonRendererInstruction();
readonly ExposedList meshes = new ExposedList();
+ readonly ExposedList usedMaterials = new ExposedList();
+ readonly ExposedList usedTextures = new ExposedList();
+
+ public ExposedList MeshesMultipleCanvasRenderers { get { return meshes; } }
+ public ExposedList MaterialsMultipleCanvasRenderers { get { return usedMaterials; } }
+ public ExposedList TexturesMultipleCanvasRenderers { get { return usedTextures; } }
public Mesh GetLastMesh () {
return meshBuffers.GetCurrent().mesh;
@@ -513,6 +581,8 @@ namespace Spine.Unity {
for (int i = 0; i < canvasRenderers.Count; ++i)
canvasRenderers[i].Clear();
DestroyMeshes();
+ usedMaterials.Clear();
+ usedTextures.Clear();
DisposeMeshBuffers();
}
@@ -601,6 +671,7 @@ namespace Spine.Unity {
int submeshCount = currentInstructions.submeshInstructions.Count;
EnsureCanvasRendererCount(submeshCount);
EnsureMeshesCount(submeshCount);
+ EnsureUsedTexturesAndMaterialsCount(submeshCount);
EnsureSeparatorPartCount();
PrepareRendererGameObjects(currentInstructions);
}
@@ -618,6 +689,7 @@ namespace Spine.Unity {
if (!this.allowMultipleCanvasRenderers) {
UpdateMeshSingleCanvasRenderer(currentInstructions);
} else {
+ UpdateMaterialsMultipleCanvasRenderers(currentInstructions);
UpdateMeshMultipleCanvasRenderers(currentInstructions);
}
@@ -675,19 +747,67 @@ namespace Spine.Unity {
if (updateTriangles) meshGenerator.FillTriangles(mesh);
meshGenerator.FillLateVertexData(mesh);
- canvasRenderer.SetMesh(mesh);
smartMesh.instructionUsed.Set(currentInstructions);
+ if (assignMeshOverrideSingle != null)
+ assignMeshOverrideSingle(mesh, this.canvasRenderer.GetMaterial(), this.mainTexture);
+
+ bool assignAtCanvasRenderer = (assignMeshOverrideSingle == null || !disableMeshAssignmentOnOverride);
+ if (assignAtCanvasRenderer)
+ canvasRenderer.SetMesh(mesh);
+ else
+ canvasRenderer.SetMesh(null);
if (currentInstructions.submeshInstructions.Count > 0) {
var material = currentInstructions.submeshInstructions.Items[0].material;
if (material != null && baseTexture != material.mainTexture) {
baseTexture = material.mainTexture;
- if (overrideTexture == null)
+ if (overrideTexture == null && assignAtCanvasRenderer)
canvasRenderer.SetTexture(this.mainTexture);
}
}
+ }
- //this.UpdateMaterial(); // note: This would allocate memory.
+ protected void UpdateMaterialsMultipleCanvasRenderers (SkeletonRendererInstruction currentInstructions) {
+ int submeshCount = currentInstructions.submeshInstructions.Count;
+ bool useOriginalTextureAndMaterial = (customMaterialOverride.Count == 0 && customTextureOverride.Count == 0);
+
+ BlendModeMaterials blendModeMaterials = skeletonDataAsset.blendModeMaterials;
+ bool hasBlendModeMaterials = blendModeMaterials.RequiresBlendModeMaterials;
+
+ bool pmaVertexColors = meshGenerator.settings.pmaVertexColors;
+ Material[] usedMaterialItems = usedMaterials.Items;
+ Texture[] usedTextureItems = usedTextures.Items;
+ for (int i = 0; i < submeshCount; i++) {
+ var submeshInstructionItem = currentInstructions.submeshInstructions.Items[i];
+ var submeshMaterial = submeshInstructionItem.material;
+ if (useOriginalTextureAndMaterial) {
+ usedTextureItems[i] = submeshMaterial.mainTexture;
+ if (!hasBlendModeMaterials) {
+ usedMaterialItems[i] = this.materialForRendering;
+ } else {
+ BlendMode blendMode = blendModeMaterials.BlendModeForMaterial(submeshMaterial);
+ Material usedMaterial = this.materialForRendering;
+ if (blendMode == BlendMode.Additive && !pmaVertexColors && additiveMaterial) {
+ usedMaterial = additiveMaterial;
+ } else if (blendMode == BlendMode.Multiply && multiplyMaterial)
+ usedMaterial = multiplyMaterial;
+ else if (blendMode == BlendMode.Screen && screenMaterial)
+ usedMaterial = screenMaterial;
+ usedMaterialItems[i] = submeshGraphics[i].GetModifiedMaterial(usedMaterial);
+ }
+ } else {
+ var originalTexture = submeshMaterial.mainTexture;
+ Material usedMaterial;
+ Texture usedTexture;
+ if (!customMaterialOverride.TryGetValue(originalTexture, out usedMaterial))
+ usedMaterial = material;
+ if (!customTextureOverride.TryGetValue(originalTexture, out usedTexture))
+ usedTexture = originalTexture;
+
+ usedMaterialItems[i] = submeshGraphics[i].GetModifiedMaterial(usedMaterial);
+ usedTextureItems[i] = usedTexture;
+ }
+ }
}
protected void UpdateMeshMultipleCanvasRenderers (SkeletonRendererInstruction currentInstructions) {
@@ -705,6 +825,9 @@ namespace Spine.Unity {
bool mainCullTransparentMesh = this.canvasRenderer.cullTransparentMesh;
#endif
bool pmaVertexColors = meshGenerator.settings.pmaVertexColors;
+ Material[] usedMaterialItems = usedMaterials.Items;
+ Texture[] usedTextureItems = usedTextures.Items;
+ bool assignAtCanvasRenderer = (assignMeshOverrideSingle == null || !disableMeshAssignmentOnOverride);
for (int i = 0; i < submeshCount; i++) {
var submeshInstructionItem = currentInstructions.submeshInstructions.Items[i];
meshGenerator.Begin();
@@ -717,53 +840,31 @@ namespace Spine.Unity {
meshGenerator.FillTriangles(targetMesh);
meshGenerator.FillLateVertexData(targetMesh);
- var submeshMaterial = submeshInstructionItem.material;
var canvasRenderer = canvasRenderers[i];
- canvasRenderer.SetMesh(targetMesh);
- canvasRenderer.materialCount = 1;
+ if (assignMeshOverrideSingle == null || !disableMeshAssignmentOnOverride)
+ canvasRenderer.SetMesh(targetMesh);
+ else
+ canvasRenderer.SetMesh(null);
SkeletonSubmeshGraphic submeshGraphic = submeshGraphics[i];
- if (useOriginalTextureAndMaterial) {
- Texture usedTexture = submeshMaterial.mainTexture;
- if (!hasBlendModeMaterials)
- canvasRenderer.SetMaterial(this.materialForRendering, usedTexture);
- else {
- bool allowCullTransparentMesh = true;
- BlendMode blendMode = blendModeMaterials.BlendModeForMaterial(submeshMaterial);
- Material usedMaterial = this.materialForRendering;
- if (blendMode == BlendMode.Normal) {
- if (submeshInstructionItem.hasPMAAdditiveSlot)
- allowCullTransparentMesh = false;
- } else if (blendMode == BlendMode.Additive) {
- if (pmaVertexColors)
- allowCullTransparentMesh = false;
- else if (additiveMaterial)
- usedMaterial = additiveMaterial;
- } else if (blendMode == BlendMode.Multiply && multiplyMaterial)
- usedMaterial = multiplyMaterial;
- else if (blendMode == BlendMode.Screen && screenMaterial)
- usedMaterial = screenMaterial;
-
- usedMaterial = submeshGraphic.GetModifiedMaterial(usedMaterial);
- canvasRenderer.SetMaterial(usedMaterial, usedTexture);
-#if HAS_CULL_TRANSPARENT_MESH
- canvasRenderer.cullTransparentMesh = allowCullTransparentMesh ?
- mainCullTransparentMesh : false;
-#endif
+ if (useOriginalTextureAndMaterial && hasBlendModeMaterials) {
+ bool allowCullTransparentMesh = true;
+ BlendMode materialBlendMode = blendModeMaterials.BlendModeForMaterial(usedMaterialItems[i]);
+ if ((materialBlendMode == BlendMode.Normal && submeshInstructionItem.hasPMAAdditiveSlot) ||
+ (materialBlendMode == BlendMode.Additive && pmaVertexColors)) {
+ allowCullTransparentMesh = false;
}
- } else {
- var originalTexture = submeshMaterial.mainTexture;
- Material usedMaterial;
- Texture usedTexture;
- if (!customMaterialOverride.TryGetValue(originalTexture, out usedMaterial))
- usedMaterial = material;
- if (!customTextureOverride.TryGetValue(originalTexture, out usedTexture))
- usedTexture = originalTexture;
-
- usedMaterial = submeshGraphic.GetModifiedMaterial(usedMaterial);
- canvasRenderer.SetMaterial(usedMaterial, usedTexture);
+#if HAS_CULL_TRANSPARENT_MESH
+ canvasRenderer.cullTransparentMesh = allowCullTransparentMesh ?
+ mainCullTransparentMesh : false;
+#endif
}
+ canvasRenderer.materialCount = 1;
+ if (assignAtCanvasRenderer)
+ canvasRenderer.SetMaterial(usedMaterialItems[i], usedTextureItems[i]);
}
+ if (assignMeshOverrideMultiple != null)
+ assignMeshOverrideMultiple(submeshCount, meshesItems, usedMaterialItems, usedTextureItems);
}
protected void EnsureCanvasRendererCount (int targetCount) {
@@ -856,6 +957,16 @@ namespace Spine.Unity {
meshes.Add(SpineMesh.NewSkeletonMesh());
}
+ protected void EnsureUsedTexturesAndMaterialsCount (int targetCount) {
+ int oldCount = usedMaterials.Count;
+ usedMaterials.EnsureCapacity(targetCount);
+ usedTextures.EnsureCapacity(targetCount);
+ for (int i = oldCount; i < targetCount; i++) {
+ usedMaterials.Add(null);
+ usedTextures.Add(null);
+ }
+ }
+
protected void DestroyMeshes () {
foreach (var mesh in meshes) {
#if UNITY_EDITOR
diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs
new file mode 100644
index 000000000..1879e2d4b
--- /dev/null
+++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs
@@ -0,0 +1,71 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2022, 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.
+ *
+ * THE SPINE RUNTIMES ARE 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
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+using UnityEngine;
+
+namespace Spine.Unity {
+ public static class MathUtilities {
+ public static float InverseLerp (float a, float b, float value) {
+ return (value - a) / (b - a);
+ }
+
+ ///
+ /// Returns the linear interpolation ratio of a to b that value lies on.
+ /// This is the t value that fulfills value = lerp(a, b, t).
+ ///
+ public static Vector2 InverseLerp (Vector2 a, Vector2 b, Vector2 value) {
+ return new Vector2(
+ (value.x - a.x) / (b.x - a.x),
+ (value.y - a.y) / (b.y - a.y));
+ }
+
+ ///
+ /// Returns the linear interpolation ratio of a to b that value lies on.
+ /// This is the t value that fulfills value = lerp(a, b, t).
+ ///
+ public static Vector3 InverseLerp (Vector3 a, Vector3 b, Vector3 value) {
+ return new Vector3(
+ (value.x - a.x) / (b.x - a.x),
+ (value.y - a.y) / (b.y - a.y),
+ (value.z - a.z) / (b.z - a.z));
+ }
+
+ ///
+ /// Returns the linear interpolation ratio of a to b that value lies on.
+ /// This is the t value that fulfills value = lerp(a, b, t).
+ ///
+ public static Vector4 InverseLerp (Vector4 a, Vector4 b, Vector4 value) {
+ return new Vector4(
+ (value.x - a.x) / (b.x - a.x),
+ (value.y - a.y) / (b.y - a.y),
+ (value.z - a.z) / (b.z - a.z),
+ (value.w - a.w) / (b.w - a.w));
+ }
+ }
+}
diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs.meta b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs.meta
new file mode 100644
index 000000000..9e0d973d7
--- /dev/null
+++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MathUtilities.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ef2b5da9383ed474d895b702a9baf79e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: