プラグインに新規グローバル シェーダーを作成する - コードの設定

グローバル シェーダー プラグイン用にプラグインとコードを設定する

Windows
MacOS
Linux
このページ中

アンリアル エンジン (UE4) 用のプラグインの新規作成を始める前に、Visual Studio がインストールされていることを確認してください。この操作ガイドでは、プラグインのコードをコンパイルして実行可能にする必要があるので、Visual Studio が必要になります。インストール方法が分からない場合は アンリアル エンジンのソースコードをダウンロードする を参照してください。

  1. まず、Desktop SettingMaximum QualityStarter Content を一切含まない設定の C++ Basic Code プロジェクトを新規作成します。

    クリックしてフルサイズで表示

  2. プロジェクトが作成されたら、Visual Studio を開き、ShadersInPlugins プロジェクトを右クリックして [Build] オプションを選択してプロジェクトをコンパイルします。

    HT_ShadersInPlugins_01.png

  3. プロジェクトのコンパイルが完了したら、Visual Studio の F5 キーを押して UE4 エディタで ShadersInPlugins プロジェクトを起動します。

  4. UE4 エディタのロード処理が完了したら、[Edit] > [Plugins] から Plugins マネージャを開いて [Plugin] ウィンドウの右下にある [New Plugin] オプションをクリックして新規プラグイン作成ウインドウを開きます。

    クリックしてフルサイズで表示

  5. [New Plugin] ウィンドウから [Blank] プラグインを選択し、[Name] 欄に 「Foo」 と入力し、すべての設定をデフォルトにします。これがすべて完了したら、[Create Plugin (プラグインを作成)] ボタンを押して、プラグインが最初に必要とするコンテンツすべてを作成します。

    クリックしてフルサイズで表示

  6. これが完了したら、UE4 と Visual Studio を閉じます。次にプロジェクト フォルダ内に作成された [Plugins] > 「Foo plugin」 フォルダを開きます。

  7. 「Foo プラグイン」フォルダ内に 「Shaders」 という名前の新規フォルダを追加し、その中に 「Private」 という名前の新規フォルダを作成します。

    クリックしてフルサイズで表示

  8. 「Private」フォルダの中にテキスト ファイルを新規作成し 「MyShader.USF」 と名前を付けたら、以下の HLSL コードをこのファイルにコピーペーストして、完了したらファイルを閉じます。

    ファイルの拡張子を .USF に必ず変更してください。そうしないと、これがシェーダーファイルであることを UE4 が認識しません。

    // Copyright 1998-2018 Epic Games, Inc.All Rights Reserved.
    
    /*=============================================================================
        LensDistortionUVGeneration.usf:Generate lens distortion and undistortion
        UV displacement map into a render target.
    
        The pixel shader directly compute the distort viewport UV to undistort
        viewport UV displacement using Sv_Position and the reference equations and
        store them into the red and green channels.
    
        However to avoid resolving with a ferrari method, or doing a newton method
        on the GPU to compute the undistort viewport UV to distort viewport UV
        displacement, this couple of shaders works as follow:The vertex shader
        undistort the grid's vertices, and pass down to the pixel shader the viewport
        UV of where they should have been on screen without undistortion.The pixel
        shader can then generate the undistort viewport UV to distort viewport UV
        displacement by just subtracting the pixel's viewport UV.
    =============================================================================*/
    
    #include "/Engine/Public/Platform.ush"
    
    // Size of the pixels in the viewport UV coordinates.
    float2 PixelUVSize;
    
    // K1, K2, K3
    float3 RadialDistortionCoefs;
    
    // P1, P2
    float2 TangentialDistortionCoefs;
    
    // Camera matrix of the undistorted viewport.
    float4 UndistortedCameraMatrix;
    
    // Camera matrix of the distorted viewport.
    float4 DistortedCameraMatrix;
    
    // Output multiply and add to the render target.
    float2 OutputMultiplyAndAdd;
    
    // Undistort a view position at V.z=1.
    float2 UndistortNormalizedViewPosition(float2 V)
    {
        float2 V2 = V * V;
        float R2 = V2.x + V2.y;
    
        // Radial distortion (extra parenthesis to match MF_Undistortion.uasset).
        float2 UndistortedV = V * (1.0 + R2 * (RadialDistortionCoefs.x + R2 * (RadialDistortionCoefs.y + R2 * RadialDistortionCoefs.z)));
    
        // Tangential distortion.
        UndistortedV.x += TangentialDistortionCoefs.y * (R2 + 2 * V2.x) + 2 * TangentialDistortionCoefs.x * V.x * V.y;
        UndistortedV.y += TangentialDistortionCoefs.x * (R2 + 2 * V2.y) + 2 * TangentialDistortionCoefs.y * V.x * V.y;
    
        return UndistortedV;
    }
    
    // Returns the undistorted viewport UV of the distorted's viewport UV.
    //
    // Notes:
    //        UVs are bottom left originated.
    float2 UndistortViewportUV(float2 ViewportUV)
    {
        // Distorted viewport UV -> Distorted view position (z=1)
        float2 DistortedViewPosition = (ViewportUV - DistortedCameraMatrix.zw) / DistortedCameraMatrix.xy;
    
        // Compute undistorted view position (z=1)
        float2 UndistortedViewPosition = UndistortNormalizedViewPosition(DistortedViewPosition);
    
        // Undistorted view position (z=1) -> Undistorted viewport UV.
        return UndistortedCameraMatrix.xy * UndistortedViewPosition + UndistortedCameraMatrix.zw;
    }
    
    // Flip UV's y component.
    float2 FlipUV(float2 UV)
    {
        return float2(UV.x, 1 - UV.y);
    }
    
    void MainVS(
        in uint GlobalVertexId :SV_VertexID,
        out float2 OutVertexDistortedViewportUV :TEXCOORD0,
        out float4 OutPosition :SV_POSITION
        )
    {
        // Compute the cell index.
        uint GridCellIndex = GlobalVertexId / 6;
    
        // Compute row and column id of the cell within the grid.
        uint GridColumnId = GridCellIndex / GRID_SUBDIVISION_Y;
        uint GridRowId = GridCellIndex - GridColumnId * GRID_SUBDIVISION_Y;
    
        // Compute the vertex id within a 2 triangles grid cell.
        uint VertexId = GlobalVertexId - GridCellIndex * 6;
    
        // Compute the bottom left originated UV coordinate of the triangle's vertex within the cell.
        float2 CellVertexUV = float2(0x1 & ((VertexId + 1) / 3), VertexId & 0x1);
    
        // Compute the top left originated UV of the vertex within the grid.
        float2 GridInvSize = 1.f / float2(GRID_SUBDIVISION_X, GRID_SUBDIVISION_Y);
        float2 GridVertexUV = FlipUV(
            GridInvSize * (CellVertexUV + float2(GridColumnId, GridRowId)));
    
        // The standard doesn't have half pixel shift.
        GridVertexUV -= PixelUVSize * 0.5;
    
        // Output vertex position.
        OutPosition = float4(FlipUV(
            UndistortViewportUV(GridVertexUV) + PixelUVSize * 0.5) * 2 - 1, 0, 1);
    
        // Output top left originated UV of the vertex.
        OutVertexDistortedViewportUV = GridVertexUV;
    }
    
    void MainPS(
        in noperspective float2 VertexDistortedViewportUV :TEXCOORD0,
        in float4 SvPosition :SV_POSITION,
        out float4 OutColor :SV_Target0
        )
    {
        // Compute the pixel's top left originated UV.
        float2 ViewportUV = SvPosition.xy * PixelUVSize;
    
        // The standard doesn't have half pixel shift.
        ViewportUV -= PixelUVSize * 0.5;
    
        float2 DistortUVtoUndistortUV = (UndistortViewportUV((ViewportUV))) - ViewportUV;
        float2 UndistortUVtoDistortUV = VertexDistortedViewportUV - ViewportUV;
    
        // Output displacement channels.
        OutColor = OutputMultiplyAndAdd.y + OutputMultiplyAndAdd.x * float4(
            DistortUVtoUndistortUV, UndistortUVtoDistortUV);
    }
  9. 次に 「Foo.uplugin」 ファイルの中にあるテキスト エディタの中を開き、その中にある情報を以下のテキストで置き換えて、最後にフィアルを保存します。

    {
        "FileVersion" :3,
        "Version" :1,
        "VersionName" :"1.0",
        "FriendlyName" :"Foo",
        "Description" :"Plugin to play around with shaders.",
        "Category" :"Sandbox",
        "CreatedBy" :"Epic Games, Inc.",
        "CreatedByURL" : "http://epicgames.com",
        "DocsURL" : "",
        "MarketplaceURL" : "",
        "SupportURL" : "",
        "EnabledByDefault" : false,
        "CanContainContent" : true,
        "IsBetaVersion" : false,
        "Installed" : false,
        "Modules" :
        [
            {
                "Name" :"Foo",
                "Type" :"Developer",
                "LoadingPhase" :"PostConfigInit"
            }
        ]
    }
  10. 次に Plugins\Foo\Source\Foo を開き 「Classes」 という名前の新規フォルダを作成し、「LensDistortionAPI.h」「LensDistortionBlueprintLibrary.h」 ファイルを Engine\Plugins\Compositing\LensDistortion から新規作成したこのフォルダへコピーします。

    コピーするファイルは Engine\Plugins\Compositing\LensDistortion にあります。

    • Classes - Create New Folder

      • Copy - LensDistortionAPI.h

      • Copy - LensDistortionBlueprintLibrary.h

      HT_ShadersInPlugins_05.png

  11. 「Private」 フォルダを開き 「LensDistortionBlueprintLibrary.cpp」「LensDistortionRendering.cpp」 ファイルの両方をこの「Private」フォルダにコピーします。

    • Private - Existing Folder

      • Copy - LensDistortionBlueprintLibrary.cpp

      • Copy - LensDistortionRendering.cpp

      HT_ShadersInPlugins_06.png

  12. UE4 と Visual Studio を両方とも閉じて、今度は「projects .U」ファイルを探します。見つかったら、右クリックして 「Generate Visual Studio project files」 オプションを選択します。

    HT_ShadersInPlugins_07.png

  13. Visual Studio ソリューションを再度開き、[Foo] > [Classes] から 「LensDistortionAPI.h」 ファイルを開きます。このファイル内で FLensDistortionCameraModelFFooCameraModel に置き換えます。

    このファイルの FLensDistortionCameraModel を FFooCameraModel に 4 回置き換えなければなりません。

        // Copyright 1998-2018 Epic Games, Inc.All Rights Reserved.
    
        #pragma once
    
        #include "CoreMinimal.h"
        #include "LensDistortionAPI.generated.h"
    
        /** Mathematic camera model for lens distortion/undistortion.
         *
         * Camera matrix =
         *  | F.X  0  C.x |
         *  |  0  F.Y C.Y |
         *  |  0   0   1  |
         */
        USTRUCT(BlueprintType)
        struct FFooCameraModel
        {
            GENERATED_USTRUCT_BODY()
            FFooCameraModel()
            {
                K1 = K2 = K3 = P1 = P2 = 0.f;
                F = FVector2D(1.f, 1.f);
                C = FVector2D(0.5f, 0.5f);
            }
    
            /** Radial parameter #1. */
            UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "Lens Distortion|Camera Model")
            float K1;
    
            /** Radial parameter #2. */
            UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "Lens Distortion|Camera Model")
            float K2;
    
            /** Radial parameter #3. */
            UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "Lens Distortion|Camera Model")
            float K3;
    
            /** Tangential parameter #1. */
            UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "Lens Distortion|Camera Model")
            float P1;
    
            /** Tangential parameter #2. */
            UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "Lens Distortion|Camera Model")
            float P2;
    
            /** Camera matrix's Fx and Fy. */
            UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "Lens Distortion|Camera Model")
            FVector2D F;
    
            /** Camera matrix's Cx and Cy. */
            UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "Lens Distortion|Camera Model")
            FVector2D C;
    
            /** Undistorts 3d vector (x, y, z=1.f) in the view space and returns (x', y', z'=1.f). */
            FVector2D UndistortNormalizedViewPosition(FVector2D V) const;
    
            /** Returns the overscan factor required for the undistort rendering to avoid unrendered distorted pixels. */
            float GetUndistortOverscanFactor(
                float DistortedHorizontalFOV,
                float DistortedAspectRatio) const;
    
            /** Draws UV displacement map within the output render target.
             * - Red & green channels hold the distortion displacement;
             * - Blue & alpha channels hold the undistortion displacement.
             * @param World Current world to get the rendering settings from (such as feature level).
             * @param DistortedHorizontalFOV The desired horizontal FOV in the distorted render.
             * @param DistortedAspectRatio The desired aspect ratio of the distorted render.
             * @param UndistortOverscanFactor The factor of the overscan for the undistorted render.
             * @param OutputRenderTarget The render target to draw to.Don't necessarily need to have same resolution or aspect ratio as distorted render.
             * @param OutputMultiply The multiplication factor applied on the displacement.
             * @param OutputAdd Value added to the multiplied displacement before storing the output render target.
             */
            void DrawUVDisplacementToRenderTarget(
                class UWorld* World,
                float DistortedHorizontalFOV,
                float DistortedAspectRatio,
                float UndistortOverscanFactor,
                class UTextureRenderTarget2D* OutputRenderTarget,
                float OutputMultiply,
                float OutputAdd) const;
    
            /** Compare two lens distortion models and return whether they are equal. */
            bool operator == (const FFooCameraModel& Other) const
            {
                return (
                    K1 == Other.K1 &&
                    K2 == Other.K2 &&
                    K3 == Other.K3 &&
                    P1 == Other.P1 &&
                    P2 == Other.P2 &&
                    F == Other.F &&
                    C == Other.C);
            }
    
            /** Compare two lens distortion models and return whether they are different. */
            bool operator != (const FFooCameraModel& Other) const
            {
                return !(*this == Other);
            }
        };
  14. 次に 「LensDistortionBlueprintLibrary.h」 ファイルを開きます。このファイルは、ブループリントでのこのノードの見え方を調節するので、FLensDistortionCameraModelFFooCameraModel に置き換えるだけでなく、Category = "Lens Distortion" Category = "Foo | Lens Distortion" に変更する必要もあります。

    このファイルの中で、FLensDistortionCameraModel を FFooCameraModel に 6 回置き換えな変えればなりません。

    // Copyright 1998-2018 Epic Games, Inc.All Rights Reserved.
    
    #pragma once
    
    #include "CoreMinimal.h"
    #include "UObject/ObjectMacros.h"
    #include "Classes/Kismet/BlueprintFunctionLibrary.h"
    #include "LensDistortionAPI.h"
    #include "LensDistortionBlueprintLibrary.generated.h"
    
    UCLASS(MinimalAPI)
    class ULensDistortionBlueprintLibrary : public UBlueprintFunctionLibrary
    {
        GENERATED_UCLASS_BODY()
    
        /** Returns the overscan factor required for the undistort rendering to avoid unrendered distorted pixels. */
        UFUNCTION(BlueprintPure, Category = "Foo | Lens Distortion")
        static void GetUndistortOverscanFactor(
            const FFooCameraModel& CameraModel,
            float DistortedHorizontalFOV,
            float DistortedAspectRatio,
            float& UndistortOverscanFactor);
    
        /** Draws UV displacement map within the output render target.
         * - Red & green channels hold the distortion displacement;
         * - Blue & alpha channels hold the undistortion displacement.
         * @param DistortedHorizontalFOV The desired horizontal FOV in the distorted render.
         * @param DistortedAspectRatio The desired aspect ratio of the distorted render.
         * @param UndistortOverscanFactor The factor of the overscan for the undistorted render.
         * @param OutputRenderTarget The render target to draw to.Don't necessarily need to have same resolution or aspect ratio as distorted render.
         * @param OutputMultiply The multiplication factor applied on the displacement.
         * @param OutputAdd Value added to the multiplied displacement before storing into the output render target.
         */
        UFUNCTION(BlueprintCallable, Category = "Foo | Lens Distortion", meta = (WorldContext = "WorldContextObject"))
        static void DrawUVDisplacementToRenderTarget(
            const UObject* WorldContextObject,
            const FFooCameraModel& CameraModel,
            float DistortedHorizontalFOV,
            float DistortedAspectRatio,
            float UndistortOverscanFactor,
            class UTextureRenderTarget2D* OutputRenderTarget,
            float OutputMultiply = 0.5,
            float OutputAdd = 0.5
            );
    
        /* Returns true if A is equal to B (A == B) */
        UFUNCTION(BlueprintPure, meta=(DisplayName = "Equal (LensDistortionCameraModel)", CompactNodeTitle = "==", Keywords = "== equal"), Category = "Foo | Lens Distortion")
        static bool EqualEqual_CompareLensDistortionModels(
            const FFooCameraModel& A,
            const FFooCameraModel& B)
        {
            return A == B;
        }
    
        /* Returns true if A is not equal to B (A != B) */
        UFUNCTION(BlueprintPure, meta = (DisplayName = "NotEqual (LensDistortionCameraModel)", CompactNodeTitle = "!=", Keywords = "!= not equal"), Category = "Foo | Lens Distortion")
        static bool NotEqual_CompareLensDistortionModels(
            const FFooCameraModel& A,
            const FFooCameraModel& B)
        {
            return A != B;
        }
    };
  15. 次に 「Private」 フォルダの 「LensDistortionBlueprintLibrary.cpp」 ファイルを開いて以下を置き換えます。

    • FLensDistortionCameraModelFFooCameraModel に置き換える

    • ULensDistortionBlueprintLibraryUFooBlueprintLibrary に置き換える

    FLensDistortionCameraModel を FFooCameraModel に 2 回置き換えて ULensDistortionBlueprintLibrary を UFooBlueprintLibrary に 4 回置き換えます。

        // Copyright 1998-2018 Epic Games, Inc.All Rights Reserved.
    
        #include "LensDistortionBlueprintLibrary.h"
    
        ULensDistortionBlueprintLibrary::ULensDistortionBlueprintLibrary(const FObjectInitializer& ObjectInitializer)
            :Super(ObjectInitializer)
        { }
    
        // static
        void ULensDistortionBlueprintLibrary::GetUndistortOverscanFactor(
            const FFooCameraModel& CameraModel,
            float DistortedHorizontalFOV,
            float DistortedAspectRatio,
            float& UndistortOverscanFactor)
        {
            UndistortOverscanFactor = CameraModel.GetUndistortOverscanFactor(DistortedHorizontalFOV, DistortedAspectRatio);
        }
    
        // static
        void ULensDistortionBlueprintLibrary::DrawUVDisplacementToRenderTarget(
            const UObject* WorldContextObject,
            const FFooCameraModel& CameraModel,
            float DistortedHorizontalFOV,
            float DistortedAspectRatio,
            float UndistortOverscanFactor,
            class UTextureRenderTarget2D* OutputRenderTarget,
            float OutputMultiply,
            float OutputAdd)
        {
            CameraModel.DrawUVDisplacementToRenderTarget(
                WorldContextObject->GetWorld(),
                DistortedHorizontalFOV, DistortedAspectRatio,
                UndistortOverscanFactor, OutputRenderTarget,
                OutputMultiply, OutputAdd);
        }
  16. 次に 「Private」 フォルダの 「LensDistortionRendering.cpp」 ファイルを開いて FLensDistortionCameraModelFFooCameraModel に置き換えます。

    このファイルの中で、FLensDistortionCameraModel を FFooCameraModel に 6 回置き換えな変えればなりません。

        // Copyright 1998-2018 Epic Games, Inc.All Rights Reserved.
    
        #include "LensDistortionAPI.h"
        #include "Classes/Engine/TextureRenderTarget2D.h"
        #include "Classes/Engine/World.h"
        #include "Public/GlobalShader.h"
        #include "Public/PipelineStateCache.h"
        #include "Public/RHIStaticStates.h"
        #include "Public/SceneUtils.h"
        #include "Public/SceneInterface.h"
        #include "Public/ShaderParameterUtils.h"
    
        static const uint32 kGridSubdivisionX = 32;
        static const uint32 kGridSubdivisionY = 16;
    
        /**
         * Internal intermediary structure derived from FFooCameraModel by the game thread
         * to hand to the render thread.
         */
        struct FCompiledCameraModel
        {
            /** Orignal camera model that has generated this compiled model. */
            FFooCameraModel OriginalCameraModel;
    
            /** Camera matrices of the lens distortion for the undistorted and distorted render.
             *  XY holds the scales factors, ZW holds the translates.
             */
            FVector4 DistortedCameraMatrix;
            FVector4 UndistortedCameraMatrix;
    
            /** Output multiply and add of the channel to the render target. */
            FVector2D OutputMultiplyAndAdd;
        };
    
        /** Undistorts top left originated viewport UV into the view space (x', y', z'=1.f) */
        static FVector2D LensUndistortViewportUVIntoViewSpace(
            const FFooCameraModel& CameraModel,
            float TanHalfDistortedHorizontalFOV, float DistortedAspectRatio,
            FVector2D DistortedViewportUV)
        {
            FVector2D AspectRatioAwareF = CameraModel.F * FVector2D(1, -DistortedAspectRatio);
            return CameraModel.UndistortNormalizedViewPosition((DistortedViewportUV - CameraModel.C) / AspectRatioAwareF);
        }
    
        class FLensDistortionUVGenerationShader : public FGlobalShader
        {
        public:
            static bool ShouldCache(EShaderPlatform Platform)
            {
                return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
            }
    
            static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
            {
                FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment);
                OutEnvironment.SetDefine(TEXT("GRID_SUBDIVISION_X"), kGridSubdivisionX);
                OutEnvironment.SetDefine(TEXT("GRID_SUBDIVISION_Y"), kGridSubdivisionY);
            }
    
            FLensDistortionUVGenerationShader() {}
    
            FLensDistortionUVGenerationShader(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
                :FGlobalShader(Initializer)
            {
                PixelUVSize.Bind(Initializer.ParameterMap, TEXT("PixelUVSize"));
                RadialDistortionCoefs.Bind(Initializer.ParameterMap, TEXT("RadialDistortionCoefs"));
                TangentialDistortionCoefs.Bind(Initializer.ParameterMap, TEXT("TangentialDistortionCoefs"));
                DistortedCameraMatrix.Bind(Initializer.ParameterMap, TEXT("DistortedCameraMatrix"));
                UndistortedCameraMatrix.Bind(Initializer.ParameterMap, TEXT("UndistortedCameraMatrix"));
                OutputMultiplyAndAdd.Bind(Initializer.ParameterMap, TEXT("OutputMultiplyAndAdd"));
            }
    
            template<typename TShaderRHIParamRef>
            void SetParameters(
                FRHICommandListImmediate& RHICmdList,
                const TShaderRHIParamRef ShaderRHI,
                const FCompiledCameraModel& CompiledCameraModel,
                const FIntPoint& DisplacementMapResolution)
            {
                FVector2D PixelUVSizeValue(
                    1.f / float(DisplacementMapResolution.X), 1.f / float(DisplacementMapResolution.Y));
                FVector RadialDistortionCoefsValue(
                    CompiledCameraModel.OriginalCameraModel.K1,
                    CompiledCameraModel.OriginalCameraModel.K2,
                    CompiledCameraModel.OriginalCameraModel.K3);
                FVector2D TangentialDistortionCoefsValue(
                    CompiledCameraModel.OriginalCameraModel.P1,
                    CompiledCameraModel.OriginalCameraModel.P2);
    
                SetShaderValue(RHICmdList, ShaderRHI, PixelUVSize, PixelUVSizeValue);
                SetShaderValue(RHICmdList, ShaderRHI, DistortedCameraMatrix, CompiledCameraModel.DistortedCameraMatrix);
                SetShaderValue(RHICmdList, ShaderRHI, UndistortedCameraMatrix, CompiledCameraModel.UndistortedCameraMatrix);
                SetShaderValue(RHICmdList, ShaderRHI, RadialDistortionCoefs, RadialDistortionCoefsValue);
                SetShaderValue(RHICmdList, ShaderRHI, TangentialDistortionCoefs, TangentialDistortionCoefsValue);
                SetShaderValue(RHICmdList, ShaderRHI, OutputMultiplyAndAdd, CompiledCameraModel.OutputMultiplyAndAdd);
            }
    
            virtual bool Serialize(FArchive& Ar) override
            {
                bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
                Ar << PixelUVSize << RadialDistortionCoefs << TangentialDistortionCoefs << DistortedCameraMatrix << UndistortedCameraMatrix << OutputMultiplyAndAdd;
                return bShaderHasOutdatedParameters;
            }
    
        private:
            FShaderParameter PixelUVSize;
            FShaderParameter RadialDistortionCoefs;
            FShaderParameter TangentialDistortionCoefs;
            FShaderParameter DistortedCameraMatrix;
            FShaderParameter UndistortedCameraMatrix;
            FShaderParameter OutputMultiplyAndAdd;
    
        };
    
        class FLensDistortionUVGenerationVS : public FLensDistortionUVGenerationShader
        {
            DECLARE_SHADER_TYPE(FLensDistortionUVGenerationVS, Global);
    
        public:
    
            /** Default constructor. */
            FLensDistortionUVGenerationVS() {}
    
            /** Initialization constructor. */
            FLensDistortionUVGenerationVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
                :FLensDistortionUVGenerationShader(Initializer)
            {
            }
        };
    
        class FLensDistortionUVGenerationPS : public FLensDistortionUVGenerationShader
        {
            DECLARE_SHADER_TYPE(FLensDistortionUVGenerationPS, Global);
    
        public:
    
            /** Default constructor. */
            FLensDistortionUVGenerationPS() {}
    
            /** Initialization constructor. */
            FLensDistortionUVGenerationPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
                :FLensDistortionUVGenerationShader(Initializer)
            { }
        };
    
        IMPLEMENT_SHADER_TYPE(, FLensDistortionUVGenerationVS, TEXT("/Plugin/Foo/Private/MyShader.usf"), TEXT("MainVS"), SF_Vertex)
        IMPLEMENT_SHADER_TYPE(, FLensDistortionUVGenerationPS, TEXT("/Plugin/Foo/Private/MyShader.usf"), TEXT("MainPS"), SF_Pixel)
    
        static void DrawUVDisplacementToRenderTarget_RenderThread(
            FRHICommandListImmediate& RHICmdList,
            const FCompiledCameraModel& CompiledCameraModel,
            const FName& TextureRenderTargetName,
            FTextureRenderTargetResource* OutTextureRenderTargetResource,
            ERHIFeatureLevel::Type FeatureLevel)
        {
            check(IsInRenderingThread());
    
        #if WANTS_DRAW_MESH_EVENTS
            FString EventName;
            TextureRenderTargetName.ToString(EventName);
            SCOPED_DRAW_EVENTF(RHICmdList, SceneCapture, TEXT("LensDistortionDisplacementGeneration %s"), *EventName);
        #else
            SCOPED_DRAW_EVENT(RHICmdList, DrawUVDisplacementToRenderTarget_RenderThread);
        #endif
    
            // Set render target.(レンダー ターゲットを設定します。)
            SetRenderTarget(
                RHICmdList,
                OutTextureRenderTargetResource->GetRenderTargetTexture(),
                FTextureRHIRef(),
                ESimpleRenderTargetMode::EUninitializedColorAndDepth,
                FExclusiveDepthStencil::DepthNop_StencilNop);
    
            FIntPoint DisplacementMapResolution(OutTextureRenderTargetResource->GetSizeX(), OutTextureRenderTargetResource->GetSizeY());
    
            // Update viewport. (ビューポートを更新します。)
            RHICmdList.SetViewport(
                0, 0, 0.f,
                DisplacementMapResolution.X, DisplacementMapResolution.Y, 1.f);
    
            // Get shaders. (シェーダーを取得します。)
            TShaderMap<FGlobalShaderType>* GlobalShaderMap = GetGlobalShaderMap(FeatureLevel);
            TShaderMapRef< FLensDistortionUVGenerationVS > VertexShader(GlobalShaderMap);
            TShaderMapRef< FLensDistortionUVGenerationPS > PixelShader(GlobalShaderMap);
    
            // Set the graphic pipeline state. (グラフィック パイプライン ステートを設定します。)
            FGraphicsPipelineStateInitializer GraphicsPSOInit;
            RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
            GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
            GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
            GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI();
            GraphicsPSOInit.PrimitiveType = PT_TriangleList;
            GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4();
            GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader);
            GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader);
            SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
    
            // Update viewport. (ビューポートを更新します。)
            RHICmdList.SetViewport(
                0, 0, 0.f,
                OutTextureRenderTargetResource->GetSizeX(), OutTextureRenderTargetResource->GetSizeY(), 1.f);
    
            // Update shader uniform parameters. (シェーダー ユニフォーム パラメータを更新します。)
            VertexShader->SetParameters(RHICmdList, VertexShader->GetVertexShader(), CompiledCameraModel, DisplacementMapResolution);
            PixelShader->SetParameters(RHICmdList, PixelShader->GetPixelShader(), CompiledCameraModel, DisplacementMapResolution);
    
            // Draw grid. (グリッドを描画します。)
            uint32 PrimitiveCount = kGridSubdivisionX * kGridSubdivisionY * 2;
            RHICmdList.DrawPrimitive(PT_TriangleList, 0, PrimitiveCount, 1);
    
            // Resolve render target. (レンダー ターゲットを解決します。)
            RHICmdList.CopyToResolveTarget(
                OutTextureRenderTargetResource->GetRenderTargetTexture(),
                OutTextureRenderTargetResource->TextureRHI,
                false, FResolveParams());
        }
    
        FVector2D FFooCameraModel::UndistortNormalizedViewPosition(FVector2D EngineV) const
        {
            // Engine view space -> standard view space. (エンジン ビュー空間 -> 標準ビュー空間)
            FVector2D V = FVector2D(1, -1) * EngineV;
    
            FVector2D V2 = V * V;
            float R2 = V2.X + V2.Y;
    
            // Radial distortion (extra parenthesis to match MF_Undistortion.uasset).
            FVector2D UndistortedV = V * (1.0 + (R2 * K1 + (R2 * R2) * K2 + (R2 * R2 * R2) * K3));
    
            // Tangential distortion. (接線歪み)
            UndistortedV.X += P2 * (R2 + 2 * V2.X) + 2 * P1 * V.X * V.Y;
            UndistortedV.Y += P1 * (R2 + 2 * V2.Y) + 2 * P2 * V.X * V.Y;
    
            // Returns engine V. (エンジン V を返します。)
            return UndistortedV * FVector2D(1, -1);
        }
    
        /** Compiles the camera model. */
        float FFooCameraModel::GetUndistortOverscanFactor(
            float DistortedHorizontalFOV, float DistortedAspectRatio) const
        {
            // If the lens distortion model is identity, then early return 1. (レンズ歪みモデルが身元であれば1 を返します。)
            if (*this == FFooCameraModel())
            {
                return 1.0f;
            }
    
            float TanHalfDistortedHorizontalFOV = FMath::Tan(DistortedHorizontalFOV * 0.5f);
    
            // Get the position in the view space at z'=1 of different key point in the distorted Viewport UV coordinate system. (歪んだビューポート UV 座標系の別のキーポイントの z'=1 でビュー空間の位置を取得します。)
            // This very approximative to know the required overscan scale factor of the undistorted viewport, but works really well in practice. (歪みのないビューポートで必要な近似のオーバースキャン スケール係数になりますが、実際とてもうまく行きます。)
            //
            //  Undistorted UV position in the view space:
            //                 ^ View space's Y
            //                 |
            //        0        1        2
            //     
            //        7        0        3 --> View space's X
            //     
            //        6        5        4
            FVector2D UndistortCornerPos0 = LensUndistortViewportUVIntoViewSpace(
                *this, TanHalfDistortedHorizontalFOV, DistortedAspectRatio, FVector2D(0.0f, 0.0f));
            FVector2D UndistortCornerPos1 = LensUndistortViewportUVIntoViewSpace(
                *this, TanHalfDistortedHorizontalFOV, DistortedAspectRatio, FVector2D(0.5f, 0.0f));
            FVector2D UndistortCornerPos2 = LensUndistortViewportUVIntoViewSpace(
                *this, TanHalfDistortedHorizontalFOV, DistortedAspectRatio, FVector2D(1.0f, 0.0f));
            FVector2D UndistortCornerPos3 = LensUndistortViewportUVIntoViewSpace(
                *this, TanHalfDistortedHorizontalFOV, DistortedAspectRatio, FVector2D(1.0f, 0.5f));
            FVector2D UndistortCornerPos4 = LensUndistortViewportUVIntoViewSpace(
                *this, TanHalfDistortedHorizontalFOV, DistortedAspectRatio, FVector2D(1.0f, 1.0f));
            FVector2D UndistortCornerPos5 = LensUndistortViewportUVIntoViewSpace(
                *this, TanHalfDistortedHorizontalFOV, DistortedAspectRatio, FVector2D(0.5f, 1.0f));
            FVector2D UndistortCornerPos6 = LensUndistortViewportUVIntoViewSpace(
                *this, TanHalfDistortedHorizontalFOV, DistortedAspectRatio, FVector2D(0.0f, 1.0f));
            FVector2D UndistortCornerPos7 = LensUndistortViewportUVIntoViewSpace(
                *this, TanHalfDistortedHorizontalFOV, DistortedAspectRatio, FVector2D(0.0f, 0.5f));
    
            // Find min and max of the inner square of undistorted Viewport in the view space at z'=1. (z'=1 のビュー空間で歪んだビューポート内の最小と最大の正方形を求めます。)
            FVector2D MinInnerViewportRect;
            FVector2D MaxInnerViewportRect;
            MinInnerViewportRect.X = FMath::Max3(UndistortCornerPos0.X, UndistortCornerPos6.X, UndistortCornerPos7.X);
            MinInnerViewportRect.Y = FMath::Max3(UndistortCornerPos4.Y, UndistortCornerPos5.Y, UndistortCornerPos6.Y);
            MaxInnerViewportRect.X = FMath::Min3(UndistortCornerPos2.X, UndistortCornerPos3.X, UndistortCornerPos4.X);
            MaxInnerViewportRect.Y = FMath::Min3(UndistortCornerPos0.Y, UndistortCornerPos1.Y, UndistortCornerPos2.Y);
    
            check(MinInnerViewportRect.X < 0.f);
            check(MinInnerViewportRect.Y < 0.f);
            check(MaxInnerViewportRect.X > 0.f);
            check(MaxInnerViewportRect.Y > 0.f);
    
            // Compute tan(VerticalFOV * 0.5) (タンジェントを計算します(VerticalFOV * 0.5))
            float TanHalfDistortedVerticalFOV = TanHalfDistortedHorizontalFOV / DistortedAspectRatio;
    
            // Compute the required un-distorted viewport scale on each axis. (軸ごとに、必要となれる歪んでいないユーポート スケールを計算します。)
            FVector2D ViewportScaleUpFactorPerViewAxis = 0.5 * FVector2D(
                TanHalfDistortedHorizontalFOV / FMath::Max(-MinInnerViewportRect.X, MaxInnerViewportRect.X),
                TanHalfDistortedVerticalFOV / FMath::Max(-MinInnerViewportRect.Y, MaxInnerViewportRect.Y));
    
            // Scale up by 2% more the undistorted viewport size in the view space to work (作業するビュー空間で歪みのないビューポート サイズを 2% 拡大します。)
            // around the fact that odd undistorted positions might not exactly be at the minimal
            // in case of a tangential distorted barrel lens distortion.
            const float ViewportScaleUpConstMultiplier = 1.02f;
            return FMath::Max(ViewportScaleUpFactorPerViewAxis.X, ViewportScaleUpFactorPerViewAxis.Y) * ViewportScaleUpConstMultiplier;
        }
    
        void FFooCameraModel::DrawUVDisplacementToRenderTarget(
            UWorld* World,
            float DistortedHorizontalFOV,
            float DistortedAspectRatio,
            float UndistortOverscanFactor,
            UTextureRenderTarget2D* OutputRenderTarget,
            float OutputMultiply,
            float OutputAdd) const
        {
            check(IsInGameThread());
    
            // Compiles the camera model to know the overscan scale factor. (オーバースキャン スケール係数を出すためにカメラ モデルをコンパイルします。)
            float TanHalfUndistortedHorizontalFOV = FMath::Tan(DistortedHorizontalFOV * 0.5f) * UndistortOverscanFactor;
            float TanHalfUndistortedVerticalFOV = TanHalfUndistortedHorizontalFOV / DistortedAspectRatio;
    
            // Output.(出力)
            FCompiledCameraModel CompiledCameraModel;
            CompiledCameraModel.OriginalCameraModel = *this;
    
            CompiledCameraModel.DistortedCameraMatrix.X = 1.0f / TanHalfUndistortedHorizontalFOV;
            CompiledCameraModel.DistortedCameraMatrix.Y = 1.0f / TanHalfUndistortedVerticalFOV;
            CompiledCameraModel.DistortedCameraMatrix.Z = 0.5f;
            CompiledCameraModel.DistortedCameraMatrix.W = 0.5f;
    
            CompiledCameraModel.UndistortedCameraMatrix.X = F.X;
            CompiledCameraModel.UndistortedCameraMatrix.Y = F.Y * DistortedAspectRatio;
            CompiledCameraModel.UndistortedCameraMatrix.Z = C.X;
            CompiledCameraModel.UndistortedCameraMatrix.W = C.Y;
    
            CompiledCameraModel.OutputMultiplyAndAdd.X = OutputMultiply;
            CompiledCameraModel.OutputMultiplyAndAdd.Y = OutputAdd;
    
            const FName TextureRenderTargetName = OutputRenderTarget->GetFName();
            FTextureRenderTargetResource* TextureRenderTargetResource = OutputRenderTarget->GameThread_GetRenderTargetResource();
    
            ERHIFeatureLevel::Type FeatureLevel = World->Scene->GetFeatureLevel();
    
            ENQUEUE_RENDER_COMMAND(CaptureCommand)(
                [CompiledCameraModel, TextureRenderTargetResource, TextureRenderTargetName, FeatureLevel](FRHICommandListImmediate& RHICmdList)
                {
                    DrawUVDisplacementToRenderTarget_RenderThread(
                        RHICmdList,
                        CompiledCameraModel,
                        TextureRenderTargetName,
                        TextureRenderTargetResource,
                        FeatureLevel);
                }
            );
        }
  17. 最後に 「LensDistortionRendering.cpp」 ファイルの 155 行と 156 行の間を、以下の 2 行のコードに変更して、予め作成しておいた新しい MyShader.USF ファイルに指定します。

    Change:

    • IMPLEMENT_SHADER_TYPE(, FLensDistortionUVGenerationVS, TEXT("/Plugin/LensDistortion/Private/UVGeneration.usf"), TEXT("MainVS"), SF_Vertex)

    To:

    • IMPLEMENT_SHADER_TYPE(, FLensDistortionUVGenerationVS, TEXT("/Plugin/Foo/Private/MyShader.usf"), TEXT("MainVS"), SF_Vertex)

    Change:

    • IMPLEMENT_SHADER_TYPE(, FLensDistortionUVGenerationPS, TEXT("/Plugin/LensDistortion/Private/UVGeneration.usf"), TEXT("MainPS"), SF_Pixel)

    To:

    • IMPLEMENT_SHADER_TYPE(, FLensDistortionUVGenerationPS, TEXT("/Plugin/Foo/Private/MyShader.usf"), TEXT("MainPS"), SF_Pixel)

  18. 次に、「Foo/Source」 フォルダの 「Foo.Build.cs」 ファイルを開いて、Foo.Build.cs[PublicDependencyModuleNames.AddRange] セクションに以下のコードを追加します。

        PublicDependencyModuleNames.AddRange(
        new string[]
        {
            "Core",
            "RenderCore",
            "ShaderCore",
            "RHI",
            // ... add other public dependencies that you statically link with here ... ( ... ここと静的にリンクしている他のパブリック依存を追加します。)
        }
        );
  19. 次に Foo.Build.csPrivateDependencyModuleNames.AddRange セクションで、SlateSlateCore を削除します。すると 「Foo.Build.cs」 ファイルはこのようにないrます。

    // Copyright 1998-2018 Epic Games, Inc.All Rights Reserved.
    
    using UnrealBuildTool;
    
    public class Foo :ModuleRules
    {
        public Foo(ReadOnlyTargetRules Target) : base(Target)
        {
            PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
    
            PublicIncludePaths.AddRange(
                new string[] {
                    "Foo/Public"
                    // ... add public include paths required here ... (必要なパブリック インクルード パスをここ ... に追加します)
                }
                );    
            PrivateIncludePaths.AddRange(
                new string[] {
                    "Foo/Private",
                    // ... add other private include paths required here ... (その他の必要なプライベート インクルード パスをここ ... に追加します)
                }
                );
    
            PublicDependencyModuleNames.AddRange(
                new string[]
                {
                    "Core",
                    "RenderCore",
                    "ShaderCore",
                    "RHI",
                    // ... add other public dependencies that you statically link with here ... ( ... 静的にリンクしている他のパブリック依存をここに追加します。)
                }
                );
            PrivateDependencyModuleNames.AddRange(
                new string[]
                {
                    "CoreUObject",
                    "Engine",
                    // ... add private dependencies that you statically link with here ... ( ... 静的にリンクしている他のプライベート依存をここに追加します。)    
                }
                );
    
            DynamicallyLoadedModuleNames.AddRange(
                new string[]
                {
                    // ... add any modules that your module loads dynamically here ... (モジュールが動的にロードするモジュールをすべてここに追加します。)
                }
                );
        }
    }
  20. プロジェクトの Visual Studio ソリューション ファイルを再起動し、CRTL + 5 を押してプロジェクトを再コンパイルします。これが完了したら、F5 を押して UE4 エディタを起動します。

  21. UE4 エディタのロード処理が完了したら、[Edit] > [Plugins] から Plugins マネージャーを開きます。

    HT_ShadersInPlugins_08.png

  22. Plugins マネージャーを一番下までスクロールすると [Project] セクションがあります。そこに Plugin があります。

    HT_ShadersInPlugins_09.png

    プラグが有効になっていない場合、名前の横にあるチェックマーク ボックスをクリックすると UE4 エディタが再起動します。

  23. すべてそろっていることを確認するためには、Level ブループリントを開いてイベントグラフを右クリックし、検索ボックスに 「Foo」 と入力します。これが完了すると、Foo Camera カテゴリに追加されたすべてのアイテムを見ることができます。

    クリックしてフルサイズで表示

最終結果

これで Lense Distortion UE4 プラグインの新バージョンの再生成とコンパイルが無事完了しました。次のステップでは、この新しいグローバル シェーダーをブループリントから呼び出して、レンダー ターゲットをどのように変形するのか見てみましょう。

新しい Unreal Engine 4 ドキュメントサイトへようこそ!

あなたの声を私たちに伝えるフィードバックシステムを含め、様々な新機能について開発をおこなっています。まだ広く使える状態にはなっていないので、準備ができるまでは、ドキュメントフィードバックフォーラムで、このページについて、もしくは遭遇した問題について教えていただけると助かります。

新しいシステムが稼働した際にお知らせします。

フィードバックを送信