소스 검색

Merge branch '3.8' into 4.0-beta

# Conflicts:
#	spine-ts/build/spine-all.js.map
#	spine-ts/build/spine-canvas.js.map
#	spine-ts/build/spine-core.js.map
#	spine-ts/build/spine-player.js.map
#	spine-ts/build/spine-threejs.js.map
#	spine-ts/build/spine-webgl.js.map
#	spine-ts/canvas/example/assets/spineboy-ess.json
#	spine-ts/canvas/example/assets/spineboy.png
#	spine-ts/player/example/assets/raptor-pma.png
#	spine-ts/player/example/assets/raptor-pro.json
#	spine-ts/player/example/assets/spineboy-pma.png
#	spine-ts/player/example/assets/spineboy-pro.skel
#	spine-ts/threejs/example/assets/raptor-pro.json
#	spine-ts/threejs/example/assets/raptor.png
#	spine-ts/webgl/example/assets/coin-pro.skel
#	spine-ts/webgl/example/assets/goblins-pro.skel
#	spine-ts/webgl/example/assets/mix-and-match-pma.atlas
#	spine-ts/webgl/example/assets/mix-and-match-pma.png
#	spine-ts/webgl/example/assets/mix-and-match-pro.skel
#	spine-ts/webgl/example/assets/owl-pma.png
#	spine-ts/webgl/example/assets/owl-pro.skel
#	spine-ts/webgl/example/assets/raptor-pma.png
#	spine-ts/webgl/example/assets/raptor-pro.skel
#	spine-ts/webgl/example/assets/spineboy-pma.png
#	spine-ts/webgl/example/assets/spineboy-pro.skel
#	spine-ts/webgl/example/assets/spineboy.png
#	spine-ts/webgl/example/assets/stretchyman-pro.skel
#	spine-ts/webgl/example/assets/tank-pma.atlas
#	spine-ts/webgl/example/assets/tank-pma.png
#	spine-ts/webgl/example/assets/tank-pro.skel
#	spine-ts/webgl/example/assets/vine-pro.skel
badlogic 4 년 전
부모
커밋
ae6eda01f7

+ 1 - 0
CHANGELOG.md

@@ -376,6 +376,7 @@
   * Added `BoundingBoxFollowerGraphic` component. This class is a counterpart of `BoundingBoxFollower` that can be used with `SkeletonGraphic`.
   * Added Inspector context menu functions `SkeletonRenderer - Add all BoundingBoxFollower GameObjects` and `SkeletonGraphic - Add all BoundingBoxFollowerGraphic GameObjects` that automatically generate bounding box follower GameObjects for every `BoundingBoxAttachment` for all skins of a skeleton.
   * `GetRemappedClone()` now provides an additional parameter `pivotShiftsMeshUVCoords` for `MeshAttachment` to prevent uv shifts at a non-central Sprite pivot. This parameter defaults to `true` to maintain previous behaviour.
+  * `SkeletonRenderer` components now provide an additional update mode `Only Event Timelines` at the `Update When Invisible` property. This mode saves additional timeline updates compared to update mode `Everything Except Mesh`.
 
 * **Changes of default values**
   * `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`.

+ 74 - 0
spine-csharp/src/AnimationState.cs

@@ -306,6 +306,43 @@ namespace Spine {
 			return applied;
 		}
 
+		/// <summary>Version of <see cref="Apply"/> only applying EventTimelines for lightweight off-screen updates.</summary>
+		// Note: This method is not part of the libgdx reference implementation.
+		public bool ApplyEventTimelinesOnly (Skeleton skeleton) {
+			if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null.");
+
+			var events = this.events;
+			bool applied = false;
+			var tracksItems = tracks.Items;
+			for (int i = 0, n = tracks.Count; i < n; i++) {
+				TrackEntry current = tracksItems[i];
+				if (current == null || current.delay > 0) continue;
+				applied = true;
+
+				// Apply mixing from entries first.
+				if (current.mixingFrom != null)
+					ApplyMixingFromEventTimelinesOnly(current, skeleton);
+
+				// Apply current entry.
+				float animationLast = current.animationLast, animationTime = current.AnimationTime;
+				int timelineCount = current.animation.timelines.Count;
+				var timelines = current.animation.timelines;
+				var timelinesItems = timelines.Items;
+				for (int ii = 0; ii < timelineCount; ii++) {
+					Timeline timeline = timelinesItems[ii];
+					if (timeline is EventTimeline)
+						timeline.Apply(skeleton, animationLast, animationTime, events, 1.0f, MixBlend.Setup, MixDirection.In);
+				}
+				QueueEvents(current, animationTime);
+				events.Clear(false);
+				current.nextAnimationLast = animationTime;
+				current.nextTrackLast = current.trackTime;
+			}
+
+			queue.Drain();
+			return applied;
+		}
+
 		private float ApplyMixingFrom (TrackEntry to, Skeleton skeleton, MixBlend blend) {
 			TrackEntry from = to.mixingFrom;
 			if (from.mixingFrom != null) ApplyMixingFrom(from, skeleton, blend);
@@ -398,6 +435,43 @@ namespace Spine {
 			return mix;
 		}
 
+		/// <summary>Version of <see cref="ApplyMixingFrom"/> only applying EventTimelines for lightweight off-screen updates.</summary>
+		// Note: This method is not part of the libgdx reference implementation.
+		private float ApplyMixingFromEventTimelinesOnly (TrackEntry to, Skeleton skeleton) {
+			TrackEntry from = to.mixingFrom;
+			if (from.mixingFrom != null) ApplyMixingFromEventTimelinesOnly(from, skeleton);
+
+			float mix;
+			if (to.mixDuration == 0) { // Single frame mix to undo mixingFrom changes.
+				mix = 1;
+			}
+			else {
+				mix = to.mixTime / to.mixDuration;
+				if (mix > 1) mix = 1;
+			}
+
+			var eventBuffer = mix < from.eventThreshold ? this.events : null;
+			if (eventBuffer == null)
+				return mix;
+
+			float animationLast = from.animationLast, animationTime = from.AnimationTime;
+			var timelines = from.animation.timelines;
+			int timelineCount = timelines.Count;
+			var timelinesItems = timelines.Items;
+			for (int i = 0; i < timelineCount; i++) {
+				var timeline = timelinesItems[i];
+				if (timeline is EventTimeline)
+					timeline.Apply(skeleton, animationLast, animationTime, eventBuffer, 0, MixBlend.Setup, MixDirection.Out);
+			}
+
+			if (to.mixDuration > 0) QueueEvents(from, animationTime);
+			this.events.Clear(false);
+			from.nextAnimationLast = animationTime;
+			from.nextTrackLast = from.trackTime;
+
+			return mix;
+		}
+
 		/// <summary> Applies the attachment timeline and sets <see cref="Slot.attachmentState"/>.</summary>
 		/// <param name="attachments">False when: 1) the attachment timeline is mixing out, 2) mix < attachmentThreshold, and 3) the timeline
 		/// is not the last timeline to set the slot's attachment. In that case the timeline is applied only so subsequent

+ 3 - 0
spine-csharp/src/Atlas.cs

@@ -58,6 +58,9 @@ namespace Spine {
 		}
 		#endregion
 
+		public List<AtlasRegion> Regions { get { return regions; } }
+		public List<AtlasPage> Pages { get { return pages; } }
+
 		#if !(IS_UNITY)
 		#if WINDOWS_STOREAPP
 		private async Task ReadFile(string path, TextureLoader textureLoader) {

+ 2 - 1
spine-ts/build/spine-all.d.ts

@@ -1868,7 +1868,8 @@ declare module spine.webgl {
 		canvas: HTMLCanvasElement | OffscreenCanvas;
 		gl: WebGLRenderingContext;
 		private restorables;
-		constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | OffscreenCanvas | WebGL2RenderingContext, contextConfig?: any);
+		constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | EventTarget | WebGL2RenderingContext, contextConfig?: any);
+		private setupCanvas;
 		addRestorable(restorable: Restorable): void;
 		removeRestorable(restorable: Restorable): void;
 	}

+ 18 - 16
spine-ts/build/spine-all.js

@@ -12192,30 +12192,32 @@ var spine;
 	(function (webgl) {
 		var ManagedWebGLRenderingContext = (function () {
 			function ManagedWebGLRenderingContext(canvasOrContext, contextConfig) {
-				var _this = this;
 				if (contextConfig === void 0) { contextConfig = { alpha: "true" }; }
 				this.restorables = new Array();
-				if (!((canvasOrContext instanceof WebGLRenderingContext) || (canvasOrContext instanceof WebGL2RenderingContext))) {
-					var canvas_1 = canvasOrContext;
-					this.gl = (canvas_1.getContext("webgl2", contextConfig) || canvas_1.getContext("webgl", contextConfig));
-					this.canvas = canvas_1;
-					canvas_1.addEventListener("webglcontextlost", function (e) {
-						var event = e;
-						if (e) {
-							e.preventDefault();
-						}
-					});
-					canvas_1.addEventListener("webglcontextrestored", function (e) {
-						for (var i = 0, n = _this.restorables.length; i < n; i++) {
-							_this.restorables[i].restore();
-						}
-					});
+				if (canvasOrContext instanceof HTMLCanvasElement || canvasOrContext instanceof EventTarget) {
+					this.setupCanvas(canvasOrContext, contextConfig);
 				}
 				else {
 					this.gl = canvasOrContext;
 					this.canvas = this.gl.canvas;
 				}
 			}
+			ManagedWebGLRenderingContext.prototype.setupCanvas = function (canvas, contextConfig) {
+				var _this = this;
+				this.gl = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
+				this.canvas = canvas;
+				canvas.addEventListener("webglcontextlost", function (e) {
+					var event = e;
+					if (e) {
+						e.preventDefault();
+					}
+				});
+				canvas.addEventListener("webglcontextrestored", function (e) {
+					for (var i = 0, n = _this.restorables.length; i < n; i++) {
+						_this.restorables[i].restore();
+					}
+				});
+			};
 			ManagedWebGLRenderingContext.prototype.addRestorable = function (restorable) {
 				this.restorables.push(restorable);
 			};

+ 2 - 1
spine-ts/build/spine-player.d.ts

@@ -1837,7 +1837,8 @@ declare module spine.webgl {
 		canvas: HTMLCanvasElement | OffscreenCanvas;
 		gl: WebGLRenderingContext;
 		private restorables;
-		constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | OffscreenCanvas | WebGL2RenderingContext, contextConfig?: any);
+		constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | EventTarget | WebGL2RenderingContext, contextConfig?: any);
+		private setupCanvas;
 		addRestorable(restorable: Restorable): void;
 		removeRestorable(restorable: Restorable): void;
 	}

+ 18 - 16
spine-ts/build/spine-player.js

@@ -11924,30 +11924,32 @@ var spine;
 	(function (webgl) {
 		var ManagedWebGLRenderingContext = (function () {
 			function ManagedWebGLRenderingContext(canvasOrContext, contextConfig) {
-				var _this = this;
 				if (contextConfig === void 0) { contextConfig = { alpha: "true" }; }
 				this.restorables = new Array();
-				if (!((canvasOrContext instanceof WebGLRenderingContext) || (canvasOrContext instanceof WebGL2RenderingContext))) {
-					var canvas = canvasOrContext;
-					this.gl = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
-					this.canvas = canvas;
-					canvas.addEventListener("webglcontextlost", function (e) {
-						var event = e;
-						if (e) {
-							e.preventDefault();
-						}
-					});
-					canvas.addEventListener("webglcontextrestored", function (e) {
-						for (var i = 0, n = _this.restorables.length; i < n; i++) {
-							_this.restorables[i].restore();
-						}
-					});
+				if (canvasOrContext instanceof HTMLCanvasElement || canvasOrContext instanceof EventTarget) {
+					this.setupCanvas(canvasOrContext, contextConfig);
 				}
 				else {
 					this.gl = canvasOrContext;
 					this.canvas = this.gl.canvas;
 				}
 			}
+			ManagedWebGLRenderingContext.prototype.setupCanvas = function (canvas, contextConfig) {
+				var _this = this;
+				this.gl = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
+				this.canvas = canvas;
+				canvas.addEventListener("webglcontextlost", function (e) {
+					var event = e;
+					if (e) {
+						e.preventDefault();
+					}
+				});
+				canvas.addEventListener("webglcontextrestored", function (e) {
+					for (var i = 0, n = _this.restorables.length; i < n; i++) {
+						_this.restorables[i].restore();
+					}
+				});
+			};
 			ManagedWebGLRenderingContext.prototype.addRestorable = function (restorable) {
 				this.restorables.push(restorable);
 			};

+ 2 - 1
spine-ts/build/spine-webgl.d.ts

@@ -1837,7 +1837,8 @@ declare module spine.webgl {
 		canvas: HTMLCanvasElement | OffscreenCanvas;
 		gl: WebGLRenderingContext;
 		private restorables;
-		constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | OffscreenCanvas | WebGL2RenderingContext, contextConfig?: any);
+		constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | EventTarget | WebGL2RenderingContext, contextConfig?: any);
+		private setupCanvas;
 		addRestorable(restorable: Restorable): void;
 		removeRestorable(restorable: Restorable): void;
 	}

+ 18 - 16
spine-ts/build/spine-webgl.js

@@ -11924,30 +11924,32 @@ var spine;
 	(function (webgl) {
 		var ManagedWebGLRenderingContext = (function () {
 			function ManagedWebGLRenderingContext(canvasOrContext, contextConfig) {
-				var _this = this;
 				if (contextConfig === void 0) { contextConfig = { alpha: "true" }; }
 				this.restorables = new Array();
-				if (!((canvasOrContext instanceof WebGLRenderingContext) || (canvasOrContext instanceof WebGL2RenderingContext))) {
-					var canvas = canvasOrContext;
-					this.gl = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
-					this.canvas = canvas;
-					canvas.addEventListener("webglcontextlost", function (e) {
-						var event = e;
-						if (e) {
-							e.preventDefault();
-						}
-					});
-					canvas.addEventListener("webglcontextrestored", function (e) {
-						for (var i = 0, n = _this.restorables.length; i < n; i++) {
-							_this.restorables[i].restore();
-						}
-					});
+				if (canvasOrContext instanceof HTMLCanvasElement || canvasOrContext instanceof EventTarget) {
+					this.setupCanvas(canvasOrContext, contextConfig);
 				}
 				else {
 					this.gl = canvasOrContext;
 					this.canvas = this.gl.canvas;
 				}
 			}
+			ManagedWebGLRenderingContext.prototype.setupCanvas = function (canvas, contextConfig) {
+				var _this = this;
+				this.gl = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
+				this.canvas = canvas;
+				canvas.addEventListener("webglcontextlost", function (e) {
+					var event = e;
+					if (e) {
+						e.preventDefault();
+					}
+				});
+				canvas.addEventListener("webglcontextrestored", function (e) {
+					for (var i = 0, n = _this.restorables.length; i < n; i++) {
+						_this.restorables[i].restore();
+					}
+				});
+			};
 			ManagedWebGLRenderingContext.prototype.addRestorable = function (restorable) {
 				this.restorables.push(restorable);
 			};

+ 20 - 17
spine-ts/webgl/src/WebGL.ts

@@ -33,29 +33,32 @@ module spine.webgl {
 		public gl: WebGLRenderingContext;
 		private restorables = new Array<Restorable>();
 
-		constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | OffscreenCanvas | WebGL2RenderingContext, contextConfig: any = { alpha: "true" }) {
-			if (!((canvasOrContext instanceof WebGLRenderingContext) || (canvasOrContext instanceof WebGL2RenderingContext))) {
-				let canvas = canvasOrContext;
-				this.gl = <WebGLRenderingContext> (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
-				this.canvas = canvas;
-				canvas.addEventListener("webglcontextlost", (e: any) => {
-					let event = <WebGLContextEvent>e;
-					if (e) {
-						e.preventDefault();
-					}
-				});
-
-				canvas.addEventListener("webglcontextrestored", (e: any) => {
-					for (let i = 0, n = this.restorables.length; i < n; i++) {
-						this.restorables[i].restore();
-					}
-				});
+		constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | EventTarget | WebGL2RenderingContext, contextConfig: any = { alpha: "true" }) {
+			if (canvasOrContext instanceof HTMLCanvasElement || canvasOrContext instanceof EventTarget) {
+				this.setupCanvas(canvasOrContext, contextConfig);
 			} else {
 				this.gl = canvasOrContext;
 				this.canvas = this.gl.canvas;
 			}
 		}
 
+		private setupCanvas(canvas: any, contextConfig: any) {
+			this.gl = <WebGLRenderingContext> (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig));
+			this.canvas = canvas;
+			canvas.addEventListener("webglcontextlost", (e: any) => {
+				let event = <WebGLContextEvent>e;
+				if (e) {
+					e.preventDefault();
+				}
+			});
+
+			canvas.addEventListener("webglcontextrestored", (e: any) => {
+				for (let i = 0, n = this.restorables.length; i < n; i++) {
+					this.restorables[i].restore();
+				}
+			});
+		}
+
 		addRestorable(restorable: Restorable) {
 			this.restorables.push(restorable);
 		}

+ 4 - 1
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs

@@ -213,7 +213,10 @@ namespace Spine.Unity {
 			if (_BeforeApply != null)
 				_BeforeApply(this);
 
-			state.Apply(skeleton);
+			if (updateMode != UpdateMode.OnlyEventTimelines)
+				state.Apply(skeleton);
+			else
+				state.ApplyEventTimelinesOnly(skeleton);
 
 			if (_UpdateLocal != null)
 				_UpdateLocal(this);

+ 6 - 3
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs

@@ -62,7 +62,7 @@ namespace Spine.Unity {
 
 		/// <summary>Update mode to optionally limit updates to e.g. only apply animations but not update the mesh.</summary>
 		public UpdateMode UpdateMode { get { return updateMode; } set { updateMode = value; } }
-		[SerializeField] protected UpdateMode updateMode = UpdateMode.FullUpdate;
+		protected UpdateMode updateMode = UpdateMode.FullUpdate;
 
 		/// <summary>Update mode used when the MeshRenderer becomes invisible
 		/// (when <c>OnBecameInvisible()</c> is called). Update mode is automatically
@@ -263,7 +263,10 @@ namespace Spine.Unity {
 			if (BeforeApply != null)
 				BeforeApply(this);
 
-			state.Apply(skeleton);
+			if (updateMode != UpdateMode.OnlyEventTimelines)
+				state.Apply(skeleton);
+			else
+				state.ApplyEventTimelinesOnly(skeleton);
 
 			if (UpdateLocal != null)
 				UpdateLocal(this);
@@ -283,7 +286,7 @@ namespace Spine.Unity {
 			// instantiation can happen from Update() after this component, leading to a missing Update() call.
 			if (!wasUpdatedAfterInit) Update(0);
 			if (freeze) return;
-			if (updateMode <= UpdateMode.EverythingExceptMesh) return;
+			if (updateMode != UpdateMode.FullUpdate) return;
 
 			UpdateMesh();
 		}

+ 2 - 2
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs

@@ -82,7 +82,7 @@ namespace Spine.Unity {
 
 		/// <summary>Update mode to optionally limit updates to e.g. only apply animations but not update the mesh.</summary>
 		public UpdateMode UpdateMode { get { return updateMode; } set { updateMode = value; } }
-		[SerializeField] protected UpdateMode updateMode = UpdateMode.FullUpdate;
+		protected UpdateMode updateMode = UpdateMode.FullUpdate;
 
 		/// <summary>Update mode used when the MeshRenderer becomes invisible
 		/// (when <c>OnBecameInvisible()</c> is called). Update mode is automatically
@@ -381,7 +381,7 @@ namespace Spine.Unity {
 			}
 			#endif
 
-			if (updateMode <= UpdateMode.EverythingExceptMesh) return;
+			if (updateMode != UpdateMode.FullUpdate) return;
 
 			#if SPINE_OPTIONAL_RENDEROVERRIDE
 			bool doMeshOverride = generateMeshOverride != null;

+ 4 - 2
spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs

@@ -31,8 +31,10 @@ namespace Spine.Unity {
 	public enum UpdateMode {
 		Nothing = 0,
 		OnlyAnimationStatus,
-		EverythingExceptMesh,
-		FullUpdate
+		OnlyEventTimelines = 4, // added as index 4 to keep scene behavior unchanged.
+		EverythingExceptMesh = 2,
+		FullUpdate,
+		//Reserved 4 for OnlyEventTimelines
 	};
 
 	public delegate void UpdateBonesDelegate (ISkeletonAnimation animated);

+ 15 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MaterialChecks.cs

@@ -79,6 +79,12 @@ namespace Spine.Unity {
 			+ "This will lead to incorrect rendering on some devices.\n\n"
 			+ "Please change the assigned Material to e.g. 'SkeletonGraphicDefault' or change the used shader to one of the 'Spine/SkeletonGraphic *' shaders.\n\n"
 			+ "Note that 'Spine/SkeletonGraphic *' shall still be used when using URP.\n";
+		public static readonly string kNoSkeletonGraphicTintBlackMaterialMessage =
+			"\nWarning: Only enable 'Canvas Group Tint Black' when using a 'SkeletonGraphic Tint Black' shader!\n"
+			+ "This will lead to incorrect rendering.\n\nPlease\n"
+			+ "a) disable 'Canvas Group Tint Black' under 'Advanced' or\n"
+			+ "b) use a 'SkeletonGraphic Tint Black' Material if you need Tint Black on a CanvasGroup.\n";
+
 		public static readonly string kTintBlackMessage =
 			"\nWarning: 'Advanced - Tint Black' required when using any 'Tint Black' shader!\n\nPlease\n"
 			+ "a) enable 'Tint Black' at the SkeletonRenderer/SkeletonGraphic component under 'Advanced' or\n"
@@ -143,6 +149,10 @@ namespace Spine.Unity {
 					isProblematic = true;
 					errorMessage += kCanvasTintBlackMessage;
 				}
+				if (settings.canvasGroupTintBlack == true && !IsSkeletonGraphicTintBlackMaterial(material)) {
+					isProblematic = true;
+					errorMessage += kNoSkeletonGraphicTintBlackMaterialMessage;
+				}
 				if (settings.canvasGroupTintBlack == true && !IsCanvasGroupCompatible(material)) {
 					isProblematic = true;
 					errorMessage += kCanvasGroupCompatibleMessage;
@@ -261,6 +271,11 @@ namespace Spine.Unity {
 			return material.shader.name.Contains("Spine") && !material.shader.name.Contains("SkeletonGraphic");
 		}
 
+		static bool IsSkeletonGraphicTintBlackMaterial (Material material) {
+			return material.shader.name.Contains("Spine") && material.shader.name.Contains("SkeletonGraphic")
+				&& material.shader.name.Contains("Black");
+		}
+
 		static bool AreShadowsDisabled (Material material) {
 			return material.IsKeywordEnabled("_RECEIVE_SHADOWS_OFF");
 		}

+ 23 - 10
spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-Sprite-ForwardPass-URP.hlsl

@@ -5,6 +5,10 @@
 
 #include "SpineCoreShaders/SpriteLighting.cginc"
 
+#if defined(_RIM_LIGHTING) || defined(_ADDITIONAL_LIGHTS) || defined(MAIN_LIGHT_CALCULATE_SHADOWS)
+	#define NEEDS_POSITION_WS
+#endif
+
 ////////////////////////////////////////
 // Vertex output struct
 //
@@ -26,10 +30,10 @@ struct VertexOutputLWRP
 #else
 	half3 normalWorld : TEXCOORD4;
 #endif
-#if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF)
+#if (defined(_MAIN_LIGHT_SHADOWS) || defined(MAIN_LIGHT_CALCULATE_SHADOWS)) && !defined(_RECEIVE_SHADOWS_OFF)
 	float4 shadowCoord : TEXCOORD7;
 #endif
-#if defined(_RIM_LIGHTING) || defined(_ADDITIONAL_LIGHTS)
+#if defined(NEEDS_POSITION_WS)
 	float4 positionWS : TEXCOORD8;
 #endif
 	UNITY_VERTEX_OUTPUT_STEREO
@@ -80,7 +84,7 @@ half4 LightweightFragmentPBRSimplified(InputData inputData, half4 texAlbedoAlpha
 	brdfData.specular *= albedo.a;
 
 #ifndef _MAIN_LIGHT_VERTEX
-#if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF)
+#if (defined(_MAIN_LIGHT_SHADOWS) || defined(MAIN_LIGHT_CALCULATE_SHADOWS)) && !defined(_RECEIVE_SHADOWS_OFF)
 	Light mainLight = GetMainLight(inputData.shadowCoord);
 #else
 	Light mainLight = GetMainLight();
@@ -115,7 +119,7 @@ half4 LightweightFragmentBlinnPhongSimplified(InputData inputData, half4 texDiff
 	half4 diffuse = texDiffuseAlpha * vertexColor;
 
 #ifndef _MAIN_LIGHT_VERTEX
-#if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF)
+#if (defined(_MAIN_LIGHT_SHADOWS) || defined(MAIN_LIGHT_CALCULATE_SHADOWS)) && !defined(_RECEIVE_SHADOWS_OFF)
 	Light mainLight = GetMainLight(inputData.shadowCoord);
 #else
 	Light mainLight = GetMainLight();
@@ -170,12 +174,12 @@ VertexOutputLWRP ForwardPassVertexSprite(VertexInput input)
 	backFaceSign = calculateBackfacingSign(positionWS.xyz);
 #endif
 	output.viewDirectionWS = GetCameraPositionWS() - positionWS;
+#if defined(NEEDS_POSITION_WS)
+	output.positionWS = float4(positionWS, 1);
+#endif
 
 #if defined(PER_PIXEL_LIGHTING)
 
-#if defined(_RIM_LIGHTING) || defined(_ADDITIONAL_LIGHTS)
-	output.positionWS = float4(positionWS, 1);
-#endif
 	half3 normalWS = calculateSpriteWorldNormal(input, -backFaceSign);
 	output.normalWorld.xyz = normalWS;
 
@@ -191,7 +195,8 @@ VertexOutputLWRP ForwardPassVertexSprite(VertexInput input)
 #endif // !PER_PIXEL_LIGHTING
 	output.fogFactorAndVertexLight.yzw = LightweightLightVertexSimplified(positionWS, normalWS);
 
-#if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF)
+
+#if (defined(_MAIN_LIGHT_SHADOWS) || defined(MAIN_LIGHT_CALCULATE_SHADOWS)) && !defined(_RECEIVE_SHADOWS_OFF)
 	VertexPositionInputs vertexInput;
 	vertexInput.positionWS = positionWS;
 	vertexInput.positionCS = output.pos;
@@ -216,8 +221,16 @@ half4 ForwardPassFragmentSprite(VertexOutputLWRP input) : SV_Target
 
 	// fill out InputData struct
 	InputData inputData;
-#if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF)
-	inputData.shadowCoord = input.shadowCoord;
+#if !defined(_RECEIVE_SHADOWS_OFF)
+	#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
+		inputData.shadowCoord = input.shadowCoord;
+	#elif defined(MAIN_LIGHT_CALCULATE_SHADOWS)
+		inputData.shadowCoord = TransformWorldToShadowCoord(input.positionWS);
+	#elif defined(_MAIN_LIGHT_SHADOWS)
+		inputData.shadowCoord = input.shadowCoord;
+	#else
+		inputData.shadowCoord = float4(0, 0, 0, 0);
+	#endif
 #endif
 
 	inputData.viewDirectionWS = input.viewDirectionWS;

+ 2 - 0
spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Spine-Sprite-URP.shader

@@ -100,6 +100,8 @@ Shader "Universal Render Pipeline/Spine/Sprite"
 			// -------------------------------------
 			// Universal Pipeline keywords
 			#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
+			#pragma multi_compile _ MAIN_LIGHT_CALCULATE_SHADOWS
+			#pragma multi_compile _ REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR
 			#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
 			#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
 			#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS