第一次在虚幻4上运用c++脚本。
项目名要用英文!
继承BlueprintFunctionLibrary父类才可以在蓝图中调用
static TArry
.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& 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 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 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&
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不起作用: