// FRenderResource interface. virtual void InitRHI() override { uint32 TextureStride = sizeof(FVector2D); EPixelFormat TextureFormat = PF_G32R32F; if (Use16bitTexCoord) { TextureStride = sizeof(FVector2DHalf); TextureFormat = PF_G16R16F; } if (!buffersAllocated) { PositionBuffer.VertexBufferRHI = AllocVertexBuffer(sizeof(FVector), Vertices.Num()); TangentBuffer.VertexBufferRHI = AllocVertexBuffer(sizeof(FPackedNormal), 2 * Vertices.Num()); TexCoordBuffer.VertexBufferRHI = AllocVertexBuffer(TextureStride, NumTexCoords * Vertices.Num()); ColorBuffer.VertexBufferRHI = AllocVertexBuffer(sizeof(FColor), Vertices.Num()); TangentBufferSRV = RHICreateShaderResourceView(TangentBuffer.VertexBufferRHI, 4, PF_R8G8B8A8); TexCoordBufferSRV = RHICreateShaderResourceView(TexCoordBuffer.VertexBufferRHI, TextureStride, TextureFormat); ColorBufferSRV = RHICreateShaderResourceView(ColorBuffer.VertexBufferRHI, 4, PF_R8G8B8A8); PositionBufferSRV = RHICreateShaderResourceView(PositionBuffer.VertexBufferRHI, sizeof(float), PF_R32_FLOAT); buffersAllocated = true; } void* TexCoordBufferData = RHILockVertexBuffer(TexCoordBuffer.VertexBufferRHI, 0, NumTexCoords * TextureStride * Vertices.Num(), RLM_WriteOnly); FVector2D* TexCoordBufferData32 = !Use16bitTexCoord ? static_cast<FVector2D*>(TexCoordBufferData) : nullptr; FVector2DHalf* TexCoordBufferData16 = Use16bitTexCoord ? static_cast<FVector2DHalf*>(TexCoordBufferData) : nullptr; // Copy the vertex data into the vertex buffers. FVector* PositionBufferData = static_cast<FVector*>(RHILockVertexBuffer(PositionBuffer.VertexBufferRHI, 0, sizeof(FVector) * Vertices.Num(), RLM_WriteOnly)); FPackedNormal* TangentBufferData = static_cast<FPackedNormal*>(RHILockVertexBuffer(TangentBuffer.VertexBufferRHI, 0, 2 * sizeof(FPackedNormal) * Vertices.Num(), RLM_WriteOnly)); FColor* ColorBufferData = static_cast<FColor*>(RHILockVertexBuffer(ColorBuffer.VertexBufferRHI, 0, sizeof(FColor) * Vertices.Num(), RLM_WriteOnly)); for (int32 i = 0; i < Vertices.Num(); i++) { PositionBufferData[i] = Vertices[i].Position; TangentBufferData[2 * i + 0] = Vertices[i].TangentX; TangentBufferData[2 * i + 1] = Vertices[i].TangentZ; ColorBufferData[i] = Vertices[i].Color; for (uint32 j = 0; j < NumTexCoords; j++) { if (Use16bitTexCoord) { TexCoordBufferData16[NumTexCoords * i + j] = FVector2DHalf(Vertices[i].TextureCoordinate[j]); } else { TexCoordBufferData32[NumTexCoords * i + j] = Vertices[i].TextureCoordinate[j]; } } } RHIUnlockVertexBuffer(PositionBuffer.VertexBufferRHI); RHIUnlockVertexBuffer(TangentBuffer.VertexBufferRHI); RHIUnlockVertexBuffer(TexCoordBuffer.VertexBufferRHI); RHIUnlockVertexBuffer(ColorBuffer.VertexBufferRHI); }
/*----------------------------------------------------------------------------- TGPUSkinAPEXClothVertexFactory::ClothShaderType -----------------------------------------------------------------------------*/ void FGPUBaseSkinAPEXClothVertexFactory::ClothShaderType::UpdateClothSimulData(const TArray<FVector4>& InSimulPositions, const TArray<FVector4>& InSimulNormals) { uint32 NumSimulVerts = InSimulPositions.Num(); if (GRHIFeatureLevel_DEPRECATED >= ERHIFeatureLevel::SM4) { FMath::Min(NumSimulVerts, (uint32)MAX_APEXCLOTH_VERTICES_FOR_VB); uint32 VectorArraySize = NumSimulVerts * sizeof(FVector4); uint32 PooledArraySize = ClothSimulDataBufferPool.PooledSizeForCreationArguments(VectorArraySize); if(!IsValidRef(ClothSimulPositionBuffer) || PooledArraySize != ClothSimulPositionBuffer.VertexBufferRHI->GetSize()) { if(IsValidRef(ClothSimulPositionBuffer)) { ClothSimulDataBufferPool.ReleasePooledResource(ClothSimulPositionBuffer); } ClothSimulPositionBuffer = ClothSimulDataBufferPool.CreatePooledResource(VectorArraySize); check(IsValidRef(ClothSimulPositionBuffer)); } if(!IsValidRef(ClothSimulNormalBuffer) || PooledArraySize != ClothSimulNormalBuffer.VertexBufferRHI->GetSize()) { if(IsValidRef(ClothSimulNormalBuffer)) { ClothSimulDataBufferPool.ReleasePooledResource(ClothSimulNormalBuffer); } ClothSimulNormalBuffer = ClothSimulDataBufferPool.CreatePooledResource(VectorArraySize); check(IsValidRef(ClothSimulNormalBuffer)); } if(NumSimulVerts) { float* Data = (float*)RHILockVertexBuffer(ClothSimulPositionBuffer.VertexBufferRHI, 0, VectorArraySize, RLM_WriteOnly); checkSlow(Data); FMemory::Memcpy(Data, InSimulPositions.GetData(), NumSimulVerts * sizeof(FVector4)); RHIUnlockVertexBuffer(ClothSimulPositionBuffer.VertexBufferRHI); Data = (float*)RHILockVertexBuffer(ClothSimulNormalBuffer.VertexBufferRHI, 0, VectorArraySize, RLM_WriteOnly); checkSlow(Data); FMemory::Memcpy(Data, InSimulNormals.GetData(), NumSimulVerts * sizeof(FVector4)); RHIUnlockVertexBuffer(ClothSimulNormalBuffer.VertexBufferRHI); } } else { UpdateClothUniformBuffer(InSimulPositions, InSimulNormals); } }
/** * Initialize the dynamic RHI for this rendering resource */ void FMorphVertexBuffer::InitDynamicRHI() { // LOD of the skel mesh is used to find number of vertices in buffer FStaticLODModel& LodModel = SkelMeshResource->LODModels[LODIdx]; // Create the buffer rendering resource uint32 Size = LodModel.NumVertices * sizeof(FMorphGPUSkinVertex); FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(Size,BUF_Dynamic,CreateInfo); // Lock the buffer. FMorphGPUSkinVertex* Buffer = (FMorphGPUSkinVertex*) RHILockVertexBuffer(VertexBufferRHI,0,Size,RLM_WriteOnly); // zero all deltas (NOTE: DeltaTangentZ is FPackedNormal, so we can't just FMemory::Memzero) for (uint32 VertIndex=0; VertIndex < LodModel.NumVertices; ++VertIndex) { Buffer[VertIndex].DeltaPosition = FVector::ZeroVector; Buffer[VertIndex].DeltaTangentZ = FPackedNormal::ZeroNormal; } // Unlock the buffer. RHIUnlockVertexBuffer(VertexBufferRHI); // hasn't been updated yet bHasBeenUpdated = false; }
void UpdateRenderData() const { // Copy the vertex data into the vertex buffer. void* VertexBufferData = RHILockVertexBuffer(VertexBufferRHI, 0, Vertices.Num() * sizeof(FDynamicMeshVertex), RLM_WriteOnly); FMemory::Memcpy(VertexBufferData, Vertices.GetData(), Vertices.Num() * sizeof(FDynamicMeshVertex)); RHIUnlockVertexBuffer(VertexBufferRHI); }
void FFinalSkinVertexBuffer::InitVertexData(FStaticLODModel& LodModel) { // Create the buffer rendering resource uint32 Size = LodModel.NumVertices * sizeof(FFinalSkinVertex); FRHIResourceCreateInfo CreateInfo; void* Buffer = nullptr; VertexBufferRHI = RHICreateAndLockVertexBuffer(Size,BUF_Dynamic, CreateInfo, Buffer); // Initialize the vertex data // All chunks are combined into one (rigid first, soft next) check(LodModel.VertexBufferGPUSkin.GetNumVertices() == LodModel.NumVertices); FFinalSkinVertex* DestVertex = (FFinalSkinVertex*)Buffer; for( uint32 VertexIdx=0; VertexIdx < LodModel.NumVertices; VertexIdx++ ) { const TGPUSkinVertexBase<bExtraBoneInfluencesT>* SrcVertex = LodModel.VertexBufferGPUSkin.GetVertexPtr<bExtraBoneInfluencesT>(VertexIdx); DestVertex->Position = LodModel.VertexBufferGPUSkin.GetVertexPositionFast<bExtraBoneInfluencesT>(VertexIdx); DestVertex->TangentX = SrcVertex->TangentX; // w component of TangentZ should already have sign of the tangent basis determinant DestVertex->TangentZ = SrcVertex->TangentZ; FVector2D UVs = LodModel.VertexBufferGPUSkin.GetVertexUVFast<bExtraBoneInfluencesT>(VertexIdx,0); DestVertex->U = UVs.X; DestVertex->V = UVs.Y; DestVertex++; } // Unlock the buffer. RHIUnlockVertexBuffer(VertexBufferRHI); }
virtual void InitRHI() override { FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), BUF_Static, CreateInfo); // Copy the vertex data into the vertex buffer. void* VertexBufferData = RHILockVertexBuffer(VertexBufferRHI, 0, Vertices.Num() * sizeof(FDynamicMeshVertex), RLM_WriteOnly); FMemory::Memcpy(VertexBufferData, Vertices.GetData(), Vertices.Num() * sizeof(FDynamicMeshVertex)); RHIUnlockVertexBuffer(VertexBufferRHI); }
virtual void InitRHI() override { FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(sizeof(FVector4) * 2, BUF_Static, CreateInfo); FVector4* DummyContents = (FVector4*)RHILockVertexBuffer(VertexBufferRHI,0,sizeof(FVector4)*2,RLM_WriteOnly); DummyContents[0] = FVector4(0.0f, 0.0f, 0.0f, 0.0f); DummyContents[1] = FVector4(1.0f, 1.0f, 1.0f, 1.0f); RHIUnlockVertexBuffer(VertexBufferRHI); }
virtual void InitRHI() { VertexBufferRHI = RHICreateVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), NULL, BUF_Static); // Copy the vertex data into the vertex buffer. void* VertexBufferData = RHILockVertexBuffer(VertexBufferRHI, 0, Vertices.Num() * sizeof(FDynamicMeshVertex), RLM_WriteOnly); FMemory::Memcpy(VertexBufferData, Vertices.GetTypedData(), Vertices.Num() * sizeof(FDynamicMeshVertex)); RHIUnlockVertexBuffer(VertexBufferRHI); }
virtual void InitRHI() override { FRHIResourceCreateInfo CreateInfo; void* VertexBufferData = nullptr; VertexBufferRHI = RHICreateAndLockVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), BUF_Static, CreateInfo, VertexBufferData); // Copy the vertex data into the vertex buffer. FMemory::Memcpy(VertexBufferData, Vertices.GetData(), Vertices.Num() * sizeof(FDynamicMeshVertex)); RHIUnlockVertexBuffer(VertexBufferRHI); }
/** * Initialize the RHI for this rendering resource */ virtual void InitRHI() override { // create a static vertex buffer FRHIResourceCreateInfo CreateInfo; void* BufferData = nullptr; VertexBufferRHI = RHICreateAndLockVertexBuffer(sizeof(FVector2D) * 4, BUF_Static | BUF_ShaderResource, CreateInfo, BufferData); FMemory::Memzero(BufferData, sizeof(FVector2D) * 4); RHIUnlockVertexBuffer(VertexBufferRHI); VertexBufferSRV = RHICreateShaderResourceView(VertexBufferRHI, sizeof(FVector2D), PF_G32R32F); }
/** * Initialize the RHI for this rendering resource */ void FLandscapeVertexBufferMobile::InitRHI() { // create a static vertex buffer FRHIResourceCreateInfo CreateInfo; void* VertexData = nullptr; VertexBufferRHI = RHICreateAndLockVertexBuffer(DataSize, BUF_Static, CreateInfo, VertexData); // Copy stored platform data FMemory::Memcpy(VertexData, (uint8*)Data, DataSize); RHIUnlockVertexBuffer(VertexBufferRHI); }
virtual void InitRHI() override { #if ENGINE_MAJOR_VERSION >= 4 && ENGINE_MINOR_VERSION >= 3 FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), BUF_Static, CreateInfo); #else VertexBufferRHI = RHICreateVertexBuffer(Vertices.Num() * sizeof(FDynamicMeshVertex), NULL, BUF_Static); #endif // Copy the vertex data into the vertex buffer. void* VertexBufferData = RHILockVertexBuffer(VertexBufferRHI, 0, Vertices.Num() * sizeof(FDynamicMeshVertex), RLM_WriteOnly); FMemory::Memcpy(VertexBufferData, Vertices.GetData(), Vertices.Num() * sizeof(FDynamicMeshVertex)); RHIUnlockVertexBuffer(VertexBufferRHI); }
/** * Creates a vertex buffer holding texture coordinates for the four corners of a sprite. */ void FParticleTexCoordVertexBuffer::InitRHI() { const uint32 Size = sizeof(FVector2D) * 4 * MAX_PARTICLES_PER_INSTANCE; VertexBufferRHI = RHICreateVertexBuffer( Size, NULL, BUF_Static ); FVector2D* Vertices = (FVector2D*)RHILockVertexBuffer( VertexBufferRHI, 0, Size, RLM_WriteOnly ); for (uint32 SpriteIndex = 0; SpriteIndex < MAX_PARTICLES_PER_INSTANCE; ++SpriteIndex) { Vertices[SpriteIndex*4 + 0] = FVector2D(0.0f, 0.0f); Vertices[SpriteIndex*4 + 1] = FVector2D(0.0f, 1.0f); Vertices[SpriteIndex*4 + 2] = FVector2D(1.0f, 1.0f); Vertices[SpriteIndex*4 + 3] = FVector2D(1.0f, 0.0f); } RHIUnlockVertexBuffer( VertexBufferRHI ); }
void FStreetMapVertexBuffer::InitRHI() { if( Vertices.Num() > 0 ) { // Allocate our vertex buffer FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer( Vertices.Num() * sizeof( Vertices[0] ), BUF_Static, CreateInfo ); // Load the vertex buffer with data void* VertexBufferData = RHILockVertexBuffer( VertexBufferRHI, 0, Vertices.Num() * sizeof( Vertices[0] ), RLM_WriteOnly ); FMemory::Memcpy( VertexBufferData, Vertices.GetData(), Vertices.Num() * sizeof( FStreetMapVertex ) ); RHIUnlockVertexBuffer( VertexBufferRHI ); } }
/** * Creates a vertex buffer holding texture coordinates for the four corners of a sprite. */ void FParticleTexCoordVertexBuffer::InitRHI() { const uint32 Size = sizeof(FVector2D) * 4 * MAX_PARTICLES_PER_INSTANCE; FRHIResourceCreateInfo CreateInfo; void* BufferData = nullptr; VertexBufferRHI = RHICreateAndLockVertexBuffer(Size, BUF_Static, CreateInfo, BufferData); FVector2D* Vertices = (FVector2D*)BufferData; for (uint32 SpriteIndex = 0; SpriteIndex < MAX_PARTICLES_PER_INSTANCE; ++SpriteIndex) { Vertices[SpriteIndex*4 + 0] = FVector2D(0.0f, 0.0f); Vertices[SpriteIndex*4 + 1] = FVector2D(0.0f, 1.0f); Vertices[SpriteIndex*4 + 2] = FVector2D(1.0f, 1.0f); Vertices[SpriteIndex*4 + 3] = FVector2D(1.0f, 0.0f); } RHIUnlockVertexBuffer( VertexBufferRHI ); }
virtual void InitRHI() { FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(12 * sizeof(FPackedNormal), BUF_Dynamic, CreateInfo); // Copy the vertex data into the vertex buffer. FPackedNormal* TangentBufferData = (FPackedNormal*)RHILockVertexBuffer(VertexBufferRHI, 0, 12 * sizeof(FPackedNormal), RLM_WriteOnly); for(int32 FaceIndex = 0;FaceIndex < 6;++FaceIndex) { const FVector UnprojectedTangentX = FVector(+1,-1,0).GetSafeNormal(); const FVector UnprojectedTangentY(-1,-1,-1); const FVector FaceNormal = FaceNormals[FaceIndex].ToFloat(); const FVector ProjectedFaceTangentX = (UnprojectedTangentX - FaceNormal * (UnprojectedTangentX | FaceNormal)).GetSafeNormal(); *TangentBufferData++ = ProjectedFaceTangentX; *TangentBufferData++ = FVector4(FaceNormal, FMath::Sign(UnprojectedTangentY | (FaceNormal ^ ProjectedFaceTangentX))); } RHIUnlockVertexBuffer(VertexBufferRHI); }
void FGPUBaseSkinVertexFactory::ShaderDataType::UpdateBoneData() { uint32 NumBones = BoneMatrices.Num(); check(NumBones <= MaxGPUSkinBones); if (GRHIFeatureLevel_DEPRECATED >= ERHIFeatureLevel::SM4) { static FSharedPoolPolicyData PoolPolicy; uint32 NumVectors = NumBones*3; check(NumVectors <= (MaxGPUSkinBones*3)); uint32 VectorArraySize = NumVectors * sizeof(FVector4); uint32 PooledArraySize = BoneBufferPool.PooledSizeForCreationArguments(VectorArraySize); if(!IsValidRef(BoneBuffer) || PooledArraySize != BoneBuffer.VertexBufferRHI->GetSize()) { if(IsValidRef(BoneBuffer)) { BoneBufferPool.ReleasePooledResource(BoneBuffer); } BoneBuffer = BoneBufferPool.CreatePooledResource(VectorArraySize); check(IsValidRef(BoneBuffer)); } if(NumBones) { #if PLATFORM_SUPPORTS_RHI_THREAD check(VectorArraySize == NumBones * sizeof(BoneMatrices[0])); if (GRHIThread) { GRHICommandList.GetImmediateCommandList().UpdateVertexBuffer(BoneBuffer.VertexBufferRHI, BoneMatrices.GetData(), NumBones * sizeof(BoneMatrices[0])); } else #endif { float* Data = (float*)RHILockVertexBuffer(BoneBuffer.VertexBufferRHI, 0, VectorArraySize, RLM_WriteOnly); checkSlow(Data); FMemory::Memcpy(Data, BoneMatrices.GetData(), NumBones * sizeof(BoneMatrices[0])); RHIUnlockVertexBuffer(BoneBuffer.VertexBufferRHI); } } } else { check(NumBones * BoneMatrices.GetTypeSize() <= sizeof(GBoneUniformStruct)); FMemory::Memcpy(&GBoneUniformStruct, BoneMatrices.GetData(), NumBones * sizeof(BoneMatrices[0])); UniformBuffer = RHICreateUniformBuffer(&GBoneUniformStruct, FBoneMatricesUniformShaderParameters::StaticStruct.GetLayout(), UniformBuffer_MultiFrame); } }
/** * Initialize the RHI for this rendering resource */ virtual void InitRHI() override { // used with a tristrip, so only 4 vertices are needed uint32 Size = 4 * sizeof(FMaterialTileVertex); // create vertex buffer FRHIResourceCreateInfo CreateInfo; VertexBufferRHI = RHICreateVertexBuffer(Size,BUF_Static,CreateInfo); // lock it void* Buffer = RHILockVertexBuffer(VertexBufferRHI,0,Size,RLM_WriteOnly); // first vertex element FMaterialTileVertex* DestVertex = (FMaterialTileVertex*)Buffer; // fill out the verts DestVertex[0].Initialize(1, -1, 1, 1); DestVertex[1].Initialize(1, 1, 1, 0); DestVertex[2].Initialize(-1, -1, 0, 1); DestVertex[3].Initialize(-1, 1, 0, 0); // Unlock the buffer. RHIUnlockVertexBuffer(VertexBufferRHI); }
/** * Creates a vertex buffer holding texture coordinates for eight corners of a polygon. */ void FParticleEightTexCoordVertexBuffer::InitRHI() { const uint32 Size = sizeof(FVector2D) * 8 * MAX_PARTICLES_PER_INSTANCE; FRHIResourceCreateInfo CreateInfo; void* BufferData = nullptr; VertexBufferRHI = RHICreateAndLockVertexBuffer(Size, BUF_Static, CreateInfo, BufferData); FVector2D* Vertices = (FVector2D*)BufferData; for (uint32 SpriteIndex = 0; SpriteIndex < MAX_PARTICLES_PER_INSTANCE; ++SpriteIndex) { // The contents of this buffer does not matter, whenever it is used, cutout geometry will override Vertices[SpriteIndex*8 + 0] = FVector2D(0.0f, 0.0f); Vertices[SpriteIndex*8 + 1] = FVector2D(0.0f, 1.0f); Vertices[SpriteIndex*8 + 2] = FVector2D(1.0f, 1.0f); Vertices[SpriteIndex*8 + 3] = FVector2D(1.0f, 0.0f); Vertices[SpriteIndex*8 + 4] = FVector2D(1.0f, 0.0f); Vertices[SpriteIndex*8 + 5] = FVector2D(1.0f, 0.0f); Vertices[SpriteIndex*8 + 6] = FVector2D(1.0f, 0.0f); Vertices[SpriteIndex*8 + 7] = FVector2D(1.0f, 0.0f); } RHIUnlockVertexBuffer( VertexBufferRHI ); }
void FFinalSkinVertexBuffer::InitVertexData(FStaticLODModel& LodModel) { // this used to be check, but during clothing importing (when replacing Apex asset) // it comes here with incomplete data causing crash during that intermediate state // so I'm changing to ensure, and update won't do anything since it contains Invalid VertexBufferRHI if (ensure(LodModel.VertexBufferGPUSkin.GetNumVertices() == LodModel.NumVertices)) { // Create the buffer rendering resource uint32 Size = LodModel.NumVertices * sizeof(FFinalSkinVertex); // Initialize the vertex data // All chunks are combined into one (rigid first, soft next) FRHIResourceCreateInfo CreateInfo; void* Buffer = nullptr; VertexBufferRHI = RHICreateAndLockVertexBuffer(Size, BUF_Dynamic, CreateInfo, Buffer); FFinalSkinVertex* DestVertex = (FFinalSkinVertex*)Buffer; for (uint32 VertexIdx = 0; VertexIdx < LodModel.NumVertices; VertexIdx++) { const TGPUSkinVertexBase<bExtraBoneInfluencesT>* SrcVertex = LodModel.VertexBufferGPUSkin.GetVertexPtr<bExtraBoneInfluencesT>(VertexIdx); DestVertex->Position = LodModel.VertexBufferGPUSkin.GetVertexPositionFast<bExtraBoneInfluencesT>(VertexIdx); DestVertex->TangentX = SrcVertex->TangentX; // w component of TangentZ should already have sign of the tangent basis determinant DestVertex->TangentZ = SrcVertex->TangentZ; FVector2D UVs = LodModel.VertexBufferGPUSkin.GetVertexUVFast<bExtraBoneInfluencesT>(VertexIdx, 0); DestVertex->U = UVs.X; DestVertex->V = UVs.Y; DestVertex++; } // Unlock the buffer. RHIUnlockVertexBuffer(VertexBufferRHI); } }
void AddElements(TArray<FDynamicMeshVertex> &Elements) { FDynamicMeshVertex* VertexBufferData = (FDynamicMeshVertex*)RHILockVertexBuffer(VertexBufferRHI, 0, BOSize * sizeof(FDynamicMeshVertex), RLM_WriteOnly); FMemory::Memcpy(VertexBufferData, &Elements[0], Elements.Num() * sizeof(FDynamicMeshVertex)); RHIUnlockVertexBuffer(VertexBufferRHI); }