UE4笔记-底层基础和底层渲染相关记录备查
記錄一些UE4文檔以外編程相關(guān)的底層基礎(chǔ)的概念和使用方法,如GC和Gameplay,各種宏/配置項(xiàng)等說明和使用
備查
文檔:http://api.unrealengine.com/INT/Programming/index.html
Q. UE4 配置Game的默認(rèn)UGameEngine類:
UGameEngine算是整個(gè)Game的入口類了(Editor模式時(shí)是UEditorEngine),
最初的Viewport的Layout都是通過GameEngine里進(jìn)行生成的.
可不使用源碼版本的情況下,可通過繼承UGameEngine類,修改擴(kuò)展初始化Game的初始化布局等功能:
step:
往DefaultEngine.ini的[/Script/Engine.Engine]下添加,如:
+GameEngine=/Script/BJShowEx.QGameEngine
Q. UE4 第三人稱(SpringArm控制下)設(shè)置初始視口位置 :
Q. UE4的委托和事件(Delegate):
記一下,開發(fā)方便Copy.
吐槽:UE4 的Delegate得定義宏又臭又長又多,C#的委托和事件不知道比UE4高到哪里去了!(UE5請務(wù)必砍掉從新實(shí)現(xiàn)!)
快速索引:委托文檔:https://docs.unrealengine.com/en-US/Programming/UnrealArchitecture/Delegates/index.html
概念:
從設(shè)計(jì)模式上來說 多播Delegate就是 觀察者模式得實(shí)現(xiàn),只不過C#集成到了語言特性上,剛好C#(QTsingle-slot)得方式 被UE4借鑒到了引擎里
Q0:C++是怎么去實(shí)現(xiàn)委托的?
鏈接:C++實(shí)現(xiàn)的類C# Delegate 參考:https://stackoverflow.com/questions/23973914/c-like-delegates-in-c
實(shí)現(xiàn)委托的代碼:
/* 代碼來著上述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 << ")
"; }
void g(char const* str) { std::cout << "g(" << str << ")
"; }
void h(char const* str) { std::cout << "h(" << str << ")
"; }
// ----------------------------------------------------------------------------
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 << ")
";
}
void cbs(char const* str)
{
std::cout << "foo(" << this->d_id << ")::cbs(" << str << ")
";
}
};
// ----------------------------------------------------------------------------
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++觸發(fā)時(shí)調(diào)用的假設(shè):
#include <iostream>
class DemonstrateClass
{
public:
int a = 10;
//綁定函數(shù)
void Func( std::string a)
{
std::cout << "hi : [ "<< a << " ] " << std::endl;
}
};
/**
*
* Qt或UE4實(shí)現(xiàn)綁定成員函數(shù)核心調(diào)用代碼Demo:
*
**/
int main()
{
// 假設(shè) pa 為綁定對(duì)象
DemonstrateClass* pa = new DemonstrateClass();
// &DemonstrateClass::Func為綁定函數(shù)
void(DemonstrateClass::* func_ref)(std::string) = &DemonstrateClass::Func;
//委托觸發(fā)時(shí),實(shí)際調(diào)用以下代碼
(pa->*(func_ref))(" linqing demonstrate ");
std::cout << "exam complated.... " << std::endl;
}
Q1.什么是單播委托/什么是多播委托/什么是事件:
wait
Q1.什么是動(dòng)態(tài)委托:
wait
Q. UE4的Input全局鉤子,全局監(jiān)聽鼠標(biāo)鍵盤等外設(shè)輸入事件:
方式一:
可繼承GameViewportClient類實(shí)現(xiàn)
例子(全局監(jiān)聽鼠標(biāo)左鍵并打印Log):
.h:
UCLASS()
class BJ_YourProject_API UGameViewportClient_Demonstrate : public UGameViewportClient
{
GENERATED_BODY()
public:
UGameViewportClient_Demonstrate();
public:
virtual EMouseCaptureMode CaptureMouseOnClick() override;
/*
輸入設(shè)備的全局鉤子函數(shù)
*/
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里修改默認(rèn)的GameViewportClient即可
Q. UE4 關(guān)于 C++中使用或設(shè)置組件的自定義 Trace Response/Object Type的問題:
UE4關(guān)于這塊配置是用的枚舉映射.
自定義Collision:
打開Config/DefaultEngine.ini
在[/Script/Engine.CollisionProfile]下可以找到:
類似如:
的設(shè)置項(xiàng).其中ECC_GameTraceChannel1就是映射的ECollisionChannel枚舉項(xiàng):
C++例子:
//因?yàn)镼ingResponse映射到ECC_GameTraceChannel1,所以這里修改的是 QingResponse的Collision值
Dynamic_Com->SetCollisionResponseToChannel(ECollisionChannel::ECC_EngineTraceChannel1, ECollisionResponse::ECR_Block);
Q. UE4 Skeletal Mesh模型 個(gè)別視角莫名消失隱藏的問題背后原因:
問題:UE4的場景剔除優(yōu)化渲染算法(可參考DX里的視錐體優(yōu)化算法)引起的問題./UE4SketalMesh無法正常顯示可見
剔除和遮擋的相關(guān)文檔:https://docs.unrealengine.com/en-US/Engine/Rendering/VisibilityCulling/VisibilityCullingReference/index.html
解決:剔除算法在Skeletal Mesh上,用的是Physics Asset 的碰撞資源來做的運(yùn)算的,把Physics Asset刷正確就OK。(也可以使用UE4 兩個(gè) Precomputed Volume處理或關(guān)閉遮擋剔除)
Q.UE4 Blueprint(藍(lán)圖) Template Function實(shí)現(xiàn)(藍(lán)圖中的模板函數(shù)實(shí)現(xiàn)):
Meta文檔:https://docs.unrealengine.com/en-US/Programming/UnrealArchitecture/Reference/Metadata/index.html
其實(shí)就是加meta標(biāo)簽,只是官方的meta的說明文檔標(biāo)簽不夠完善o(╥﹏╥)o
具體的可以翻源碼里的ObjectMacros.h 頭文件查看標(biāo)簽意義.
這里順便記錄一下比較常用的Meta標(biāo)簽:
UFUNCTION:
DefaultToSelf 指定參數(shù)默認(rèn)值為調(diào)用本函數(shù)類實(shí)例的self(類似于javascript的this,誰調(diào)用指向誰)
HidePin 指定BP里要隱藏成員參數(shù),通常配合DefaultToSelf標(biāo)簽一起食用
解決:
根據(jù)藍(lán)圖中傳入的類返回類的實(shí)例.
可以參考SpawnActor的代碼實(shí)現(xiàn).
栗子:
note:這是個(gè) BPLibraryFunction類,所有聲明的static
UFUNCTION(BlueprintCallable, meta = (DeterminesOutputType = "actorClass"))
static class AActor* TestActor(class TSubclassOf<class AActor> actorClass);
Q.UE4中使用dynamic_cast,編譯報(bào)錯(cuò)問題.
UE4 默認(rèn)是關(guān)閉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藍(lán)圖宏(Macros)和函數(shù)(functions)的區(qū)別:
記錄一下具體描述
BP下的function不支持delay,AI Move to的等時(shí)間Latent型節(jié)點(diǎn)的,但是Macro支持.
總體來說編譯上function是靜態(tài)編譯,而Macro就是c++的動(dòng)態(tài)宏,是動(dòng)態(tài)編譯的.
Q.跨平臺(tái)相關(guān)宏:
如果需要編寫平臺(tái)相關(guān)的代碼段的話,需要使用宏來約定。
跨平臺(tái)相關(guān)的宏定義都在Platform.h里。
例如:
#if PLATFORM_WINDOWS
UE_LOG(LogTemp, Error, TEXT("hi ,windows"));
#elif PLATFORM_MAC
UE_LOG(LogTemp, Error, TEXT("hi ,MAC"));
#endif
Q.關(guān)于C++使用LoadClass加載資源的路徑問題:
一般平常加載Texture或mesh時(shí),都是采用例如TEXT("/Game/Blueprints/MyMesh.MyMesh")的路徑形式,
但是如果是用LoadClass加載BP類或UMG類的話需要在路徑后面加上_C的后綴:例如
LoadClass<UUserWidget>(NULL,TEXT("/Game/Blueprints/BaseWgt.BaseWgt_C"));
文檔里沒有詳細(xì)介紹,但是這問題幾乎會(huì)困擾所有剛使用LoadClass這個(gè)函數(shù)小伙伴。
Q.保存游戲/應(yīng)用信息到本地:
USaveGame的應(yīng)用:
發(fā)現(xiàn)UE4已經(jīng)寫了相關(guān)文檔,之前沒有找到:
http://api.unrealengine.com/INT/Gameplay/SaveGame/index.html
Q.Struct 和Emum 類型的定義方式 :
UE4 基礎(chǔ),但是不經(jīng)常用總是忘記,做個(gè)筆記馬一下:
Note:雖然USTRUCT可以定義函數(shù),但是不能加UFUNCTION 標(biāo)簽喔
結(jié)構(gòu)體:
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的定義方式:(經(jīng)常忘,留底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 的定義方式 :(經(jīng)常忘,留底Copy用)
UE4的interface 分藍(lán)圖可繼承和不可集成兩種:
文檔: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; }
};
總結(jié)
以上是生活随笔為你收集整理的UE4笔记-底层基础和底层渲染相关记录备查的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux-正则表达式学习(精)
- 下一篇: 【linux基础】如何查看剩余电量