UE4笔记-底层基础和底层渲染相关记录备查
記錄一些UE4文檔以外編程相關的底層基礎的概念和使用方法,如GC和Gameplay,各種宏/配置項等說明和使用
備查
文檔:http://api.unrealengine.com/INT/Programming/index.html
Q. UE4 配置Game的默認UGameEngine類:
UGameEngine算是整個Game的入口類了(Editor模式時是UEditorEngine),
最初的Viewport的Layout都是通過GameEngine里進行生成的.
可不使用源碼版本的情況下,可通過繼承UGameEngine類,修改擴展初始化Game的初始化布局等功能:
step:
往DefaultEngine.ini的[/Script/Engine.Engine]下添加,如:
+GameEngine=/Script/BJShowEx.QGameEngine
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#(QTsingle-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 << ")
"; }
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++觸發時調用的假設:
#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:
DefaultToSelf 指定參數默認值為調用本函數類實例的self(類似于javascript的this,誰調用指向誰)
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; }
};
總結
以上是生活随笔為你收集整理的UE4笔记-底层基础和底层渲染相关记录备查的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux-正则表达式学习(精)
- 下一篇: 【linux基础】如何查看剩余电量