第一次在虛幻4上運用c++腳本。
項目名要用英文!
繼承BlueprintFunctionLibrary父類纔可以在藍圖中調用
- UFUNCTION(BlueprintPure,Category=" ??")
- 繼承自UBlueprintFunctionLibrary類中,凡是具備BlueprintCallable屬性的UFUNTION即可在Blueprint中被調用
- 如果UFUNCTION還帶有BlueprintPure屬性,那麼意味着這個函數不會修改任何遊戲狀態,因此無需exec鏈的觸發(在Blueprint中體現爲沒有白線輸入),可以在任何時刻被調用獲取其結果,作爲隨時可被調用的全局函數,都需要被聲明成static函數
- Category:方法所屬類別
- //聲明一個靜態方法
static TArry<int32> RamdomizeIntArry(TArray<int32> inputArry)
.cpp文件中的方法要和.h文件中類所繼承的父類一樣,如下圖:
選擇DebugGame Editor進行調試
調試的時候最好關閉虛幻編輯器 容易出現奇怪的錯誤
藍圖調用數據表:
1.數據表用Excel即可建立,導出爲CSV格式。
2.在VS2013中定義結構體,代碼如下:
ue4中文版藍圖中Squence節點的中文叫序列
創建新的渲染代理:
1.創建一個繼承自PrimitiveComponent的C++組件類
2.頭文件與cpp如下:
#pragma once
#include "Engine.h"
#include "CoreMinimal.h"
#include "Components/PrimitiveComponent.h"
#include "UTestCustomComponent.generated.h"
UCLASS(meta=(BlueprintSpawnableComponent))
class UTestCustomComponent : public UPrimitiveComponent
{
GENERATED_BODY()
public :
virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
};
#include "UTestCustomComponent.h"
class FTestCustomComponentSceneProxy : public FPrimitiveSceneProxy
{
public :
FTestCustomComponentSceneProxy(UPrimitiveComponent* Component)
:FPrimitiveSceneProxy(Component) {}
virtual uint32 GetMemoryFootprint(void) const override {
return (sizeof(*this) + GetAllocatedSize());
}
virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, class FMeshElementCollector& Collector)const override
{
FBox TestDynamicBox = FBox(FVector(-100.0f), FVector(100.0f));
DrawWireBox(
Collector.GetPDI(0),
GetLocalToWorld(),
TestDynamicBox,
FLinearColor::Red,
ESceneDepthPriorityGroup::SDPG_Foreground,
10.0f);
}
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView * View)const override
{
FPrimitiveViewRelevance Result;
Result.bDrawRelevance = IsShown(View);
Result.bDynamicRelevance = true;
Result.bShadowRelevance = IsShadowCast(View);
Result.bEditorPrimitiveRelevance = UseEditorCompositing(View);
return Result;
}
};
FPrimitiveSceneProxy* UTestCustomComponent :: CreateSceneProxy()
{
return new FTestCustomComponentSceneProxy(this);
}
實現結果如下:
總結:vs容易誤報錯誤,其實編譯可以通過,如下:
編譯之後錯誤會消失。
創建靜態渲染代理:
1.build.cs文件中引入新模塊:
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "Slate","SlateCore","InputCore", "HeadMountedDisplay" ,"RenderCore","ShaderCore","RHI"
});
2.cpp文件如下:
// Fill out your copyright notice in the Description page of Project Settings.
#include "UTestCustomComponent.h"
#include "DynamicMeshBuilder.h"
/*Vertex Buffer*/
class FTestCustomComponentVertexBuffer : public FVertexBuffer
{
public:
TArray<FDynamicMeshVertex> Vertices;
virtual void InitRHI() override
{
FRHIResourceCreateInfo CreateInfo;
void* VertexBufferData = nullptr;
VertexBufferRHI = RHICreateAndLockVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), BUF_Static, CreateInfo, VertexBufferData);
FMemory::Memcpy(VertexBufferData, Vertices.GetData(), Vertices.Num() * sizeof(FDynamicMeshVertex));
RHIUnlockVertexBuffer(VertexBufferRHI);
}
};
/*Index Buffer*/
class FTestCustomComponentIndexBuffer : public FIndexBuffer
{
public :
TArray<int32> Indices;
virtual void InitRHI() override
{
FRHIResourceCreateInfo CreateInfo;
IndexBufferRHI = RHICreateIndexBuffer(sizeof(int32), Indices.Num() * sizeof(int32), BUF_Static, CreateInfo);
void* Buffer = RHILockIndexBuffer(IndexBufferRHI, 0, Indices.Num() * sizeof(int32), RLM_WriteOnly);
FMemory::Memcpy(Buffer, Indices.GetData(), Indices.Num() * sizeof(int32));
RHIUnlockIndexBuffer(IndexBufferRHI);
}
};
/*Vertex Factory*/
class FTestCustomComponentVertexFactory : public FLocalVertexFactory
{
public:
FTestCustomComponentVertexFactory()
{ }
/*Initialization*/
void Init(const FTestCustomComponentVertexBuffer* VertexBuffer)
{
if (IsInRenderingThread())
{
//Initialize the vertex factory'sstream components
DataType NewData;
NewData.PositionComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, Position, VET_Float3);
NewData.TextureCoordinates.Add(FVertexStreamComponent(VertexBuffer, STRUCT_OFFSET(FDynamicMeshVertex, TextureCoordinate), sizeof(FDynamicMeshVertex), VET_Float2));
NewData.TangentBasisComponents[0] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer,
FDynamicMeshVertex, TangentX, VET_PackedNormal);
NewData.TangentBasisComponents[1] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer,
FDynamicMeshVertex, TangentZ, VET_PackedNormal);
SetData(NewData);
}
else
{
ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
InitTestCustomComponentVertexFactor,
FTestCustomComponentVertexFactory*, VertexFactory, this, const FTestCustomComponentVertexBuffer*, VertexBuffer, VertexBuffer,
{
//Initialize the vertex factory's stream componnents,
DataType NewData;
NewData.PositionComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(
VertexBuffer, FDynamicMeshVertex, Position, VET_Float3);
NewData.TextureCoordinates.Add(FVertexStreamComponent(VertexBuffer, STRUCT_OFFSET(FDynamicMeshVertex, TextureCoordinate), sizeof(FDynamicMeshVertex), VET_Float2));
NewData.TangentBasisComponents[0] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer,
FDynamicMeshVertex, TangentX, VET_PackedNormal);
NewData.TangentBasisComponents[1] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer,
FDynamicMeshVertex, TangentZ, VET_PackedNormal);
VertexFactory->SetData(NewData);
});
}
}
};
class FTestCustomComponentSceneProxy : public FPrimitiveSceneProxy
{
public :
FTestCustomComponentIndexBuffer IndexBuffer;
FTestCustomComponentVertexBuffer VertexBuffer;
FTestCustomComponentVertexFactory VertexFactory;
public :
FTestCustomComponentSceneProxy(UPrimitiveComponent* Component)
:FPrimitiveSceneProxy(Component)
{
const float BoxSize = 100.0f;
//填充頂點
VertexBuffer.Vertices.Add(FVector(0.0F));
VertexBuffer.Vertices.Add(FVector(BoxSize, 0.0f, 0.0f));
VertexBuffer.Vertices.Add(FVector(0.0f, BoxSize, 0.0f));
VertexBuffer.Vertices.Add(FVector(0.0f, 0.0f, BoxSize));
//填充索引
/*IndexBuffer.Indices.Add(0);
IndexBuffer.Indices.Add(1);
IndexBuffer.Indices.Add(2);
*/
IndexBuffer.Indices.Add(0);
IndexBuffer.Indices.Add(2);
IndexBuffer.Indices.Add(3);
IndexBuffer.Indices.Add(0);
IndexBuffer.Indices.Add(3);
IndexBuffer.Indices.Add(1);
/*IndexBuffer.Indices.Add(3);
IndexBuffer.Indices.Add(2);
IndexBuffer.Indices.Add(1);
*/
//初始化
VertexFactory.Init(&VertexBuffer);
BeginInitResource(&IndexBuffer);
BeginInitResource(&VertexBuffer);
BeginInitResource(&VertexFactory);
}
virtual ~FTestCustomComponentSceneProxy()
{
VertexBuffer.ReleaseResource();
IndexBuffer.ReleaseResource();
VertexFactory.ReleaseResource();
}
virtual uint32 GetMemoryFootprint(void) const override
{
return (sizeof(*this) + GetAllocatedSize());
}
virtual void GetDynamicMeshElements(const TArray<const FSceneView*>&
Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, class FMeshElementCollector &Collector) const override
{
FBox TestDynamicBox = FBox(FVector(-100.0f), FVector(100.0f));
DrawWireBox(
Collector.GetPDI(0),
GetLocalToWorld(),
TestDynamicBox,
FLinearColor::Black,
ESceneDepthPriorityGroup::SDPG_Foreground,
10.0f
);
}
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView*View)const override
{
FPrimitiveViewRelevance Result;
Result.bDrawRelevance =true;
Result.bStaticRelevance = true;
Result.bDynamicRelevance = true;
return Result;
}
virtual void DrawStaticElements(FStaticPrimitiveDrawInterface*PDI)override
{
FMeshBatch Mesh;
FMeshBatchElement& BatchElement = Mesh.Elements[0];
BatchElement.IndexBuffer = &IndexBuffer;
Mesh.bWireframe = false;
Mesh.VertexFactory = &VertexFactory;
Mesh.MaterialRenderProxy = UMaterial::GetDefaultMaterial(MD_Surface)
->GetRenderProxy(false);
//Mesh->SetMaterial(0,);
BatchElement.PrimitiveUniformBuffer = CreatePrimitiveUniformBufferImmediate(GetLocalToWorld(), GetBounds()
, GetLocalBounds(), true, UseEditorDepthTest());
BatchElement.FirstIndex = 0;
BatchElement.NumPrimitives = IndexBuffer.Indices.Num() / 3;
BatchElement.MinVertexIndex = 0;
BatchElement.MaxVertexIndex = VertexBuffer.Vertices.Num() - 1;
Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative();
Mesh.Type = PT_TriangleList;
Mesh.DepthPriorityGroup = SDPG_Foreground;
Mesh.bCanApplyViewModeOverrides = false;
Mesh.bDisableBackfaceCulling = false;
PDI->DrawMesh(Mesh, 1.0f);
}
};
FPrimitiveSceneProxy* UTestCustomComponent :: CreateSceneProxy()
{
return new FTestCustomComponentSceneProxy(this);
}
效果如下:
在上一節的基礎上繪製了一個靜態模型,本來是一個三棱錐,被我改成了兩個三角面,,基本上了解了通過c++繪製靜態模型與動態模型的流程,但是依然無法做到修改靜態模型的材質,達到雙面顯示的目的,有待學習。
瞭解瞭如何通過頂點緩衝區和索引緩衝區繪製模型的原理:
const float BoxSize = 100.0f;
//填充頂點
VertexBuffer.Vertices.Add(FVector(0.0F));
VertexBuffer.Vertices.Add(FVector(BoxSize, 0.0f, 0.0f));
VertexBuffer.Vertices.Add(FVector(0.0f, BoxSize, 0.0f));
VertexBuffer.Vertices.Add(FVector(0.0f, 0.0f, BoxSize));
上一段代碼定義了四個頂點,索引分別爲0,1,2,3.
//填充索引
IndexBuffer.Indices.Add(0);
IndexBuffer.Indices.Add(1);
IndexBuffer.Indices.Add(2);
IndexBuffer.Indices.Add(0);
IndexBuffer.Indices.Add(2);
IndexBuffer.Indices.Add(3);
IndexBuffer.Indices.Add(0);
IndexBuffer.Indices.Add(3);
IndexBuffer.Indices.Add(1);
IndexBuffer.Indices.Add(3);
IndexBuffer.Indices.Add(2);
IndexBuffer.Indices.Add(1);
上一段代碼通過索引來定義了四個面並存儲在了索引緩衝區中。
Mesh.MaterialRenderProxy = UMaterial::GetDefaultMaterial(MD_Surface)
->GetRenderProxy(false);
上一段代碼定義了靜態模型的材質,暫時還不知道怎麼修改。
A繞B旋轉C
SetFloatingPointPropertyValue不起作用: