UE4 RenderSource

UE4 RenderSource

UE4 渲染API重新封装了诸如OpenGL、D3D和Vulkan API。
在这里插入图片描述

渲染资源RenderResource

属于渲染线程的渲染资源。

/**
 * A rendering resource which is owned by the rendering thread.
 */
class RENDERCORE_API FRenderResource

初始化渲染资源

/**
 * Sends a message to the rendering thread to initialize a resource.
 * This is called in the game thread.
 */
 
extern RENDERCORE_API void BeginInitResource(FRenderResource* Resource);

void BeginInitResource(FRenderResource* Resource)
{
	ENQUEUE_RENDER_COMMAND(InitCommand)(
		[Resource](FRHICommandListImmediate& RHICmdList)
		{
			Resource->InitResource();
		});
}
void FRenderResource::InitResource()
{
	check(IsInRenderingThread());
	if (ListIndex == INDEX_NONE)
	{
		TArray<FRenderResource*>& ResourceList = GetResourceList();
		TArray<int32>& FreeIndicesList = GetFreeIndicesList();

		// If resource list is currently being iterated, new resources must be added to the end of the list, to ensure they're processed during the iteration
		// Otherwise empty slots in the list may be re-used for new resources
		int32 LocalListIndex = INDEX_NONE;
		if (FreeIndicesList.Num() > 0 && ResourceListIterationActive.GetValue() == 0)
		{
			LocalListIndex = FreeIndicesList.Pop();
			check(ResourceList[LocalListIndex] == nullptr);
			ResourceList[LocalListIndex] = this;
		}
		else
		{
			LocalListIndex = ResourceList.Add(this);
		}

		if (GIsRHIInitialized)
		{
			CSV_SCOPED_TIMING_STAT_EXCLUSIVE(InitRenderResource);
			InitDynamicRHI();
			InitRHI();
		}

		FPlatformMisc::MemoryBarrier(); // there are some multithreaded reads of ListIndex
		ListIndex = LocalListIndex;
	}
}
void FRenderResource::UpdateRHI()
{
	check(IsInRenderingThread());
	if(IsInitialized() && GIsRHIInitialized)
	{
		ReleaseRHI();
		ReleaseDynamicRHI();
		InitDynamicRHI();
		InitRHI();
	}
}
namespace
{
inline void InitOrUpdateResource(FRenderResource* Resource)
{
	if (!Resource->IsInitialized())
	{
		Resource->InitResource();
	}
	else
	{
		Resource->UpdateRHI();
	}
}
} // namespace

索引缓冲区(IBO)

/** Index Buffer */
class ENGINE_API FDynamicMeshIndexBuffer32 : public FIndexBuffer
{
public:
	TArray<uint32> Indices;

	virtual void InitRHI() override;
	//void UpdateRHI();
};

建立索引缓冲区

void FDynamicMeshIndexBuffer32::InitRHI()
{
   // create  the index buffer
	FRHIResourceCreateInfo CreateInfo;
	IndexBufferRHI = RHICreateIndexBuffer(sizeof(uint32), Indices.Num() * sizeof(uint32), BUF_Static, CreateInfo);

	// Copy the index data into the index buffer.
	void* Buffer = RHILockIndexBuffer(IndexBufferRHI, 0, Indices.Num() * sizeof(uint32), RLM_WriteOnly);
	FMemory::Memcpy(Buffer, Indices.GetData(), Indices.Num() * sizeof(uint32));
	RHIUnlockIndexBuffer(IndexBufferRHI);
}

使用

FDynamicMeshIndexBuffer32 IndexBuffer;
IndexBuffer.Indices.SetNum(Triangles.size());
FMemory::Memcpy(IndexBuffer.Indices.GetData(), Triangles.data(), Triangles.size() * sizeof(uint32));
BeginInitResource(&IndexBuffer);//invoke InitRHI
...准备其他数据...
SetupMeshBatch();

顶点位置缓冲区(VBO)

/** A vertex buffer of positions. */
class FPositionVertexBuffer : public FVertexBuffer

初始化

void FPositionVertexBuffer::InitRHI()
{
	VertexBufferRHI = CreateRHIBuffer_RenderThread();
	// we have decide to create the SRV based on GMaxRHIShaderPlatform because this is created once and shared between feature levels for editor preview.
	// Also check to see whether cpu access has been activated on the vertex data
	if (VertexBufferRHI)
	{
		// we have decide to create the SRV based on GMaxRHIShaderPlatform because this is created once and shared between feature levels for editor preview.
		bool bSRV = RHISupportsManualVertexFetch(GMaxRHIShaderPlatform) || IsGPUSkinCacheAvailable(GMaxRHIShaderPlatform);

		// When bAllowCPUAccess is true, the meshes is likely going to be used for Niagara to spawn particles on mesh surface.
		// And it can be the case for CPU *and* GPU access: no differenciation today. That is why we create a SRV in this case.
		// This also avoid setting lots of states on all the members of all the different buffers used by meshes. Follow up: https://jira.it.epicgames.net/browse/UE-69376.
		bSRV |= (VertexData && VertexData->GetAllowCPUAccess());
		if(bSRV)
		{
			// When VertexData is null, this buffer hasn't been streamed in yet. We still need to create a FRHIShaderResourceView which will be
			// cached in a vertex factory uniform buffer later. The nullptr tells the RHI that the SRV doesn't view on anything yet.
			PositionComponentSRV = RHICreateShaderResourceView(FShaderResourceViewInitializer(VertexData ? VertexBufferRHI : nullptr, PF_R32_FLOAT));
		}
	}
}

顶点缓冲区的数据的拷贝

void CopyGPUBufferLocked(FRHIVertexBuffer* rhiVertexBuffer, void* src, SIZE_T size)
{
	void* VertexBufferData = RHILockVertexBuffer(rhiVertexBuffer, 0, size, RLM_WriteOnly);
	FMemory::Memcpy(VertexBufferData, src, size);
	RHIUnlockVertexBuffer(rhiVertexBuffer);
}
CopyGPUBufferLocked(PositionVertexBuffer.VertexBufferRHI, PositionVertexBuffer.GetVertexData(),
						PositionVertexBuffer.GetNumVertices() * PositionVertexBuffer.GetStride());

顶点颜色缓冲区

/**
* A vertex buffer of colors.
*/
class FColorVertexBuffer : public FVertexBuffer

顶点切线空间和UV缓冲区

/** Vertex buffer for a static mesh LOD */
class FStaticMeshVertexBuffer : public FRenderResource

顶点工厂(VAO)

/**
 * A vertex factory which simply transforms explicit vertex attributes from local to world space.
 */
class ENGINE_API FLocalVertexFactory : public FVertexFactory

初始化顶点工厂InitVertexFactory

FLocalVertexFactory::FDataType Data;

PositionVertexBuffer.BindPositionVertexBuffer(&VertexFactory, Data);
StaticMeshVertexBuffer.BindTangentVertexBuffer(&VertexFactory, Data);
StaticMeshVertexBuffer.BindPackedTexCoordVertexBuffer(&VertexFactory, Data);

ColorVertexBuffer.BindColorVertexBuffer(&VertexFactory, Data);

VertexFactory.SetData(Data);

InitOrUpdateResource(&VertexFactory);

顶点工厂绑定顶点缓冲区

void FPositionVertexBuffer::BindPositionVertexBuffer(const FVertexFactory* VertexFactory, FStaticMeshDataType& StaticMeshData) const
{
	StaticMeshData.PositionComponent = FVertexStreamComponent(
		this,
		STRUCT_OFFSET(FPositionVertex, Position),
		GetStride(),
		VET_Float3
	);
	StaticMeshData.PositionComponentSRV = PositionComponentSRV;
}

void FColorVertexBuffer::BindColorVertexBuffer(const FVertexFactory* VertexFactory, FStaticMeshDataType& StaticMeshData) const
{
	if (GetNumVertices() == 0)
	{
		BindDefaultColorVertexBuffer(VertexFactory, StaticMeshData, NullBindStride::ZeroForDefaultBufferBind);
		return;
	}

	StaticMeshData.ColorComponentsSRV = ColorComponentsSRV;
	StaticMeshData.ColorIndexMask = ~0u;

	{	
		StaticMeshData.ColorComponent = FVertexStreamComponent(
			this,
			0,	// Struct offset to color
			GetStride(),
			VET_Color,
			EVertexStreamUsage::ManualFetch
		);
	}
}

绘制SetupMeshBatch

FMeshBatch MeshBatch;
//绑定VAO
MeshBatch.VertexFactory = &VertexFactory;

BatchElement.FirstIndex = 0;
BatchElement.IndexBuffer = &IndexBuffer;
BatchElement.NumPrimitives = IndexBuffer.Indices.Num() / 3;

BatchElement.MinVertexIndex = 0;

BatchElement.MaxVertexIndex = PositionVertexBuffer.GetNumVertices() - 1;

伪代码示例使用

FDynamicMeshIndexBuffer32 IndexBuffer;
	
FPositionVertexBuffer PositionVertexBuffer;
FColorVertexBuffer ColorVertexBuffer;

FStaticMeshVertexBuffer StaticMeshVertexBuffer;
FLocalVertexFactory VertexFactory;

//init index
IndexBuffer.Indices.SetNum(Triangles.size());
FMemory::Memcpy(IndexBuffer.Indices.GetData(), Triangles.data(),Triangles.size() * sizeof(uint32));

 //init position
int32 NumVertices;
int32 NumUVs ;


PositionVertexBuffer.Init(NumVertices);

for (int32 i = 0; i < NumVertices; ++i)
{
    const auto& vertex = *reinterpret_cast<const FVector*>(&Vertices[i]);
    PositionVertexBuffer.VertexPosition(i) = vertex;
}

// init color
ColorVertexBuffer.Init(NumVertices);
StaticMeshVertexBuffer.SetUseHighPrecisionTangentBasis(true);
// init tangent noraml uv
StaticMeshVertexBuffer.Init(NumVertices, NumUVs);
for (int32 i = 0; i < NumVertices; ++i)
{
    StaticMeshVertexBuffer.SetVertexTangents(i, FVector(0, 1, 0), FVector(1, 0, 0), FVector(0, 0, 1));

    for (int32 j = 0; j < NumUVs; ++j)
    {
    	StaticMeshVertexBuffer.SetVertexUV(i, j, FVector2D(0, 0));
    }

    ColorVertexBuffer.VertexColor(i) = FColor(0);
}

InitOrUpdateResource(&PositionVertexBuffer);
InitOrUpdateResource(&StaticMeshVertexBuffer);
InitOrUpdateResource(&ColorVertexBuffer);
BeginInitResource(&IndexBuffer);

InitVertexFactory();
InitOrUpdateResource(&VertexFactory);

//初次绘制
SetupMeshBatch();

//update position
for (int32 i = 0; i < NumVertices; ++i)
{
    const auto& vertex = *reinterpret_cast<const FVector*>(&Vertices[i]);
    PositionVertexBuffer.VertexPosition(i) = vertex;
}
//update tangent uv color
for (int32 i = 0; i < NumVertices; ++i)
{
    StaticMeshVertexBuffer.SetVertexTangents(i, FVector(0, 1, 0), FVector(1, 0, 0), FVector(0, 0, 1));

    for (int32 j = 0; j < NumUVs; ++j)
    {
    	StaticMeshVertexBuffer.SetVertexUV(i, j, FVector2D(0, 0));
    }

    ColorVertexBuffer.VertexColor(i) = FColor(0);
}
// copy pos to buffer
CopyGPUBufferLocked(PositionVertexBuffer.VertexBufferRHI, PositionVertexBuffer.GetVertexData(),
						PositionVertexBuffer.GetNumVertices() * PositionVertexBuffer.GetStride());
// copy color to buffer
CopyGPUBufferLocked(ColorVertexBuffer.VertexBufferRHI, ColorVertexBuffer.GetVertexData(),
						ColorVertexBuffer.GetNumVertices() * ColorVertexBuffer.GetStride());
// copy tanget to buffer
CopyGPUBufferLocked(StaticMeshVertexBuffer.TangentsVertexBuffer.VertexBufferRHI, StaticMeshVertexBuffer.GetTangentData(),
						StaticMeshVertexBuffer.GetTangentSize());
// copy tex to buffer
CopyGPUBufferLocked(StaticMeshVertexBuffer.TexCoordVertexBuffer.VertexBufferRHI, StaticMeshVertexBuffer.GetTexCoordData(),
						StaticMeshVertexBuffer.GetTexCoordSize());
//更新绘制
SetupMeshBatch();

//资源释放
PositionVertexBuffer.ReleaseResource();
StaticMeshVertexBuffer.ReleaseResource();
ColorVertexBuffer.ReleaseResource();
IndexBuffer.ReleaseResource();
VertexFactory.ReleaseResource();

参考文献

UE4 RenderSource

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值