diff --git a/CHANGELOG.md b/CHANGELOG.md index 1182315d2..c231a8c96 100644 --- a/CHANGELOG.md +++ b/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`. diff --git a/spine-csharp/src/AnimationState.cs b/spine-csharp/src/AnimationState.cs index b093169f3..370cf9621 100644 --- a/spine-csharp/src/AnimationState.cs +++ b/spine-csharp/src/AnimationState.cs @@ -306,6 +306,43 @@ namespace Spine { return applied; } + /// Version of only applying EventTimelines for lightweight off-screen updates. + // 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; } + /// Version of only applying EventTimelines for lightweight off-screen updates. + // 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; + } + /// Applies the attachment timeline and sets . /// 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 diff --git a/spine-csharp/src/Atlas.cs b/spine-csharp/src/Atlas.cs index 3ef27c5d1..aeaf1050a 100644 --- a/spine-csharp/src/Atlas.cs +++ b/spine-csharp/src/Atlas.cs @@ -58,6 +58,9 @@ namespace Spine { } #endregion + public List Regions { get { return regions; } } + public List Pages { get { return pages; } } + #if !(IS_UNITY) #if WINDOWS_STOREAPP private async Task ReadFile(string path, TextureLoader textureLoader) { diff --git a/spine-ts/build/spine-all.d.ts b/spine-ts/build/spine-all.d.ts index f4e4bb9ec..6b2728474 100644 --- a/spine-ts/build/spine-all.d.ts +++ b/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; } diff --git a/spine-ts/build/spine-all.js b/spine-ts/build/spine-all.js index ef06f58b5..368cbde25 100644 --- a/spine-ts/build/spine-all.js +++ b/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); }; diff --git a/spine-ts/build/spine-player.d.ts b/spine-ts/build/spine-player.d.ts index 4c85ca1ce..624d68c1c 100644 --- a/spine-ts/build/spine-player.d.ts +++ b/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; } diff --git a/spine-ts/build/spine-player.js b/spine-ts/build/spine-player.js index 0aee5c815..c9b3eeacd 100644 --- a/spine-ts/build/spine-player.js +++ b/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); }; diff --git a/spine-ts/build/spine-webgl.d.ts b/spine-ts/build/spine-webgl.d.ts index 03789e0a1..75c17dff2 100644 --- a/spine-ts/build/spine-webgl.d.ts +++ b/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; } diff --git a/spine-ts/build/spine-webgl.js b/spine-ts/build/spine-webgl.js index 48a38af70..92093a4c3 100644 --- a/spine-ts/build/spine-webgl.js +++ b/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); }; diff --git a/spine-ts/webgl/src/WebGL.ts b/spine-ts/webgl/src/WebGL.ts index b62507ab9..3632fd205 100644 --- a/spine-ts/webgl/src/WebGL.ts +++ b/spine-ts/webgl/src/WebGL.ts @@ -33,29 +33,32 @@ module spine.webgl { public gl: WebGLRenderingContext; private restorables = new Array(); - constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext | OffscreenCanvas | WebGL2RenderingContext, contextConfig: any = { alpha: "true" }) { - if (!((canvasOrContext instanceof WebGLRenderingContext) || (canvasOrContext instanceof WebGL2RenderingContext))) { - let canvas = canvasOrContext; - this.gl = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig)); - this.canvas = canvas; - canvas.addEventListener("webglcontextlost", (e: any) => { - let event = 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 = (canvas.getContext("webgl2", contextConfig) || canvas.getContext("webgl", contextConfig)); + this.canvas = canvas; + canvas.addEventListener("webglcontextlost", (e: any) => { + let event = 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); } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs index 514eaa341..cfc5ddf29 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs +++ b/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); 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 429266bf1..457ba3124 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs @@ -62,7 +62,7 @@ namespace Spine.Unity { /// Update mode to optionally limit updates to e.g. only apply animations but not update the mesh. public UpdateMode UpdateMode { get { return updateMode; } set { updateMode = value; } } - [SerializeField] protected UpdateMode updateMode = UpdateMode.FullUpdate; + protected UpdateMode updateMode = UpdateMode.FullUpdate; /// Update mode used when the MeshRenderer becomes invisible /// (when OnBecameInvisible() 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(); } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs index 519bf334f..2fea2f7d4 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs @@ -82,7 +82,7 @@ namespace Spine.Unity { /// Update mode to optionally limit updates to e.g. only apply animations but not update the mesh. public UpdateMode UpdateMode { get { return updateMode; } set { updateMode = value; } } - [SerializeField] protected UpdateMode updateMode = UpdateMode.FullUpdate; + protected UpdateMode updateMode = UpdateMode.FullUpdate; /// Update mode used when the MeshRenderer becomes invisible /// (when OnBecameInvisible() 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; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs index 36e300ec9..90486e381 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs +++ b/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); diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MaterialChecks.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MaterialChecks.cs index 0cac07a37..d838a75c1 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/MaterialChecks.cs +++ b/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"); } diff --git a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-Sprite-ForwardPass-URP.hlsl b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-Sprite-ForwardPass-URP.hlsl index d4f7ccd7a..452389590 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Include/Spine-Sprite-ForwardPass-URP.hlsl +++ b/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; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Spine-Sprite-URP.shader b/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Spine-Sprite-URP.shader index 41c3f7aeb..f40e5098b 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.urp-shaders/Shaders/Spine-Sprite-URP.shader +++ b/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