From 4f85a27254782f39f2f358c03815348aa77fd244 Mon Sep 17 00:00:00 2001 From: wada Date: Thu, 31 Oct 2024 11:12:56 +0900 Subject: [PATCH] Update to Cubism 5 SDK for Unreal Engine R1 alpha3 --- .editorconfig | 32 ++ CHANGELOG.md | 9 + Live2DCubismSDK.uplugin | 2 +- README.ja.md | 2 +- README.md | 2 +- Shaders/Private/CubismMeshMask.usf | 4 +- .../Private/Model/CubismDrawableComponent.cpp | 30 +- .../Rendering/CubismDrawableSceneProxy.h | 159 ++++++--- .../Rendering/CubismMaskTextureComponent.cpp | 79 ++--- .../Rendering/CubismRenderingResource.h | 327 ++++++++++++++++++ .../Private/Rendering/CubismShaders.cpp | 150 ++++---- .../Private/Rendering/CubismShaders.h | 94 +++-- .../Rendering/CubismMaskTextureComponent.h | 1 + 13 files changed, 692 insertions(+), 199 deletions(-) create mode 100644 .editorconfig create mode 100644 Source/Live2DCubismFramework/Private/Rendering/CubismRenderingResource.h diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5211c11 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,32 @@ +# This setting refers to https://github.com/EpicGames/UnrealEngine/blob/release/.editorconfig . + +# top-most EditorConfig file +root = true + +# Baseline +[*] +charset = utf-8 +indent_style = tab +indent_size = 4 +tab_width = 4 +trim_trailing_whitespace = false +max_line_length = 150 + +# ReSharper properties +resharper_cpp_keep_user_linebreaks = false +resharper_cpp_wrap_lines = false +resharper_cpp_wrap_before_colon = true +resharper_cpp_line_break_before_comma_in_member_initializer_lists = true + +# MSBuild +[*.{csproj,proj,projitems,shproj,fsproj,target,props}] +indent_style = space +indent_size = 2 + +# XML config files +[*.{config,nuspec,resx,natvis}] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fa348f..f3243fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [5-r.1-alpha.3] - 2024-10-31 + +### Changed + +* Optimize mask texture rendering. +* Optimize model mesh rendering. + + ## [5-r.1-alpha.2] - 2024-09-26 ### Added @@ -28,4 +36,5 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * New released! +[5-r.1-alpha.3]: https://github.com/Live2D/CubismUnrealEngineComponents/compare/5-r.1-alpha.2...5-r.1-alpha.3 [5-r.1-alpha.2]: https://github.com/Live2D/CubismUnrealEngineComponents/compare/5-r.1-alpha.1...5-r.1-alpha.2 diff --git a/Live2DCubismSDK.uplugin b/Live2DCubismSDK.uplugin index 05371e6..b76e36c 100644 --- a/Live2DCubismSDK.uplugin +++ b/Live2DCubismSDK.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, "Version": 1, - "VersionName": "5-r.1-alpha.2", + "VersionName": "5-r.1-alpha.3", "FriendlyName": "Live2DCubismSDK", "Description": "Live2D Cubism SDK for Unreal Engine Components", "Category": "Other", diff --git a/README.ja.md b/README.ja.md index a950676..4ff66ce 100644 --- a/README.ja.md +++ b/README.ja.md @@ -70,7 +70,7 @@ Cubismファイルをuassetファイルに変換する機能は `./Source/Live2D | ライブラリ / ツール | バージョン | | --- | --- | -| Visual Studio 2022 | 17.11.4 | +| Visual Studio 2022 | 17.11.5 | | Windows SDK | 10.0.22621.0 | ## テスト済みの環境 diff --git a/README.md b/README.md index ca6367a..3cc02b0 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ Resources like shaders and other assets are located in `./Content/Materials`. | Library / Tool | Version | | --- | --- | -| Visual Studio 2022 | 17.11.4 | +| Visual Studio 2022 | 17.11.5 | | Windows SDK | 10.0.22621.0 | ## Tested environment diff --git a/Shaders/Private/CubismMeshMask.usf b/Shaders/Private/CubismMeshMask.usf index 3d1dd1b..988243c 100644 --- a/Shaders/Private/CubismMeshMask.usf +++ b/Shaders/Private/CubismMeshMask.usf @@ -3,11 +3,11 @@ float4 Offset; void MainVS( - in float4 InPosition : ATTRIBUTE0, in float2 InUV : ATTRIBUTE2, + in float2 InPosition : ATTRIBUTE0, in float2 InUV : ATTRIBUTE1, out float4 OutPosition : SV_POSITION, out float2 OutUV : TEXCOORD0 ) { - OutPosition = InPosition; + OutPosition = float4(InPosition.xy, 0.0, 1.0); OutPosition.xy += Offset.xy; OutPosition.xy *= Offset.z; diff --git a/Source/Live2DCubismFramework/Private/Model/CubismDrawableComponent.cpp b/Source/Live2DCubismFramework/Private/Model/CubismDrawableComponent.cpp index 2216d10..b6f02eb 100644 --- a/Source/Live2DCubismFramework/Private/Model/CubismDrawableComponent.cpp +++ b/Source/Live2DCubismFramework/Private/Model/CubismDrawableComponent.cpp @@ -264,27 +264,24 @@ void UCubismDrawableComponent::SendRenderDynamicData_Concurrent() FCubismDrawableDynamicMeshData NewDynamicData; NewDynamicData.Index = Index; - NewDynamicData.Indices.Append(VertexIndices); for (const FVector2D& LocalPosition : GetVertexPositions()) { NewDynamicData.Positions.Add(FVector3f(ToGlobalPosition(LocalPosition))); } - for (const FVector2D& Uv : GetVertexUvs()) + for (const FVector2D& UV : GetVertexUvs()) { - NewDynamicData.UVs.Add(FVector2f(Uv)); + NewDynamicData.UVs.Add(FVector2f(UV)); } - NewDynamicData.Color = BaseColor.ToRGBE(); - NewDynamicData.Color.A *= Opacity; - + NewDynamicData.Indices.Append(VertexIndices); NewDynamicData.bTwoSided = bTwoSided; ENQUEUE_RENDER_COMMAND(DrawableUpdateDynamicData)( [DrawableProxy, NewDynamicData](FRHICommandListImmediate& RHICommandList) { - DrawableProxy->DynamicData = NewDynamicData; + DrawableProxy->UpdateDynamicData(NewDynamicData); } ); } @@ -357,6 +354,23 @@ FBoxSphereBounds UCubismDrawableComponent::CalcBounds(const FTransform& LocalToW //~ Begin UPrimitiveComponent Interface FPrimitiveSceneProxy* UCubismDrawableComponent::CreateSceneProxy() { - return new FCubismDrawableSceneProxy(this); + FCubismDrawableDynamicMeshData DynamicData; + + DynamicData.Index = Index; + + for (const FVector2D& LocalPosition : GetVertexPositions()) + { + DynamicData.Positions.Add(FVector3f(ToGlobalPosition(LocalPosition))); + } + + for (const FVector2D& UV : GetVertexUvs()) + { + DynamicData.UVs.Add(FVector2f(UV)); + } + + DynamicData.Indices.Append(VertexIndices); + DynamicData.bTwoSided = bTwoSided; + + return new FCubismDrawableSceneProxy(this, DynamicData); } //~ End UPrimitiveComponent Interface diff --git a/Source/Live2DCubismFramework/Private/Rendering/CubismDrawableSceneProxy.h b/Source/Live2DCubismFramework/Private/Rendering/CubismDrawableSceneProxy.h index 817b931..021173e 100644 --- a/Source/Live2DCubismFramework/Private/Rendering/CubismDrawableSceneProxy.h +++ b/Source/Live2DCubismFramework/Private/Rendering/CubismDrawableSceneProxy.h @@ -8,25 +8,7 @@ #pragma once -#include "PrimitiveSceneProxy.h" -#include "DynamicMeshBuilder.h" -#include "Materials/Material.h" -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 2 -#include "Materials/MaterialRenderProxy.h" -#endif - -/** - * Dynamic mesh data for a drawable. - */ -struct FCubismDrawableDynamicMeshData -{ - int32 Index; - TArray Indices; - FColor Color; - TArray Positions; - TArray UVs; - bool bTwoSided; -}; +#include "CubismRenderingResource.h" /** * A representation of a UCubismDrawableComponent on the rendering thread. @@ -34,14 +16,69 @@ struct FCubismDrawableDynamicMeshData class FCubismDrawableSceneProxy : public FPrimitiveSceneProxy { public: - FCubismDrawableSceneProxy(const TObjectPtr& Drawable) + FCubismDrawableSceneProxy(const TObjectPtr& Drawable, FCubismDrawableDynamicMeshData InDynamicData) : FPrimitiveSceneProxy(Drawable) + , DynamicData(InDynamicData) , MaterialInstance(Drawable->GetMaterial(0)) , MaterialRelevance(Drawable->GetMaterialRelevance(GetScene().GetFeatureLevel())) + , VertexBuffer(nullptr) + , IndexBuffer(nullptr) + , VertexFactory(nullptr) { + ENQUEUE_RENDER_COMMAND(InitCubismDrawableSceneProxy)( + [this](FRHICommandListImmediate& RHICmdList) + { + if (!VertexBuffer) + { + VertexBuffer = new FCubismDrawableVertexBuffer(DynamicData); + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + VertexBuffer->InitResource(RHICmdList); + #else + VertexBuffer->InitResource(); + #endif + } + + if (!IndexBuffer) + { + IndexBuffer = new FCubismDrawableIndexBuffer(DynamicData); + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + IndexBuffer->InitResource(RHICmdList); + #else + IndexBuffer->InitResource(); + #endif + } + + if (!VertexFactory) + { + VertexFactory = new FCubismDrawableVertexFactory(GetScene().GetFeatureLevel(), VertexBuffer); + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + VertexFactory->InitResource(RHICmdList); + #else + VertexFactory->InitResource(); + #endif + } + } + ); } - virtual ~FCubismDrawableSceneProxy() { } + virtual ~FCubismDrawableSceneProxy() + { + if (VertexFactory) + { + VertexFactory->ReleaseResource(); + delete VertexFactory; + } + if (VertexBuffer) + { + VertexBuffer->ReleaseResource(); + delete VertexBuffer; + } + if (IndexBuffer) + { + IndexBuffer->ReleaseResource(); + delete IndexBuffer; + } + } SIZE_T GetTypeHash() const override { @@ -56,9 +93,14 @@ class FCubismDrawableSceneProxy : public FPrimitiveSceneProxy FMeshElementCollector& Collector ) const override { + if (DynamicData.Positions.Num() == 0) + { + return; + } + const bool bWireframe = AllowDebugViewmodes() && ViewFamily.EngineShowFlags.Wireframe; - FMaterialRenderProxy* MaterialProxy = nullptr; + FMaterialRenderProxy* MaterialRenderProxy = nullptr; if (bWireframe) { FColoredMaterialRenderProxy* WireframeMaterialInstance = new FColoredMaterialRenderProxy( @@ -67,24 +109,11 @@ class FCubismDrawableSceneProxy : public FPrimitiveSceneProxy ); Collector.RegisterOneFrameMaterialProxy(WireframeMaterialInstance); - MaterialProxy = WireframeMaterialInstance; + MaterialRenderProxy = WireframeMaterialInstance; } else { - MaterialProxy = MaterialInstance->GetRenderProxy(); - } - - TArray Vertices; - for (int32 i = 0; i < DynamicData.Positions.Num(); i++) - { - FDynamicMeshVertex Vertex; - - Vertex.SetTangents(FVector3f(1.0f,0.0f,0.0f), FVector3f(0.0f,1.0f,0.0f), FVector3f(0.0f,0.0f,1.0f)); - Vertex.Color = DynamicData.Color; - Vertex.Position = DynamicData.Positions[i]; - Vertex.TextureCoordinate[0] = DynamicData.UVs[i]; - - Vertices.Add(Vertex); + MaterialRenderProxy = MaterialInstance->GetRenderProxy(); } for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) @@ -93,18 +122,32 @@ class FCubismDrawableSceneProxy : public FPrimitiveSceneProxy { const FSceneView* View = Views[ViewIndex]; - FDynamicMeshBuilder Builder(View->GetFeatureLevel()); - Builder.AddVertices(Vertices); - Builder.AddTriangles(DynamicData.Indices); - Builder.GetMesh( - GetLocalToWorld(), - MaterialProxy, - SDPG_World, - DynamicData.bTwoSided, - false, - ViewIndex, - Collector - ); + FMeshBatch& Mesh = Collector.AllocateMesh(); + Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative(); + Mesh.bDisableBackfaceCulling = DynamicData.bTwoSided; + Mesh.Type = PT_TriangleList; + + Mesh.VertexFactory = VertexFactory; + Mesh.MaterialRenderProxy = MaterialRenderProxy; + + FMeshBatchElement& BatchElement = Mesh.Elements[0]; + + FDynamicPrimitiveUniformBuffer& DynamicPrimitiveUniformBuffer = Collector.AllocateOneFrameResource(); + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 4 + DynamicPrimitiveUniformBuffer.Set(Collector.GetRHICommandList(), GetLocalToWorld(), GetLocalToWorld(), GetBounds(), GetLocalBounds(), false, false, AlwaysHasVelocity()); + #else + DynamicPrimitiveUniformBuffer.Set(GetLocalToWorld(), GetLocalToWorld(), GetBounds(), GetLocalBounds(), false, false, AlwaysHasVelocity()); + #endif + BatchElement.PrimitiveUniformBufferResource = &DynamicPrimitiveUniformBuffer.UniformBuffer; + + BatchElement.IndexBuffer = IndexBuffer; + + BatchElement.FirstIndex = 0; + BatchElement.NumPrimitives = IndexBuffer->Indices.Num() / 3; + BatchElement.MinVertexIndex = 0; + BatchElement.MaxVertexIndex = VertexBuffer->Positions.Num() - 1; + + Collector.AddMesh(ViewIndex, Mesh); } } } @@ -126,6 +169,19 @@ class FCubismDrawableSceneProxy : public FPrimitiveSceneProxy virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); } + void UpdateDynamicData(const FCubismDrawableDynamicMeshData& NewDynamicData) + { + DynamicData = NewDynamicData; + if (VertexBuffer) + { + VertexBuffer->UpdateBuffer(DynamicData.Positions, DynamicData.UVs); + } + if (IndexBuffer) + { + IndexBuffer->UpdateBuffer(DynamicData.Indices); + } + } + public: /** Dynamic mesh data for the drawable. */ FCubismDrawableDynamicMeshData DynamicData; @@ -136,4 +192,9 @@ class FCubismDrawableSceneProxy : public FPrimitiveSceneProxy /** The material relevance for the drawable. */ FMaterialRelevance MaterialRelevance; + + /** Dynamic rendering resources */ + mutable FCubismDrawableVertexBuffer* VertexBuffer; + mutable FCubismDrawableIndexBuffer* IndexBuffer; + mutable FCubismDrawableVertexFactory* VertexFactory; }; diff --git a/Source/Live2DCubismFramework/Private/Rendering/CubismMaskTextureComponent.cpp b/Source/Live2DCubismFramework/Private/Rendering/CubismMaskTextureComponent.cpp index f786071..5035143 100644 --- a/Source/Live2DCubismFramework/Private/Rendering/CubismMaskTextureComponent.cpp +++ b/Source/Live2DCubismFramework/Private/Rendering/CubismMaskTextureComponent.cpp @@ -11,11 +11,7 @@ #include "Model/CubismDrawableComponent.h" #include "Rendering/CubismRendererComponent.h" #include "Rendering/CubismMaskJunction.h" -#include "Rendering/CubismShaders.h" -#include "Engine/Canvas.h" #include "Engine/TextureRenderTarget2D.h" -#include "Kismet/KismetRenderingLibrary.h" -#include "ClearQuad.h" #include "CubismLog.h" #include @@ -238,8 +234,6 @@ void UCubismMaskTextureComponent::TickComponent(float DeltaTime, ELevelTick Tick bDirty = false; } - UWorld* World = GetWorld(); - for (const TObjectPtr& RenderTarget : RenderTargets) { if (!IsValid(RenderTarget)) @@ -247,27 +241,7 @@ void UCubismMaskTextureComponent::TickComponent(float DeltaTime, ELevelTick Tick continue; } - // Clear the render target. - FTextureRenderTargetResource* RenderTargetResource = RenderTarget->GameThread_GetRenderTargetResource(); - ENQUEUE_RENDER_COMMAND(ClearRTCommand)( - [RenderTargetResource](FRHICommandList& RHICmdList) - { - FRHIRenderPassInfo RPInfo(RenderTargetResource->GetRenderTargetTexture(), ERenderTargetActions::DontLoad_Store); - RHICmdList.Transition(FRHITransitionInfo(RenderTargetResource->GetRenderTargetTexture(), ERHIAccess::Unknown, ERHIAccess::RTV)); - RHICmdList.BeginRenderPass(RPInfo, TEXT("ClearRT")); - DrawClearQuad(RHICmdList, FLinearColor::Transparent); - RHICmdList.EndRenderPass(); - - RHICmdList.Transition(FRHITransitionInfo(RenderTargetResource->GetRenderTargetTexture(), ERHIAccess::RTV, ERHIAccess::SRVMask)); - } - ); - - UCanvas* Canvas; - FVector2D CanvasSize; - FDrawToRenderTargetContext Context; - - // Draw a new mask to the render target. - UKismetRenderingLibrary::BeginDrawCanvasToRenderTarget(World, RenderTarget, Canvas, CanvasSize, Context); + TArray MaskDrawInfos; for (const TObjectPtr& ModelActor : Models) { @@ -301,42 +275,43 @@ void UCubismMaskTextureComponent::TickComponent(float DeltaTime, ELevelTick Tick continue; } - TArray Tris; + const TArray& Indices = MaskDrawable->GetVertexIndices(); + const TArray& Positions = MaskDrawable->GetVertexPositions(); + const TArray& UVs = MaskDrawable->GetVertexUvs(); - const TArray Indices = MaskDrawable->GetVertexIndices(); - const TArray Positions = MaskDrawable->GetVertexPositions(); - const TArray Uvs = MaskDrawable->GetVertexUvs(); + FMaskDrawInfo DrawInfo; - // Collect the vertices of the drawable that make up the mask. - for (int32 i = 0; i < Indices.Num(); i += 3) + for (int32 i = 0; i < Indices.Num(); ++i) { - const int32 Idx0 = Indices[i ]; - const int32 Idx1 = Indices[i+1]; - const int32 Idx2 = Indices[i+2]; - - FCanvasUVTri Tri; - - Tri.V0_Pos = Positions[Idx0]; - Tri.V1_Pos = Positions[Idx1]; - Tri.V2_Pos = Positions[Idx2]; - - Tri.V0_UV = Uvs[Idx0]; - Tri.V1_UV = Uvs[Idx1]; - Tri.V2_UV = Uvs[Idx2]; - - Tris.Add(Tri); + DrawInfo.Indices.Add((uint16)Indices[i]); } + for (int32 i = 0; i < Positions.Num(); ++i) + { + FCubismMeshMaskVertex Vertex; - FCanvasTriangleItem TriangleItem(Tris, Texture->GetResource()); + Vertex.Position = (FVector2f)Positions[i]; + Vertex.UV = (FVector2f)UVs[i]; - TriangleItem.BatchedElementParameters = new FCubismMaskBatchedElementParameters(Junction->Offset, Junction->Channel, Texture->GetResource()); + DrawInfo.Vertices.Add(Vertex); + } + DrawInfo.Offset = Junction->Offset; + DrawInfo.Channel = Junction->Channel; + DrawInfo.MainTexture = Texture->GetResource(); - Canvas->DrawItem(TriangleItem); + MaskDrawInfos.Add(DrawInfo); } } } - UKismetRenderingLibrary::EndDrawCanvasToRenderTarget(World, Context); + FTextureRenderTargetResource* RenderTargetResource = RenderTarget->GameThread_GetRenderTargetResource(); + + // Draw the mask to the render target. + ENQUEUE_RENDER_COMMAND(DrawMaskCommand)( + [this, RenderTargetResource, MaskDrawInfos](FRHICommandList& RHICmdList) + { + DrawMask_RenderThread(RHICmdList, RenderTargetResource, MaskDrawInfos); + } + ); } } // End of UActorComponent interface diff --git a/Source/Live2DCubismFramework/Private/Rendering/CubismRenderingResource.h b/Source/Live2DCubismFramework/Private/Rendering/CubismRenderingResource.h new file mode 100644 index 0000000..a6daeec --- /dev/null +++ b/Source/Live2DCubismFramework/Private/Rendering/CubismRenderingResource.h @@ -0,0 +1,327 @@ +/** + * Copyright(c) Live2D Inc. All rights reserved. + * + * Use of this source code is governed by the Live2D Open Software license + * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. + */ + + +#pragma once + +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 2 +#include "Materials/MaterialRenderProxy.h" +#include "DataDrivenShaderPlatformInfo.h" +#else +#include "ShaderParameterStruct.h" +#endif +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 +#include "PrimitiveUniformShaderParametersBuilder.h" +#else +#include "ResourcePool.h" +#endif + +/** + * Dynamic mesh data for a drawable. + */ +struct FCubismDrawableDynamicMeshData +{ + int32 Index; + TArray Positions; + TArray UVs; + TArray Indices; + bool bTwoSided; +}; + +/** + * Vertex buffer for a drawable. + */ +class FCubismDrawableVertexBuffer : public FRenderResource +{ +public: + FCubismDrawableVertexBuffer(const FCubismDrawableDynamicMeshData& DynamicData) + : Positions(DynamicData.Positions) + , UVs(DynamicData.UVs) + { } + + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + virtual void InitRHI(FRHICommandListBase& RHICmdList) override + #else + virtual void InitRHI() override + #endif + { + TRACE_CPUPROFILER_EVENT_SCOPE(FCubismDrawableVertexBuffer::InitRHI) + + // Initialize Position Buffer + { + const uint32 SizeInBytes = sizeof(FVector3f) * Positions.Num(); + + FRHIResourceCreateInfo PositionVertexBufferInfo(TEXT("PositionVertexBuffer")); + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + PositionBuffer.VertexBufferRHI = RHICmdList.CreateVertexBuffer(SizeInBytes, BUF_Volatile, PositionVertexBufferInfo); + void* PositionBufferData = RHICmdList.LockBuffer(PositionBuffer.VertexBufferRHI, 0, SizeInBytes, RLM_WriteOnly); + FMemory::Memcpy(PositionBufferData, Positions.GetData(), SizeInBytes); + RHICmdList.UnlockBuffer(PositionBuffer.VertexBufferRHI); + #else + PositionBuffer.VertexBufferRHI = RHICreateVertexBuffer(SizeInBytes, BUF_Volatile, PositionVertexBufferInfo); + void* PositionBufferData = RHILockBuffer(PositionBuffer.VertexBufferRHI, 0, SizeInBytes, RLM_WriteOnly); + FMemory::Memcpy(PositionBufferData, Positions.GetData(), SizeInBytes); + RHIUnlockBuffer(PositionBuffer.VertexBufferRHI); + #endif + } + + // Initialize UV Buffer + { + const uint32 SizeInBytes = sizeof(FVector2f) * UVs.Num(); + + FRHIResourceCreateInfo UVVertexBufferInfo(TEXT("UVVertexBuffer")); + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + UVBuffer.VertexBufferRHI = RHICmdList.CreateVertexBuffer(SizeInBytes, BUF_Volatile, UVVertexBufferInfo); + void* UVBufferData = RHICmdList.LockBuffer(UVBuffer.VertexBufferRHI, 0, SizeInBytes, RLM_WriteOnly); + FMemory::Memcpy(UVBufferData, UVs.GetData(), SizeInBytes); + RHICmdList.UnlockBuffer(UVBuffer.VertexBufferRHI); + #else + UVBuffer.VertexBufferRHI = RHICreateVertexBuffer(SizeInBytes, BUF_Volatile, UVVertexBufferInfo); + void* UVBufferData = RHILockBuffer(UVBuffer.VertexBufferRHI, 0, SizeInBytes, RLM_WriteOnly); + FMemory::Memcpy(UVBufferData, UVs.GetData(), SizeInBytes); + RHIUnlockBuffer(UVBuffer.VertexBufferRHI); + #endif + } + + // Initialize Tangent Buffer (unused) + { + const uint32 SizeInBytes = 2 * sizeof(FPackedNormal) * Positions.Num(); + + FRHIResourceCreateInfo TangentVertexBufferInfo(TEXT("TangentVertexBuffer")); + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + TangentBuffer.VertexBufferRHI = RHICmdList.CreateVertexBuffer(SizeInBytes, BUF_Volatile, TangentVertexBufferInfo); + #else + TangentBuffer.VertexBufferRHI = RHICreateVertexBuffer(SizeInBytes, BUF_Volatile, TangentVertexBufferInfo); + #endif + } + + // Initialize Color Buffer (unused) + { + const uint32 SizeInBytes = sizeof(FColor) * Positions.Num(); + + FRHIResourceCreateInfo ColorVertexBufferInfo(TEXT("ColorVertexBuffer")); + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + ColorBuffer.VertexBufferRHI = RHICmdList.CreateVertexBuffer(SizeInBytes, BUF_Volatile, ColorVertexBufferInfo); + #else + ColorBuffer.VertexBufferRHI = RHICreateVertexBuffer(SizeInBytes, BUF_Volatile, ColorVertexBufferInfo); + #endif + } + + if (RHISupportsManualVertexFetch(GMaxRHIShaderPlatform)) + { + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + PositionBufferSRV = RHICmdList.CreateShaderResourceView(PositionBuffer.VertexBufferRHI, sizeof(float), PF_R32_FLOAT); + UVBufferSRV = RHICmdList.CreateShaderResourceView(UVBuffer.VertexBufferRHI, sizeof(FVector2f), PF_G32R32F); + TangentBufferSRV = RHICmdList.CreateShaderResourceView(TangentBuffer.VertexBufferRHI, 4, PF_R8G8B8A8_SNORM); + ColorBufferSRV = RHICmdList.CreateShaderResourceView(ColorBuffer.VertexBufferRHI, 4, PF_R8G8B8A8); + #else + PositionBufferSRV = RHICreateShaderResourceView(PositionBuffer.VertexBufferRHI, sizeof(float), PF_R32_FLOAT); + UVBufferSRV = RHICreateShaderResourceView(UVBuffer.VertexBufferRHI, sizeof(FVector2f), PF_G32R32F); + TangentBufferSRV = RHICreateShaderResourceView(TangentBuffer.VertexBufferRHI, 4, PF_R8G8B8A8_SNORM); + ColorBufferSRV = RHICreateShaderResourceView(ColorBuffer.VertexBufferRHI, 4, PF_R8G8B8A8); + #endif + } + } + + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + void InitResource(FRHICommandListBase& RHICmdList) override + { + FRenderResource::InitResource(RHICmdList); + + PositionBuffer.InitResource(RHICmdList); + UVBuffer.InitResource(RHICmdList); + TangentBuffer.InitResource(RHICmdList); + ColorBuffer.InitResource(RHICmdList); + } + #else + void InitResource() override + { + FRenderResource::InitResource(); + + PositionBuffer.InitResource(); + UVBuffer.InitResource(); + TangentBuffer.InitResource(); + ColorBuffer.InitResource(); + } + #endif + + void ReleaseResource() override + { + FRenderResource::ReleaseResource(); + + PositionBuffer.ReleaseResource(); + UVBuffer.ReleaseResource(); + TangentBuffer.ReleaseResource(); + ColorBuffer.ReleaseResource(); + } + + virtual void ReleaseRHI() override + { + PositionBuffer.VertexBufferRHI.SafeRelease(); + UVBuffer.VertexBufferRHI.SafeRelease(); + TangentBuffer.VertexBufferRHI.SafeRelease(); + ColorBuffer.VertexBufferRHI.SafeRelease(); + } + + void UpdateBuffer(const TArray& NewPositions, const TArray& NewUVs) + { + ENQUEUE_RENDER_COMMAND(UpdateVertexBuffer)( + [this, NewPositions, NewUVs](FRHICommandListImmediate& RHICmdList) + { + // Update Position Buffer + { + const uint32 SizeInBytes = sizeof(FVector3f) * NewPositions.Num(); + void* PositionBufferData = RHICmdList.LockBuffer(PositionBuffer.VertexBufferRHI, 0, SizeInBytes, RLM_WriteOnly); + FMemory::Memcpy(PositionBufferData, NewPositions.GetData(), SizeInBytes); + RHICmdList.UnlockBuffer(PositionBuffer.VertexBufferRHI); + } + + // Update UV Buffer + { + const uint32 SizeInBytes = sizeof(FVector2f) * NewUVs.Num(); + void* UVBufferData = RHICmdList.LockBuffer(UVBuffer.VertexBufferRHI, 0, SizeInBytes, RLM_WriteOnly); + FMemory::Memcpy(UVBufferData, NewUVs.GetData(), SizeInBytes); + RHICmdList.UnlockBuffer(UVBuffer.VertexBufferRHI); + } + } + ); + } + +public: + FVertexBuffer PositionBuffer; + FVertexBuffer UVBuffer; + FVertexBuffer TangentBuffer; + FVertexBuffer ColorBuffer; + + FShaderResourceViewRHIRef PositionBufferSRV; + FShaderResourceViewRHIRef UVBufferSRV; + FShaderResourceViewRHIRef TangentBufferSRV; + FShaderResourceViewRHIRef ColorBufferSRV; + + TArray Positions; + TArray UVs; +}; + +/** + * Index buffer for a drawable. + */ +class FCubismDrawableIndexBuffer : public FIndexBuffer +{ +public: + FCubismDrawableIndexBuffer(const FCubismDrawableDynamicMeshData& DynamicData) + : Indices(DynamicData.Indices) + { } + + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + virtual void InitRHI(FRHICommandListBase& RHICmdList) override + #else + virtual void InitRHI() override + #endif + { + TRACE_CPUPROFILER_EVENT_SCOPE(FCubismDrawableIndexBuffer::InitRHI) + + const uint32 SizeInBytes = sizeof(uint16) * Indices.Num(); + + FRHIResourceCreateInfo IndexBufferInfo(TEXT("IndexBuffer")); + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + IndexBufferRHI = RHICmdList.CreateIndexBuffer(sizeof(uint16), SizeInBytes, BUF_Volatile, IndexBufferInfo); + void* IndexBufferData = RHICmdList.LockBuffer(IndexBufferRHI, 0, SizeInBytes, RLM_WriteOnly); + FMemory::Memcpy(IndexBufferData, Indices.GetData(), SizeInBytes); + RHICmdList.UnlockBuffer(IndexBufferRHI); + #else + IndexBufferRHI = RHICreateIndexBuffer(sizeof(uint16), SizeInBytes, BUF_Volatile, IndexBufferInfo); + void* IndexBufferData = RHILockBuffer(IndexBufferRHI, 0, SizeInBytes, RLM_WriteOnly); + FMemory::Memcpy(IndexBufferData, Indices.GetData(), SizeInBytes); + RHIUnlockBuffer(IndexBufferRHI); + #endif + } + + virtual void ReleaseRHI() override + { + IndexBufferRHI.SafeRelease(); + FIndexBuffer::ReleaseRHI(); + } + + void UpdateBuffer(const TArray& NewIndices) + { + ENQUEUE_RENDER_COMMAND(UpdateIndexBuffer)( + [this, NewIndices](FRHICommandListImmediate& RHICmdList) + { + const uint32 SizeInBytes = sizeof(uint16) * NewIndices.Num(); + void* IndexBufferData = RHICmdList.LockBuffer(IndexBufferRHI, 0, SizeInBytes, RLM_WriteOnly); + FMemory::Memcpy(IndexBufferData, NewIndices.GetData(), SizeInBytes); + RHICmdList.UnlockBuffer(IndexBufferRHI); + } + ); + } + +public: + TArray Indices; +}; + +/** + * Vertex factory for a drawable. + */ +class FCubismDrawableVertexFactory : public FLocalVertexFactory +{ +public: + FCubismDrawableVertexFactory(ERHIFeatureLevel::Type InFeatureLevel, const FCubismDrawableVertexBuffer* InVertexBuffer) + : FLocalVertexFactory(InFeatureLevel, "FCubismDrawableVertexFactory") + , VertexBuffer(InVertexBuffer) + { } + + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + void InitResource(FRHICommandListBase& RHICmdList) override + #else + void InitResource() override + #endif + { + TRACE_CPUPROFILER_EVENT_SCOPE(FCubismDrawableVertexFactory::InitResource) + + { + FDataType LocalData; + + LocalData.NumTexCoords = 1; + LocalData.PositionComponentSRV = VertexBuffer->PositionBufferSRV; + LocalData.TextureCoordinatesSRV = VertexBuffer->UVBufferSRV; + LocalData.TangentsSRV = VertexBuffer->TangentBufferSRV; + LocalData.ColorComponentsSRV = VertexBuffer->ColorBufferSRV; + + { + LocalData.PositionComponent = FVertexStreamComponent( + &VertexBuffer->PositionBuffer, + 0, + sizeof(FVector3f), + VET_Float3 + ); + + LocalData.TextureCoordinates.Add(FVertexStreamComponent( + &VertexBuffer->UVBuffer, + 0, + sizeof(FVector2f), + VET_Float2, + EVertexStreamUsage::ManualFetch + )); + } + + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 4 + SetData(RHICmdList, LocalData); + #else + SetData(LocalData); + #endif + } + + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + FLocalVertexFactory::InitResource(RHICmdList); + #else + FLocalVertexFactory::InitResource(); + #endif + } + +private: + const FCubismDrawableVertexBuffer* VertexBuffer; +}; diff --git a/Source/Live2DCubismFramework/Private/Rendering/CubismShaders.cpp b/Source/Live2DCubismFramework/Private/Rendering/CubismShaders.cpp index 7f86749..6741e94 100644 --- a/Source/Live2DCubismFramework/Private/Rendering/CubismShaders.cpp +++ b/Source/Live2DCubismFramework/Private/Rendering/CubismShaders.cpp @@ -7,91 +7,119 @@ #include "Rendering/CubismShaders.h" +#include "ClearQuad.h" -#include "ShaderParameterUtils.h" -#include "ShaderParameterStruct.h" -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 2 -#include "DataDrivenShaderPlatformInfo.h" -#endif -#include "BatchedElements.h" -#include "RenderResource.h" -#include "GlobalShader.h" - -/*** Cubism Mask Shader ***/ - -class FCubismMeshMaskVS : public FGlobalShader +class FCubismMeshMaskVertexDeclaration : public FRenderResource { - DECLARE_GLOBAL_SHADER(FCubismMeshMaskVS); +public: + FVertexDeclarationRHIRef VertexDeclarationRHI; - FCubismMeshMaskVS() {} - FCubismMeshMaskVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) - : FGlobalShader(Initializer) - { - Scale.Bind(Initializer.ParameterMap, TEXT("Scale")); - Offset.Bind(Initializer.ParameterMap, TEXT("Offset")); - } + virtual ~FCubismMeshMaskVertexDeclaration() {} - static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + virtual void InitRHI(FRHICommandListBase& RHICmdList) override + #else + virtual void InitRHI() override + #endif { - return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); + FVertexDeclarationElementList Elements; + uint16 Stride = sizeof(FCubismMeshMaskVertex); + Elements.Add(FVertexElement(0, STRUCT_OFFSET(FCubismMeshMaskVertex, Position), VET_Float2, 0, Stride)); + Elements.Add(FVertexElement(0, STRUCT_OFFSET(FCubismMeshMaskVertex, UV), VET_Float2, 1, Stride)); + VertexDeclarationRHI = PipelineStateCache::GetOrCreateVertexDeclaration(Elements); } - template - void SetParameters(FRHICommandList& RHICmdList, const TShaderRHIParamRef ShaderRHI, const FVector4& InOffset) + virtual void ReleaseRHI() override { - #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 - FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters(); - SetShaderValue(BatchedParameters, Offset, FVector4f(InOffset)); - RHICmdList.SetBatchedShaderParameters(ShaderRHI, BatchedParameters); - #else - SetShaderValue(RHICmdList, ShaderRHI, Offset, FVector4f(InOffset)); - #endif + VertexDeclarationRHI.SafeRelease(); } - -protected: - LAYOUT_FIELD(FShaderParameter, Scale); - LAYOUT_FIELD(FShaderParameter, Offset); }; -class FCubismMeshMaskPS : public FGlobalShader +TGlobalResource GCubismMeshMaskVertexDeclaration; + +void DrawMask_RenderThread(FRHICommandList& RHICmdList, FTextureRenderTargetResource* RenderTargetResource, const TArray& MaskDrawInfos) { - DECLARE_GLOBAL_SHADER(FCubismMeshMaskPS); - SHADER_USE_PARAMETER_STRUCT(FCubismMeshMaskPS, FGlobalShader); + FRHIRenderPassInfo RPInfo(RenderTargetResource->GetRenderTargetTexture(), ERenderTargetActions::DontLoad_Store); + RHICmdList.BeginRenderPass(RPInfo, TEXT("DrawMask")); - static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) - { - return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); - } + // Clear the render target. + DrawClearQuad(RHICmdList, FLinearColor::Transparent); - BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) - SHADER_PARAMETER(FVector4f, Channel) - SHADER_PARAMETER_TEXTURE(Texture2D, MainTexture) - SHADER_PARAMETER_SAMPLER(SamplerState, MainSampler) - END_SHADER_PARAMETER_STRUCT() -}; + TShaderMapRef VertexShader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); + TShaderMapRef PixelShader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); -void FCubismMaskBatchedElementParameters::BindShaders(FRHICommandList& RHICmdList, FGraphicsPipelineStateInitializer& GraphicsPSOInit, ERHIFeatureLevel::Type InFeatureLevel, const FMatrix& InTransform, const float InGamma, const FMatrix& ColorWeights, const FTexture* Texture) -{ - TShaderMapRef VertexShader(GetGlobalShaderMap(InFeatureLevel)); - TShaderMapRef PixelShader(GetGlobalShaderMap(InFeatureLevel)); + FGraphicsPipelineStateInitializer GraphicsPSOInit; + RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); + + GraphicsPSOInit.RasterizerState = TStaticRasterizerState::GetRHI(); + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); - GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GSimpleElementVertexDeclaration.VertexDeclarationRHI; + GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GCubismMeshMaskVertexDeclaration.VertexDeclarationRHI; GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader(); GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader(); GraphicsPSOInit.PrimitiveType = PT_TriangleList; - GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); - RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0); - VertexShader->SetParameters(RHICmdList, VertexShader.GetVertexShader(), Offset); + for (const FMaskDrawInfo& DrawInfo : MaskDrawInfos) + { + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters(); + VertexShader->SetParameters(BatchedParameters, DrawInfo.Offset); + RHICmdList.SetBatchedShaderParameters(VertexShader.GetVertexShader(), BatchedParameters); + #else + VertexShader->SetParameters(RHICmdList, VertexShader.GetVertexShader(), DrawInfo.Offset); + #endif - FCubismMeshMaskPS::FParameters ShaderParameters; - ShaderParameters.Channel = (FVector4f)Channel; - ShaderParameters.MainTexture = MainTexture->TextureRHI; - ShaderParameters.MainSampler = TStaticSamplerState<>::GetRHI(); + FCubismMeshMaskPS::FParameters ParametersPS; + ParametersPS.Channel = (FVector4f)DrawInfo.Channel; + ParametersPS.MainTexture = DrawInfo.MainTexture->TextureRHI; + ParametersPS.MainSampler = TStaticSamplerState<>::GetRHI(); + + SetShaderParameters(RHICmdList, PixelShader, PixelShader.GetPixelShader(), ParametersPS); + + int32 NumVerts = DrawInfo.Vertices.Num(); + int32 NumIndices = DrawInfo.Indices.Num(); + + { + FRHIResourceCreateInfo VertexBufferInfo(TEXT("MaskVertexBuffer")); + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + FBufferRHIRef VertexBuffer = RHICmdList.CreateVertexBuffer(sizeof(FCubismMeshMaskVertex) * NumVerts, BUF_Volatile, VertexBufferInfo); + #else + FBufferRHIRef VertexBuffer = RHICreateVertexBuffer(sizeof(FCubismMeshMaskVertex) * NumVerts, BUF_Volatile, VertexBufferInfo); + #endif + void* VertexBufferData = RHICmdList.LockBuffer(VertexBuffer, 0, sizeof(FCubismMeshMaskVertex) * NumVerts, RLM_WriteOnly); + FMemory::Memcpy(VertexBufferData, DrawInfo.Vertices.GetData(), sizeof(FCubismMeshMaskVertex) * NumVerts); + RHICmdList.UnlockBuffer(VertexBuffer); + + // Bind the vertex buffers + RHICmdList.SetStreamSource(0, VertexBuffer, 0); + + // Release the vertex buffer + VertexBuffer.SafeRelease(); + } + + { + FRHIResourceCreateInfo IndexBufferInfo(TEXT("MaskIndexBuffer")); + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + FBufferRHIRef IndexBuffer = RHICmdList.CreateIndexBuffer(sizeof(uint16), sizeof(uint16) * NumIndices, BUF_Volatile, IndexBufferInfo); + #else + FBufferRHIRef IndexBuffer = RHICreateIndexBuffer(sizeof(uint16), sizeof(uint16) * NumIndices, BUF_Volatile, IndexBufferInfo); + #endif + void* IndexBufferData = RHICmdList.LockBuffer(IndexBuffer, 0, sizeof(uint16) * NumIndices, RLM_WriteOnly); + FMemory::Memcpy(IndexBufferData, DrawInfo.Indices.GetData(), sizeof(uint16) * NumIndices); + RHICmdList.UnlockBuffer(IndexBuffer); + + // Issue the draw call + RHICmdList.DrawIndexedPrimitive(IndexBuffer, 0, 0, NumVerts, 0, NumIndices / 3, 1); + + // Release the index buffer + IndexBuffer.SafeRelease(); + } + } - SetShaderParameters(RHICmdList, PixelShader, PixelShader.GetPixelShader(), ShaderParameters); + RHICmdList.EndRenderPass(); } IMPLEMENT_GLOBAL_SHADER(FCubismMeshMaskVS, "/Plugin/Live2DCubismSDK/Private/CubismMeshMask.usf", "MainVS", SF_Vertex); diff --git a/Source/Live2DCubismFramework/Private/Rendering/CubismShaders.h b/Source/Live2DCubismFramework/Private/Rendering/CubismShaders.h index 124ff4e..4705201 100644 --- a/Source/Live2DCubismFramework/Private/Rendering/CubismShaders.h +++ b/Source/Live2DCubismFramework/Private/Rendering/CubismShaders.h @@ -8,30 +8,76 @@ #pragma once -#include "BatchedElements.h" +#include "ShaderParameterStruct.h" +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 +#include "DataDrivenShaderPlatformInfo.h" +#endif -class FCubismMaskBatchedElementParameters : public FBatchedElementParameters +struct FCubismMeshMaskVertex { -public: - FCubismMaskBatchedElementParameters( - const FVector4 InOffset, - const FVector4 InChannel, - const FTextureResource* InMainTexture - ) - : Offset(InOffset) - , Channel(InChannel) - , MainTexture(InMainTexture) - { } - - virtual void BindShaders(FRHICommandList& RHICmdList, FGraphicsPipelineStateInitializer& GraphicsPSOInit, ERHIFeatureLevel::Type InFeatureLevel, const FMatrix& InTransform, const float InGamma, const FMatrix& ColorWeights, const FTexture* Texture) override; - -protected: - /** The offset of the mask to be drawn. */ - const FVector4 Offset; - - /** The channel of the mask to be drawn. */ - const FVector4 Channel; - - /** The texture assigned to the drawable. */ - const FTextureResource* MainTexture; + FVector2f Position; // ATTRIBUTE0 + FVector2f UV; // ATTRIBUTE1 +}; + +struct FMaskDrawInfo +{ + TArray Indices; + TArray Vertices; + FVector4 Offset; + FVector4 Channel; + FTexture* MainTexture; +}; + +/*** Cubism Mask Shader ***/ + +void DrawMask_RenderThread(FRHICommandList& RHICmdList, FTextureRenderTargetResource* RenderTargetResource, const TArray& MaskDrawInfos); + +class FCubismMeshMaskVS : public FGlobalShader +{ + DECLARE_GLOBAL_SHADER(FCubismMeshMaskVS); + + FCubismMeshMaskVS() {} + FCubismMeshMaskVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) + : FGlobalShader(Initializer) + { + Offset.Bind(Initializer.ParameterMap, TEXT("Offset")); + } + + static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) + { + return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); + } + + #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3 + void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, const FVector4& InOffset) + { + SetShaderValue(BatchedParameters, Offset, (FVector4f)InOffset); + } + #else + template + void SetParameters(FRHICommandList& RHICmdList, const TShaderRHIParamRef ShaderRHI, const FVector4& InOffset) + { + SetShaderValue(RHICmdList, ShaderRHI, Offset, (FVector4f)InOffset); + } + #endif + +private: + LAYOUT_FIELD(FShaderParameter, Offset); +}; + +class FCubismMeshMaskPS : public FGlobalShader +{ + DECLARE_GLOBAL_SHADER(FCubismMeshMaskPS); + SHADER_USE_PARAMETER_STRUCT(FCubismMeshMaskPS, FGlobalShader); + + BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) + SHADER_PARAMETER(FVector4f, Channel) + SHADER_PARAMETER_TEXTURE(Texture2D, MainTexture) + SHADER_PARAMETER_SAMPLER(SamplerState, MainSampler) + END_SHADER_PARAMETER_STRUCT() + + static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) + { + return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); + } }; diff --git a/Source/Live2DCubismFramework/Public/Rendering/CubismMaskTextureComponent.h b/Source/Live2DCubismFramework/Public/Rendering/CubismMaskTextureComponent.h index b2e6464..c02e22c 100644 --- a/Source/Live2DCubismFramework/Public/Rendering/CubismMaskTextureComponent.h +++ b/Source/Live2DCubismFramework/Public/Rendering/CubismMaskTextureComponent.h @@ -9,6 +9,7 @@ #pragma once #include "Model/CubismModelActor.h" +#include "Rendering/CubismShaders.h" #include "CubismMaskTextureComponent.generated.h"