From a0882701866a0d9389a70dab47b696cd954363c8 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Tue, 12 Jan 2021 20:18:23 +0100 Subject: [PATCH 1/5] [ue4] Modifying parent materials (of the four blend modes) updates material instances again. Closes #1791. --- .../SpineSkeletonRendererComponent.cpp | 78 ++++++++----------- .../Public/SpineSkeletonRendererComponent.h | 30 +++---- 2 files changed, 49 insertions(+), 59 deletions(-) diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp index 133e5d980..0cb79597a 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp @@ -36,7 +36,7 @@ using namespace spine; -USpineSkeletonRendererComponent::USpineSkeletonRendererComponent (const FObjectInitializer& ObjectInitializer) +USpineSkeletonRendererComponent::USpineSkeletonRendererComponent (const FObjectInitializer& ObjectInitializer) : UProceduralMeshComponent(ObjectInitializer) { PrimaryComponentTick.bCanEverTick = true; bTickInEditor = true; @@ -44,16 +44,16 @@ USpineSkeletonRendererComponent::USpineSkeletonRendererComponent (const FObjectI static ConstructorHelpers::FObjectFinder NormalMaterialRef(TEXT("/SpinePlugin/SpineUnlitNormalMaterial")); NormalBlendMaterial = NormalMaterialRef.Object; - + static ConstructorHelpers::FObjectFinder AdditiveMaterialRef(TEXT("/SpinePlugin/SpineUnlitAdditiveMaterial")); AdditiveBlendMaterial = AdditiveMaterialRef.Object; - + static ConstructorHelpers::FObjectFinder MultiplyMaterialRef(TEXT("/SpinePlugin/SpineUnlitMultiplyMaterial")); MultiplyBlendMaterial = MultiplyMaterialRef.Object; - + static ConstructorHelpers::FObjectFinder ScreenMaterialRef(TEXT("/SpinePlugin/SpineUnlitScreenMaterial")); ScreenBlendMaterial = ScreenMaterialRef.Object; - + TextureParameterName = FName(TEXT("SpriteTexture")); worldVertices.ensureCapacity(1024 * 2); @@ -69,12 +69,12 @@ void USpineSkeletonRendererComponent::BeginPlay () { void USpineSkeletonRendererComponent::TickComponent (float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - + AActor* owner = GetOwner(); if (owner) { UClass* skeletonClass = USpineSkeletonComponent::StaticClass(); USpineSkeletonComponent* skeleton = Cast(owner->GetComponentByClass(skeletonClass)); - + UpdateRenderer(skeleton); } } @@ -126,41 +126,12 @@ void USpineSkeletonRendererComponent::UpdateRenderer(USpineSkeletonComponent* sk for (int i = 0; i < skeleton->Atlas->atlasPages.Num(); i++) { AtlasPage* currPage = skeleton->Atlas->GetAtlas()->getPages()[i]; - UTexture2D* texture = skeleton->Atlas->atlasPages[i]; - UTexture* oldTexture = nullptr; - UMaterialInstanceDynamic* current = atlasNormalBlendMaterials[i]; - if (!current || !current->GetTextureParameterValue(TextureParameterName, oldTexture) || oldTexture != texture) { - UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(NormalBlendMaterial, this); - material->SetTextureParameterValue(TextureParameterName, texture); - atlasNormalBlendMaterials[i] = material; - } - pageToNormalBlendMaterial.Add(currPage, atlasNormalBlendMaterials[i]); - - current = atlasAdditiveBlendMaterials[i]; - if (!current || !current->GetTextureParameterValue(TextureParameterName, oldTexture) || oldTexture != texture) { - UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(AdditiveBlendMaterial, this); - material->SetTextureParameterValue(TextureParameterName, texture); - atlasAdditiveBlendMaterials[i] = material; - } - pageToAdditiveBlendMaterial.Add(currPage, atlasAdditiveBlendMaterials[i]); - - current = atlasMultiplyBlendMaterials[i]; - if (!current || !current->GetTextureParameterValue(TextureParameterName, oldTexture) || oldTexture != texture) { - UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(MultiplyBlendMaterial, this); - material->SetTextureParameterValue(TextureParameterName, texture); - atlasMultiplyBlendMaterials[i] = material; - } - pageToMultiplyBlendMaterial.Add(currPage, atlasMultiplyBlendMaterials[i]); - - current = atlasScreenBlendMaterials[i]; - if (!current || !current->GetTextureParameterValue(TextureParameterName, oldTexture) || oldTexture != texture) { - UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(ScreenBlendMaterial, this); - material->SetTextureParameterValue(TextureParameterName, texture); - atlasScreenBlendMaterials[i] = material; - } - pageToScreenBlendMaterial.Add(currPage, atlasScreenBlendMaterials[i]); + UpdateRendererMaterial(currPage, texture, atlasNormalBlendMaterials[i], NormalBlendMaterial, pageToNormalBlendMaterial); + UpdateRendererMaterial(currPage, texture, atlasAdditiveBlendMaterials[i], AdditiveBlendMaterial, pageToAdditiveBlendMaterial); + UpdateRendererMaterial(currPage, texture, atlasMultiplyBlendMaterials[i], MultiplyBlendMaterial, pageToMultiplyBlendMaterial); + UpdateRendererMaterial(currPage, texture, atlasScreenBlendMaterials[i], ScreenBlendMaterial, pageToScreenBlendMaterial); } } UpdateMesh(skeleton->GetSkeleton()); @@ -170,6 +141,21 @@ void USpineSkeletonRendererComponent::UpdateRenderer(USpineSkeletonComponent* sk } } +void USpineSkeletonRendererComponent::UpdateRendererMaterial (spine::AtlasPage *CurrentPage, UTexture2D *Texture, + UMaterialInstanceDynamic *&CurrentInstance, UMaterialInterface *ParentMaterial, + TMap &PageToBlendMaterial) { + + UTexture* oldTexture = nullptr; + if (!CurrentInstance || !CurrentInstance->GetTextureParameterValue(TextureParameterName, oldTexture) || + oldTexture != Texture || CurrentInstance->Parent != ParentMaterial) { + + UMaterialInstanceDynamic* material = UMaterialInstanceDynamic::Create(ParentMaterial, this); + material->SetTextureParameterValue(TextureParameterName, Texture); + CurrentInstance = material; + } + PageToBlendMaterial.Add(CurrentPage, CurrentInstance); +} + void USpineSkeletonRendererComponent::Flush (int &Idx, TArray &Vertices, TArray &Indices, TArray &Normals, TArray &Uvs, TArray &Colors, TArray& Colors2, UMaterialInstanceDynamic* Material) { if (Vertices.Num() == 0) return; SetMaterial(Idx, Material); @@ -192,7 +178,7 @@ void USpineSkeletonRendererComponent::UpdateMesh(Skeleton* Skeleton) { TArray uvs; TArray colors; TArray darkColors; - + int idx = 0; int meshSection = 0; UMaterialInstanceDynamic* lastMaterial = nullptr; @@ -231,7 +217,7 @@ void USpineSkeletonRendererComponent::UpdateMesh(Skeleton* Skeleton) { clipper.clipEnd(*slot); continue; } - + if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { RegionAttachment* regionAttachment = (RegionAttachment*)attachment; @@ -258,7 +244,7 @@ void USpineSkeletonRendererComponent::UpdateMesh(Skeleton* Skeleton) { } attachmentColor.set(mesh->getColor()); - attachmentAtlasRegion = (AtlasRegion*)mesh->getRendererObject(); + attachmentAtlasRegion = (AtlasRegion*)mesh->getRendererObject(); mesh->computeWorldVertices(*slot, 0, mesh->getWorldVerticesLength(), *attachmentVertices, 0, 2); attachmentIndices = mesh->getTriangles().buffer(); attachmentUvs = mesh->getUVs().buffer(); @@ -339,7 +325,7 @@ void USpineSkeletonRendererComponent::UpdateMesh(Skeleton* Skeleton) { float dr = slot->hasDarkColor() ? slot->getDarkColor().r : 0.0f; float dg = slot->hasDarkColor() ? slot->getDarkColor().g : 0.0f; - float db = slot->hasDarkColor() ? slot->getDarkColor().b : 0.0f; + float db = slot->hasDarkColor() ? slot->getDarkColor().b : 0.0f; float* verticesPtr = attachmentVertices->buffer(); for (int j = 0; j < numVertices << 1; j += 2) { @@ -357,9 +343,9 @@ void USpineSkeletonRendererComponent::UpdateMesh(Skeleton* Skeleton) { idx += numVertices; depthOffset += this->DepthOffset; - clipper.clipEnd(*slot); + clipper.clipEnd(*slot); } - + Flush(meshSection, vertices, indices, normals, uvs, colors, darkColors, lastMaterial); clipper.clipEnd(); } diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonRendererComponent.h b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonRendererComponent.h index c37b43834..064ba67bc 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonRendererComponent.h +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonRendererComponent.h @@ -39,11 +39,11 @@ UCLASS(ClassGroup=(Spine), meta=(BlueprintSpawnableComponent)) class SPINEPLUGIN_API USpineSkeletonRendererComponent: public UProceduralMeshComponent { GENERATED_BODY() -public: +public: USpineSkeletonRendererComponent (const FObjectInitializer& ObjectInitializer); - + virtual void BeginPlay () override; - + virtual void TickComponent (float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; /* Updates this skeleton renderer using the provided skeleton animation component. */ @@ -52,13 +52,13 @@ public: // Material Instance parents UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite) UMaterialInterface* NormalBlendMaterial; - + UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite) UMaterialInterface* AdditiveBlendMaterial; - + UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite) UMaterialInterface* MultiplyBlendMaterial; - + UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite) UMaterialInterface* ScreenBlendMaterial; @@ -66,22 +66,22 @@ public: UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite) TArray atlasNormalBlendMaterials; TMap pageToNormalBlendMaterial; - + UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite) TArray atlasAdditiveBlendMaterials; TMap pageToAdditiveBlendMaterial; - + UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite) TArray atlasMultiplyBlendMaterials; TMap pageToMultiplyBlendMaterial; - + UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite) TArray atlasScreenBlendMaterials; TMap pageToScreenBlendMaterial; - + UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite) float DepthOffset = 0.1f; - + UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite) FName TextureParameterName; @@ -93,12 +93,16 @@ public: bool bCreateCollision; virtual void FinishDestroy() override; - + protected: + void UpdateRendererMaterial (spine::AtlasPage *CurrentPage, UTexture2D *Texture, + UMaterialInstanceDynamic *&CurrentInstance, UMaterialInterface *ParentMaterial, + TMap &PageToBlendMaterial); + void UpdateMesh (spine::Skeleton* Skeleton); void Flush (int &Idx, TArray &Vertices, TArray &Indices, TArray &Normals, TArray &Uvs, TArray &Colors, TArray &Colors2, UMaterialInstanceDynamic* Material); - + spine::Vector worldVertices; spine::SkeletonClipping clipper; }; From 9032040503be0ed110b7b0c8e6f4f664796caea4 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Thu, 14 Jan 2021 20:42:43 +0100 Subject: [PATCH 2/5] [ue4] Generated normals are now correctly being flipped at back-faces. Closes #1830. --- .../Private/SpineSkeletonRendererComponent.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp index 0cb79597a..395869350 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonRendererComponent.cpp @@ -332,14 +332,25 @@ void USpineSkeletonRendererComponent::UpdateMesh(Skeleton* Skeleton) { colors.Add(FColor(r, g, b, a)); darkColors.Add(FVector(dr, dg, db)); vertices.Add(FVector(verticesPtr[j], depthOffset, verticesPtr[j + 1])); - normals.Add(FVector(0, -1, 0)); uvs.Add(FVector2D(attachmentUvs[j], attachmentUvs[j + 1])); } + int firstIndex = indices.Num(); for (int j = 0; j < numIndices; j++) { indices.Add(idx + attachmentIndices[j]); } + FVector normal = FVector(0, -1, 0); + if (numVertices > 2 && + FVector::CrossProduct( + vertices[indices[firstIndex + 2]] - vertices[indices[firstIndex]], + vertices[indices[firstIndex + 1]] - vertices[indices[firstIndex]]).Y > 0.f) { + normal.Y = 1; + } + for (int j = 0; j < numVertices; j++) { + normals.Add(normal); + } + idx += numVertices; depthOffset += this->DepthOffset; From 1f76074e626e8a1288dfc5bb0f1046f2d889c159 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Mon, 18 Jan 2021 18:31:07 +0100 Subject: [PATCH 3/5] [unity] Added hint about RectTransform bounds to "Skeleton Graphic" example scene to prevent problems. --- .../Getting Started/6 SkeletonGraphic.unity | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spine-unity/Assets/Spine Examples/Getting Started/6 SkeletonGraphic.unity b/spine-unity/Assets/Spine Examples/Getting Started/6 SkeletonGraphic.unity index b35d13663..afc13f06c 100644 --- a/spine-unity/Assets/Spine Examples/Getting Started/6 SkeletonGraphic.unity +++ b/spine-unity/Assets/Spine Examples/Getting Started/6 SkeletonGraphic.unity @@ -733,7 +733,13 @@ MonoBehaviour: Enter PLAY Mode, and try scrolling up and down, or tap and drag the scroll - view.' + view. + + + The SkeletonGraphic''s RectTransform shall not be smaller than the + mesh, otherwise a RectMask2D will omit drawing the skeleton when the RectTransform + is completely outside. You can fit the RectTransform to the current pose + via the Inspector button Match RectTransform with Mesh.' --- !u!222 &774800196 CanvasRenderer: m_ObjectHideFlags: 0 From 60b52cb36a4ec97523a066abefaed358cde0beaa Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Tue, 19 Jan 2021 18:13:37 +0100 Subject: [PATCH 4/5] [unity] Fixed SkeletonRagdoll and SkeletonRagdoll2D behaving incorrectly when any Transforms are scaled. Closes #1831. --- .../SkeletonUtility Modules/SkeletonRagdoll.cs | 2 +- .../SkeletonUtility Modules/SkeletonRagdoll2D.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonRagdoll.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonRagdoll.cs index 6f7750ccd..bc5b3a862 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonRagdoll.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonRagdoll.cs @@ -334,7 +334,7 @@ namespace Spine.Unity.Examples { parentSpaceHelper.position = parentTransformWorldPosition; parentSpaceHelper.rotation = parentTransformWorldRotation; - parentSpaceHelper.localScale = parentTransform.localScale; + parentSpaceHelper.localScale = parentTransform.lossyScale; Vector3 boneWorldPosition = t.position; Vector3 right = parentSpaceHelper.InverseTransformDirection(t.right); diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonRagdoll2D.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonRagdoll2D.cs index cad12b8bc..b985f8553 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonRagdoll2D.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonRagdoll2D.cs @@ -351,7 +351,7 @@ namespace Spine.Unity.Examples { parentSpaceHelper.position = parentTransformWorldPosition; parentSpaceHelper.rotation = parentTransformWorldRotation; - parentSpaceHelper.localScale = parentTransform.localScale; + parentSpaceHelper.localScale = parentTransform.lossyScale; Vector3 boneWorldPosition = t.position; Vector3 right = parentSpaceHelper.InverseTransformDirection(t.right); From 110581abeacef1b4eacb7d8b88d76af3f046fa1c Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Thu, 21 Jan 2021 13:07:02 +0100 Subject: [PATCH 5/5] [unity] Changing AnimationName in the SkeletonAnimation Inspector now updates every time. Now also repaints GameView accordingly, for both animation and skin changes. Closes #1832. --- .../Components/SkeletonAnimationInspector.cs | 18 +++++++++--------- .../Components/SkeletonRendererInspector.cs | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonAnimationInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonAnimationInspector.cs index c87ee6262..ac91bd41f 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonAnimationInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonAnimationInspector.cs @@ -37,7 +37,6 @@ namespace Spine.Unity.Editor { [CanEditMultipleObjects] public class SkeletonAnimationInspector : SkeletonRendererInspector { protected SerializedProperty animationName, loop, timeScale, autoReset; - protected bool wasAnimationNameChanged; protected bool requireRepaint; readonly GUIContent LoopLabel = new GUIContent("Loop", "Whether or not .AnimationName should loop. This only applies to the initial animation specified in the inspector, or any subsequent Animations played through .AnimationName. Animations set through state.SetAnimation are unaffected."); readonly GUIContent TimeScaleLabel = new GUIContent("Time Scale", "The rate at which animations progress over time. 1 means normal speed. 0.5 means 50% speed."); @@ -55,16 +54,13 @@ namespace Spine.Unity.Editor { bool sameData = SpineInspectorUtility.TargetsUseSameData(serializedObject); foreach (var o in targets) - TrySetAnimation(o as SkeletonAnimation, multi); - wasAnimationNameChanged = false; + TrySetAnimation(o as SkeletonAnimation); EditorGUILayout.Space(); if (!sameData) { EditorGUILayout.DelayedTextField(animationName); } else { - EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(animationName); - wasAnimationNameChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update. } EditorGUILayout.PropertyField(loop, LoopLabel); EditorGUILayout.PropertyField(timeScale, TimeScaleLabel); @@ -76,20 +72,25 @@ namespace Spine.Unity.Editor { EditorGUILayout.Space(); SkeletonRootMotionParameter(); + serializedObject.ApplyModifiedProperties(); + if (!isInspectingPrefab) { if (requireRepaint) { - SceneView.RepaintAll(); + UnityEditorInternal.InternalEditorUtility.RepaintAllViews(); requireRepaint = false; } } } - protected void TrySetAnimation (SkeletonAnimation skeletonAnimation, bool multi) { + protected void TrySetAnimation (SkeletonAnimation skeletonAnimation) { if (skeletonAnimation == null) return; if (!skeletonAnimation.valid) return; + TrackEntry current = skeletonAnimation.AnimationState.GetCurrent(0); if (!isInspectingPrefab) { + string activeAnimation = (current != null) ? current.Animation.Name : null; + bool wasAnimationNameChanged = activeAnimation != animationName.stringValue; if (wasAnimationNameChanged) { var skeleton = skeletonAnimation.Skeleton; var state = skeletonAnimation.AnimationState; @@ -105,7 +106,7 @@ namespace Spine.Unity.Editor { if (animationToUse != null) { skeletonAnimation.AnimationState.SetAnimation(0, animationToUse, loop.boolValue); } - skeleton.UpdateWorldTransform(); + skeletonAnimation.Update(0); skeletonAnimation.LateUpdate(); requireRepaint = true; } else { @@ -118,7 +119,6 @@ namespace Spine.Unity.Editor { // Reflect animationName serialized property in the inspector even if SetAnimation API was used. if (Application.isPlaying) { - TrackEntry current = skeletonAnimation.AnimationState.GetCurrent(0); if (current != null) { if (skeletonAnimation.AnimationName != animationName.stringValue) animationName.stringValue = current.Animation.Name; diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs index 2bb52f43d..d66869120 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs @@ -530,7 +530,7 @@ namespace Spine.Unity.Editor { if (mismatchDetected) { mismatchDetected = false; - SceneView.RepaintAll(); + UnityEditorInternal.InternalEditorUtility.RepaintAllViews(); } } }