UE4 C++學習

第一次在虛幻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

A繞B旋轉C

 

 

 

SetFloatingPointPropertyValue不起作用:

SetFloatingPointPropertyValue_not work

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章