UE4筆記-底層基礎和底層渲染相關記錄備查


記錄一些UE4文檔以外編程相關的底層基礎的概念和使用方法,如GC和Gameplay,各種宏/配置項等說明和使用

備查

 

 文檔:http://api.unrealengine.com/INT/Programming/index.html

 

Q. UE4 第三人稱(SpringArm控制下)設置初始視口位置 :

 

 

 

 

 Q. UE4的委托和事件(Delegate):

  記一下,開發方便Copy.

  吐槽:UE4 的Delegate得定義宏又臭又長又多,C#的委托和事件不知道比UE4高到哪里去了!(UE5請務必砍掉從新實現!)

  快速索引:委托文檔:https://docs.unrealengine.com/en-US/Programming/UnrealArchitecture/Delegates/index.html

  概念:

    從設計模式上來說 多播Delegate就是 觀察者模式得實現,只不過C#集成到了語言特性上,剛好C#(QT single-slot)得方式 被UE4借鑒到了引擎里

    Q0:C++是怎么去實現委托的?

      鏈接:C++實現的類C# Delegate 參考: https://stackoverflow.com/questions/23973914/c-like-delegates-in-c

 

      實現委托的代碼:      

 

/* 代碼來着上述stackoverflow */
#include <algorithm>
#include <iostream>
#include <memory>
#include <utility>
#include <vector>

template <typename Signature>
struct delegate;

template <typename... Args>
struct delegate<void(Args...)>
{
    struct base
    {
        virtual ~base() {}
        virtual bool do_cmp(base* other) = 0;
        virtual void do_call(Args... args) = 0;
    };
    template <typename T>
    struct call : base
    {
        T d_callback;
        template <typename S>
        call(S&& callback) : d_callback(std::forward<S>(callback))
        {

        }

        bool do_cmp(base* other)
        {
            call<T>* tmp = dynamic_cast<call<T>*>(other);
            
            return tmp && this->d_callback == tmp->d_callback;
        }
        void do_call(Args... args)
        {
            return this->d_callback(std::forward<Args>(args)...);
        }
    };
    std::vector<std::unique_ptr<base>> d_callbacks;

    delegate(delegate const&) = delete;
    void operator=(delegate const&) = delete;
public:
    delegate()
    {

    }
    template <typename T>
    delegate& operator+= (T&& callback)
    {
        this->d_callbacks.emplace_back(new call<T>(std::forward<T>(callback)));
        return *this;
    }

    template <typename T>
    delegate& operator-= (T&& callback)
    {
        call<T> tmp(std::forward<T>(callback));
        auto it = std::remove_if(this->d_callbacks.begin(),
            this->d_callbacks.end(),
            [&](std::unique_ptr<base>& other) {
                return tmp.do_cmp(other.get());
            });
        this->d_callbacks.erase(it, this->d_callbacks.end());
        return *this;
    }

    void operator()(Args... args) 
    {
        for (auto& callback : this->d_callbacks) 
        {
            callback->do_call(args...);
        }
    }
};

// ----------------------------------------------------------------------------

template <typename RC, typename Class, typename... Args>
class member_call 
{
    Class* d_object;
    RC(Class::* d_member)(Args...);
public:
    member_call(Class* object, RC(Class::* member)(Args...))
        : d_object(object)
        , d_member(member) 
    {
    }

    RC operator()(Args... args) 
    {
        return (d_object->*d_member)(std::forward<Args>(args)...);
    }

    bool operator== (member_call const& other) const 
    {
        return (this->d_object == other.d_object) && (this->d_member == other.d_member);
    }

    bool operator!= (member_call const& other) const 
    {
        return !(*this == other);
    }
};

/**
* @prarms RC 返回類型, Class
**/
template <typename RC, typename Class, typename... Args>
member_call<RC, Class, Args...> mem_call(Class& object,
    RC(Class::* member)(Args...)) 
{
    return member_call<RC, Class, Args...>(&object, member);
}

// ----------------------------------------------------------------------------

void f(char const* str) { std::cout << "f(" << str << ")\n"; }
void g(char const* str) { std::cout << "g(" << str << ")\n"; }
void h(char const* str) { std::cout << "h(" << str << ")\n"; }

// ----------------------------------------------------------------------------

struct foo
{
    int d_id;
    explicit foo(int id) : d_id(id) 
    {

    }

    void bar(char const* str) 
    {
        std::cout << "foo(" << this->d_id << ")::bar(" << str << ")\n";
    }

    void cbs(char const* str) 
    {
        std::cout << "foo(" << this->d_id << ")::cbs(" << str << ")\n";
    }

};

// ----------------------------------------------------------------------------

int main()
{
    delegate<void(char const*)> d0;

    foo f0(0);
    foo f1(1);

    d0 += f;
    d0 += g;
    d0 += g;
    d0 += h;

    d0 += mem_call(f0, &foo::bar);
    d0 += mem_call(f0, &foo::cbs);
    d0 += mem_call(f1, &foo::bar);
    d0 += mem_call(f1, &foo::cbs);
    d0("first call");
    d0 -= g;
    d0 -= mem_call(f0, &foo::cbs);
    d0 -= mem_call(f1, &foo::bar);
    d0("second call");
}
View Code

      

      C++觸發時調用的假設:

#include <iostream>

class DemonstrateClass
{
public:
    int a = 10;
    //綁定函數
    void Func( std::string a) 
    {
        std::cout << "hi : [ "<< a << " ] " << std::endl;    
    }
};

/**
 *
 * Qt或UE4實現綁定成員函數核心調用代碼Demo:
 *
 **/
int main()
{
    // 假設 pa 為綁定對象
    DemonstrateClass* pa = new DemonstrateClass();

    // &DemonstrateClass::Func為綁定函數
    void(DemonstrateClass::* func_ref)(std::string) = &DemonstrateClass::Func;

    //委托觸發時,實際調用以下代碼
    (pa->*(func_ref))(" linqing demonstrate ");

    std::cout << "exam  complated....  " << std::endl;
}

 

  

    Q1.什么是單播委托/什么是多播委托/什么是事件:

      wait

    Q1.什么是動態委托:

      wait

 Q. UE4的Input全局鈎子,全局監聽鼠標鍵盤等外設輸入事件:

  方式一:

  可繼承GameViewportClient類實現

  

  例子(全局監聽鼠標左鍵並打印Log):

  .h:

UCLASS()
class BJ_YourProject_API UGameViewportClient_Demonstrate : public UGameViewportClient
{
    GENERATED_BODY()

public:
    UGameViewportClient_Demonstrate();
public:
    virtual EMouseCaptureMode CaptureMouseOnClick() override;

    /*
        輸入設備的全局鈎子函數
    */
    virtual bool InputKey
    (
        const FInputKeyEventArgs & EventArgs
    ) override;
};

 

.cpp

UGameViewportClient_Demonstrate::UGameViewportClient_Demonstrate()
{
}

EMouseCaptureMode UGameViewportClient_Demonstrate::CaptureMouseOnClick()
{
    UE_LOG(LogTemp, Log, TEXT("[GVC:] CaptureMouseOnClick"));
    return Super::CaptureMouseOnClick();
}

bool UGameViewportClient_Demonstrate::InputKey(const FInputKeyEventArgs & EventArgs)
{
    if (EKeys::LeftMouseButton == EventArgs.Key)
    {
        UE_LOG(LogTemp, Log, TEXT("[GVC:] InputKey is left mouse button"));
    }

    return Super::InputKey(EventArgs);
}

 

 

 

  最后在Editor中的Project Setttings里修改默認的GameViewportClient即可

  

 

 

 

 

 Q. UE4 關於 C++中使用或設置組件的自定義 Trace Response/Object Type的問題:

UE4關於這塊配置是用的枚舉映射.

 

自定義Collision:

打開Config/DefaultEngine.ini

在[/Script/Engine.CollisionProfile]下可以找到:

類似如:

的設置項.其中ECC_GameTraceChannel1就是映射的ECollisionChannel枚舉項:

C++例子:

        //因為QingResponse映射到ECC_GameTraceChannel1,所以這里修改的是 QingResponse的Collision值
        Dynamic_Com->SetCollisionResponseToChannel(ECollisionChannel::ECC_EngineTraceChannel1, ECollisionResponse::ECR_Block);

 

 

 Q. UE4 Skeletal Mesh模型 個別視角莫名消失隱藏的問題背后原因:

  問題:UE4的場景剔除優化渲染算法(可參考DX里的視錐體優化算法)引起的問題./UE4SketalMesh無法正常顯示可見

  剔除和遮擋的相關文檔:https://docs.unrealengine.com/en-US/Engine/Rendering/VisibilityCulling/VisibilityCullingReference/index.html

  解決:剔除算法在Skeletal Mesh上,用的是Physics Asset 的碰撞資源來做的運算的,把Physics Asset刷正確就OK。(也可以使用UE4 兩個 Precomputed Volume處理或關閉遮擋剔除)

 

 

 Q.UE4 Blueprint(藍圖) Template Function實現(藍圖中的模板函數實現):

  Meta文檔:https://docs.unrealengine.com/en-US/Programming/UnrealArchitecture/Reference/Metadata/index.html

  其實就是加meta標簽,只是官方的meta的說明文檔標簽不夠完善o(╥﹏╥)o

  具體的可以翻源碼里的ObjectMacros.h 頭文件查看標簽意義.

  這里順便記錄一下比較常用的Meta標簽:

 

  UFUNCTION:

  1. DefaultToSelf            指定參數默認值為調用本函數類實例的self(類似於javascript的this,誰調用指向誰)
  2. HidePin                指定BP里要隱藏成員參數,通常配合DefaultToSelf標簽一起食用

 

  解決:

  根據藍圖中傳入的類返回類的實例.

  可以參考SpawnActor的代碼實現.

  栗子:

    note:這是個 BPLibraryFunction類,所有聲明的static

    UFUNCTION(BlueprintCallable, meta = (DeterminesOutputType = "actorClass"))
          static class AActor* TestActor(class TSubclassOf<class AActor> actorClass);

 Q.UE4中使用dynamic_cast,編譯報錯問題.

  UE4 默認是關閉RTTI的,如果要使用dynamic_cast,需要在build.cs中啟用rtti;

  

 

using UnrealBuildTool;

public class MyAPP : ModuleRules
{
    public MyAPP(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
        bUseRTTI = true;
        bEnableExceptions = true;

        PublicDependencyModuleNames.AddRange(
            new string[] 
            {
               ""
            });

        PrivateDependencyModuleNames.AddRange(new string[] 
        {
               ""
        });
    }
}
    

 

Q.BP 藍圖宏 (Macros)和函數(functions)的區別:

  記錄一下 具體描述

  BP下的function不支持delay,AI Move to的等時間Latent型節點的,但是Macro支持.

  總體來說編譯上function是靜態編譯,而Macro就是c++的動態宏,是動態編譯的.

Q.跨平台相關宏:

  如果需要編寫平台相關的代碼段的話,需要使用宏來約定。

  跨平台相關的宏定義都在Platform.h里。

  例如:

#if PLATFORM_WINDOWS
    UE_LOG(LogTemp, Error, TEXT("hi ,windows"));
#elif PLATFORM_MAC
    UE_LOG(LogTemp, Error, TEXT("hi ,MAC"));
#endif

 

 

Q.關於C++使用LoadClass加載資源的路徑問題:

  一般平常加載Texture或mesh時,都是采用例如TEXT("/Game/Blueprints/MyMesh.MyMesh")的路徑形式,

  但是如果是用LoadClass加載BP類或UMG類的話需要在路徑后面加上_C的后綴:例如

LoadClass<UUserWidget>(NULL,TEXT("/Game/Blueprints/BaseWgt.BaseWgt_C"));

   文檔里沒有詳細介紹,但是這問題幾乎會困擾所有剛使用LoadClass這個函數小伙伴。

 

Q.保存游戲/應用信息到本地:

  USaveGame的應用:

  發現UE4已經寫了相關文檔,之前沒有找到:

  http://api.unrealengine.com/INT/Gameplay/SaveGame/index.html

 

Q.Struct 和Emum 類型的定義方式 :

UE4 基礎,但是不經常用總是忘記,做個筆記馬一下:

Note:雖然USTRUCT可以定義函數,但是不能加UFUNCTION 標簽喔

結構體:

USTRUCT(BlueprintType)
struct FData_PageInfo
{
    GENERATED_USTRUCT_BODY()

    FData_PageInfo();
    FData_PageInfo(UChildActorComponent *parent_Com);

    void reInit();

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "struct_Variants")
        class UChildActorComponent *Parent_Com;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "struct_Variants")
        class ACpp_PagerActor *PageActor;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "struct_Variants")
        class UChildActorComponent *FrontCanvas_Com;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "struct_Variants")
        class UChildActorComponent *BackCanvas_Com;
};

枚舉:

UENUM(BlueprintType)
enum class GroupActorState : uint8
{
    EM_Expand    UMETA(DisplayName = "Expand"),
    EM_Merge    UMETA(DisplayName = "Merge")
};

 Q.C++ DatatableRow的定義方式:(經常忘,留底Copy用):

#include "Runtime/Engine/Classes/Engine/DataTable.h"
#include "DTOData_AssetItem.generated.h"
USTRUCT(BlueprintType)
struct FDTOData_AssetItem : public FTableRowBase
{
    GENERATED_USTRUCT_BODY()
public:
    FDTOData_AssetItem()
    {
    }
public:

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FDTO_AssetItem")
        int Id = 0;
};

 

 

Q.C++ Interface 的定義方式 :(經常忘,留底Copy用)

UE4的interface 分藍圖可繼承和不可集成兩種:

文檔:http://api.unrealengine.com/CHN/Programming/UnrealArchitecture/Reference/Interfaces/

可繼承:

#include "CoreMinimal.h"
#include "Demonstrate.generated.h"
/**
 * 
 */

UINTERFACE(BlueprintType)
class BJ_3DDESIGNAPP_API UDemonstrate : public UInterface
{
    GENERATED_BODY()

};
class BJ_3DDESIGNAPP_API IDemonstrate
{
    GENERATED_BODY()
public:
    UFUNCTION(BlueprintImplementableEvent, Category = "Trigger Reaction")
        void Hi();
};

 不可繼承:

UINTERFACE(meta = (CannotImplementInterfaceInBlueprint) )
class BJ_3DDESIGNAPP_API UDemonstrateGameMode : public UInterface
{
    GENERATED_BODY()

};

class BJ_3DDESIGNAPP_API IDemonstrateGameMode
{
    GENERATED_BODY()
public :
    UFUNCTION(BlueprintCallable, Category = "IDemonstrateGameMode")
        virtual class ACppCharacter_Demonstrate * GetCurrentDemonstrateActor() const { return nullptr; }
};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM