ue4.24调通了shader文档

先上图,ue4.24调通了shader文档

ue4.24调通了shader文档

 

有几个感慨:

1,ue4文档不与时俱进,所以还要看源码或者例子。这个就是按照源码插件依葫芦画瓢进行的

2,shader加载时机,按照build.cs进行,要不会崩溃,启动编辑器之后才加载

3.蓝图要熟,因为要给蓝图用,所以,还要学学。

4,渲染到纹理是每帧进行,一开始忘了,所以没出来结果,event tick()

5,需要虚拟目录了,

 

6,虚拟目录后,vs和Ps找的shader文件,也不是真实的目录,而是逻辑层次(这点存疑,还需要看看)


IMPLEMENT_SHADER_TYPE(, FLensDistortionUVGenerationVS, TEXT("/Plugin/Foo/Private/UVGeneration.usf"), TEXT("MainVS"), SF_Vertex)
IMPLEMENT_SHADER_TYPE(, FLensDistortionUVGenerationPS, TEXT("/Plugin/Foo/Private/UVGeneration.usf"), TEXT("MainPS"), SF_Pixel)

先看看存放目录

ue4.24调通了shader文档

 

磨蹭了很长时间,发现蓝图不熟,以后还得慢慢学,

暴露给蓝图使用,类要用category标识,比如

        UFUNCTION(BlueprintPure, Category = "findMyFoo")
        static void GetUndistortOverscanFactor(
            const FFooCameraModel& CameraModel,
            float DistortedHorizontalFOV,
            float DistortedAspectRatio,
            float& UndistortOverscanFactor);

这个方法的Catetory是"findMyFoo",在蓝图中,输入"find"及以后的就可以智能弹出,能够找到。ue4.24调通了shader文档

 

但是结构体很诡异,我一开始用FooCameraModel,结果显示的ooCameraModel,用FFooCameraModel,才显示FooCameraModel,第一个F被吃了。
struct FOO_API FFooCameraModel
{

}..

ue4.24调通了shader文档

 

generate.h生成时,要用.uproject文件

ue4.24调通了shader文档

另外,为了显示是否正确生成,在ps上直接赋值红色。

蓝图设置上,

ue4.24调通了shader文档

最后,直接上源码了

 

Foo.h


#pragma once

#include "CoreMinimal.h"
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"


/**
* The public interface to this module
*/
class ILensDistortion : public IModuleInterface
{

public:

    /**
    * Singleton-like access to this module's interface.  This is just for convenience!
    * Beware of calling this during the shutdown phase, though.  Your module might have been unloaded already.
    *
    * @return Returns singleton instance, loading the module on demand if needed
    */
    static inline ILensDistortion& Get()
    {
        return FModuleManager::LoadModuleChecked< ILensDistortion >("Foo");
    }

    /**
    * Checks to see if this module is loaded and ready.  It is only valid to call Get() if IsAvailable() returns true.
    *
    * @return True if the module is loaded and ready to use
    */
    static inline bool IsAvailable()
    {
        return FModuleManager::Get().IsModuleLoaded("Foo");
    }
};

Foo.cpp

// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.

#include "Foo.h"
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
#include "Interfaces/IPluginManager.h"
#include "Misc/Paths.h"
#include "ShaderCore.h"


class FLensDistortion : public ILensDistortion
{
    /** IModuleInterface implementation */
    virtual void StartupModule() override;
    virtual void ShutdownModule() override;
};

IMPLEMENT_MODULE(FLensDistortion, Foo)


void FLensDistortion::StartupModule()
{
    FString PluginShaderDir = FPaths::Combine(IPluginManager::Get().FindPlugin(TEXT("Foo"))->GetBaseDir(), TEXT("Shaders"));
    AddShaderSourceDirectoryMapping(TEXT("/Plugin/Foo"), PluginShaderDir);
}


void FLensDistortion::ShutdownModule()
{
    // This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,
    // we call this function before unloading the module.
}


FooBlueprintFunctionLibrary.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "FooCameraModule.h"
#include "FooBlueprintFunctionLibrary.generated.h"

/**
 * 
 */

UCLASS(MinimalAPI, meta = (ScriptName = "FooFunctionLibrary"))
class UFooBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
    GENERATED_UCLASS_BODY()


        /** Returns the overscan factor required for the undistort rendering to avoid unrendered distorted pixels. */
        UFUNCTION(BlueprintPure, Category = "findMyFoo")
        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 = "findMyFoo", 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 (FFooCameraModel)", CompactNodeTitle = "==", Keywords = "== equal"), Category = "findMyFoo")
        static bool EqualEqual_CompareFFooCameraModels(
            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 (FFooCameraModel)", CompactNodeTitle = "!=", Keywords = "!= not equal"), Category = "findMyFoo")
        static bool NotEqual_CompareFFooCameraModels(
            const FFooCameraModel& A,
            const FFooCameraModel& B)
    {
        return A != B;
    }
};

FooBlueprintFunctionLibrary.cpp

 

// Fill out your copyright notice in the Description page of Project Settings.


#include "FooBlueprintFunctionLibrary.h"


UFooBlueprintFunctionLibrary::UFooBlueprintFunctionLibrary(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{ }


// static
void UFooBlueprintFunctionLibrary::GetUndistortOverscanFactor(
    const FFooCameraModel& CameraModel,
    float DistortedHorizontalFOV,
    float DistortedAspectRatio,
    float& UndistortOverscanFactor)
{
    UndistortOverscanFactor = CameraModel.GetUndistortOverscanFactor(DistortedHorizontalFOV, DistortedAspectRatio);
}


// static
void UFooBlueprintFunctionLibrary::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);
}
FooCameraModule.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "FooCameraModule.generated.h"
/**
 * 
 */
USTRUCT(BlueprintType)
struct FOO_API 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 = "findMyCameraModule")
        float K1;

    /** Radial parameter #2. */
    UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "findMyCameraModule")
        float K2;

    /** Radial parameter #3. */
    UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "findMyCameraModule")
        float K3;

    /** Tangential parameter #1. */
    UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "findMyCameraModule")
        float P1;

    /** Tangential parameter #2. */
    UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "findMyCameraModule")
        float P2;

    /** Camera matrix's Fx and Fy. */
    UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "findMyCameraModule")
        FVector2D F;

    /** Camera matrix's Cx and Cy. */
    UPROPERTY(Interp, EditAnywhere, BlueprintReadWrite, Category = "findMyCameraModule")
        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 into 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);
    }
};
FooCameraModule.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include  "FooCameraModule.h"

#include "Classes/Engine/TextureRenderTarget2D.h"
#include "Classes/Engine/World.h"
#include "GlobalShader.h"
#include "PipelineStateCache.h"
#include "RHIStaticStates.h"
#include "SceneUtils.h"
#include "SceneInterface.h"
#include "ShaderParameterUtils.h"
#include "Logging/MessageLog.h"
#include "Internationalization/Internationalization.h"
#include "shader.h"


static const uint32 kGridSubdivisionX = 32;
static const uint32 kGridSubdivisionY = 16;

#define LOCTEXT_NAMESPACE "FFooModule"

/**
* Internal intermediary structure derived from FLensDistortionCameraModel 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 ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
    {
        return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
    }

    static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
    {
        FGlobalShader::ModifyCompilationEnvironment(Parameters, 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/UVGeneration.usf"), TEXT("MainVS"), SF_Vertex)
IMPLEMENT_SHADER_TYPE(, FLensDistortionUVGenerationPS, TEXT("/Plugin/Foo/Private/UVGeneration.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

    FRHITexture2D* RenderTargetTexture = OutTextureRenderTargetResource->GetRenderTargetTexture();

    RHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, RenderTargetTexture);

    FRHIRenderPassInfo RPInfo(RenderTargetTexture, ERenderTargetActions::DontLoad_Store, OutTextureRenderTargetResource->TextureRHI);
    RHICmdList.BeginRenderPass(RPInfo, TEXT("DrawUVDisplacement"));
    {
        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(0, PrimitiveCount, 1);
    }
    RHICmdList.EndRenderPass();
}


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.
    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.
    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.
    // 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.
    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)
    float TanHalfDistortedVerticalFOV = TanHalfDistortedHorizontalFOV / DistortedAspectRatio;

    // Compute the required undistorted viewport scale on each axes.
    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
    // 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());

    if (!OutputRenderTarget)
    {
        FMessageLog("Blueprint").Warning(
            LOCTEXT("LensDistortionCameraModel_DrawUVDisplacementToRenderTarget",
                "DrawUVDisplacementToRenderTarget: Output render target is required."));
        return;
    }

    // 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);
    }
    );
}

#undef LOCTEXT_NAMESPACE

Foo.Build.cs

// Copyright 1998-2019 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[] {
                // ... add public include paths required here ...
                
                    "D:/install/ue4/UE_4.24/Engine/Source/Runtime/Engine/",
                    "D:/install/ue4/UE_4.24/Engine/Source/Runtime/RHI/",
                    "D:/install/ue4/UE_4.24/Engine/Source/Runtime/RenderCore/",
            }
            );
                
        
        PrivateIncludePaths.AddRange(
            new string[] {
                // ... add other private include paths required here ...
            }
            );


        PublicDependencyModuleNames.AddRange(
            new string[]
            {
                    "Core",
                    "CoreUObject",
                    "Engine",
                    "RHI",
                    "Engine",
                    "RenderCore",
                // ... add other public dependencies that you statically link with here ...
            }
            );

        PrivateDependencyModuleNames.AddRange(
            new string[]
            {
                    "Projects",
                // ... add private dependencies that you statically link with here ...
            }
            );


        DynamicallyLoadedModuleNames.AddRange(
            new string[]
            {
                // ... add any modules that your module loads dynamically here ...
            }
            );
    }
}
 

Foo.uplugin

{
    "FileVersion": 3,
    "Version": 1,
    "VersionName": "1.0",
    "FriendlyName": "Foo",
    "Description": "",
    "Category": "Other",
    "CreatedBy": "",
    "CreatedByURL": "",
    "DocsURL": "",
    "MarketplaceURL": "",
    "SupportURL": "",
    "CanContainContent": true,
    "IsBetaVersion": false,
    "IsExperimentalVersion": false,
    "Installed": false,
    "Modules": [
        {
            "Name": "Foo",
            "Type": "Runtime",
            "LoadingPhase": "PostConfigInit"
        }
    ]
}

 

UVGeneration.usf

 

// Copyright 1998-2019 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 displacment 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 passdown 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"
//#include "D:/install/ue4/UE_4.24/Engine/Shaders/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);
    OutColor = float4( 1.0, 0.0, 0.0, 1.0);
    //OutColor = float4( 0.0, 1.0, 0.0, 1.0);
}