代码:

void UKismetProceduralMeshLibrary::SliceProceduralMesh(UProceduralMeshComponent* InProcMesh, FVector PlanePosition, FVector PlaneNormal, bool bCreateOtherHalf, UProceduralMeshComponent*& OutOtherHalfProcMesh, EProcMeshSliceCapOption CapOption, UMaterialInterface* CapMaterial)
{if (InProcMesh != nullptr){// Transform plane from world to local spaceFTransform ProcCompToWorld = InProcMesh->GetComponentToWorld();FVector LocalPlanePos = ProcCompToWorld.InverseTransformPosition(PlanePosition);FVector LocalPlaneNormal = ProcCompToWorld.InverseTransformVectorNoScale(PlaneNormal);LocalPlaneNormal = LocalPlaneNormal.GetSafeNormal(); // Ensure normalizedFPlane SlicePlane(LocalPlanePos, LocalPlaneNormal);// Set of sections to add to the 'other half' componentTArray<FProcMeshSection> OtherSections;// Material for each section of other halfTArray<UMaterialInterface*> OtherMaterials;// Set of new edges created by clipping polys by planeTArray<FUtilEdge3D> ClipEdges;for (int32 SectionIndex = 0; SectionIndex < InProcMesh->GetNumSections(); SectionIndex++){FProcMeshSection* BaseSection = InProcMesh->GetProcMeshSection(SectionIndex);// If we have a section, and it has some valid geomif (BaseSection != nullptr && BaseSection->ProcIndexBuffer.Num() > 0 && BaseSection->ProcVertexBuffer.Num() > 0){// Compare bounding box of section with slicing planeint32 BoxCompare = BoxPlaneCompare(BaseSection->SectionLocalBox, SlicePlane);// Box totally clipped, clear sectionif (BoxCompare == -1){// Add entire section to other halfif (bCreateOtherHalf){OtherSections.Add(*BaseSection);OtherMaterials.Add(InProcMesh->GetMaterial(SectionIndex));}InProcMesh->ClearMeshSection(SectionIndex);}// Box totally on one side of plane, leave it alone, do nothingelse if (BoxCompare == 1){// ...}// Box intersects plane, need to clip some polys!else{// New section for geometryFProcMeshSection NewSection;// New section for 'other half' geometry (if desired)FProcMeshSection* NewOtherSection = nullptr;if (bCreateOtherHalf){int32 OtherSectionIndex = OtherSections.Add(FProcMeshSection());NewOtherSection = &OtherSections[OtherSectionIndex];OtherMaterials.Add(InProcMesh->GetMaterial(SectionIndex)); // Remember material for this section}// Map of base vert index to sliced vert indexTMap<int32, int32> BaseToSlicedVertIndex;TMap<int32, int32> BaseToOtherSlicedVertIndex;const int32 NumBaseVerts = BaseSection->ProcVertexBuffer.Num();// Distance of each base vert from slice planeTArray<float> VertDistance;VertDistance.AddUninitialized(NumBaseVerts);// Build vertex buffer for (int32 BaseVertIndex = 0; BaseVertIndex < NumBaseVerts; BaseVertIndex++){FProcMeshVertex& BaseVert = BaseSection->ProcVertexBuffer[BaseVertIndex];// Calc distance from planeVertDistance[BaseVertIndex] = SlicePlane.PlaneDot(BaseVert.Position);// See if vert is being kept in this sectionif (VertDistance[BaseVertIndex] > 0.f){// Copy to sliced v bufferint32 SlicedVertIndex = NewSection.ProcVertexBuffer.Add(BaseVert);// Update section boundsNewSection.SectionLocalBox += BaseVert.Position;// Add to mapBaseToSlicedVertIndex.Add(BaseVertIndex, SlicedVertIndex);}// Or add to other half if desiredelse if(NewOtherSection != nullptr){int32 SlicedVertIndex = NewOtherSection->ProcVertexBuffer.Add(BaseVert);NewOtherSection->SectionLocalBox += BaseVert.Position;BaseToOtherSlicedVertIndex.Add(BaseVertIndex, SlicedVertIndex);}}// Iterate over base triangles (ie 3 indices at a time)for (int32 BaseIndex = 0; BaseIndex < BaseSection->ProcIndexBuffer.Num(); BaseIndex += 3){int32 BaseV[3]; // Triangle vert indices in original meshint32* SlicedV[3]; // Pointers to vert indices in new v bufferint32* SlicedOtherV[3]; // Pointers to vert indices in new 'other half' v buffer// For each vertex..for (int32 i = 0; i < 3; i++){// Get triangle vert indexBaseV[i] = BaseSection->ProcIndexBuffer[BaseIndex + i];// Look up in sliced v bufferSlicedV[i] = BaseToSlicedVertIndex.Find(BaseV[i]);// Look up in 'other half' v buffer (if desired)if (bCreateOtherHalf){SlicedOtherV[i] = BaseToOtherSlicedVertIndex.Find(BaseV[i]);// Each base vert _must_ exist in either BaseToSlicedVertIndex or BaseToOtherSlicedVertIndex check((SlicedV[i] != nullptr) != (SlicedOtherV[i] != nullptr));}}// If all verts survived plane cull, keep the triangleif (SlicedV[0] != nullptr && SlicedV[1] != nullptr && SlicedV[2] != nullptr){NewSection.ProcIndexBuffer.Add(*SlicedV[0]);NewSection.ProcIndexBuffer.Add(*SlicedV[1]);NewSection.ProcIndexBuffer.Add(*SlicedV[2]);}// If all verts were removed by plane cullelse if (SlicedV[0] == nullptr && SlicedV[1] == nullptr && SlicedV[2] == nullptr){// If creating other half, add all verts to thatif (NewOtherSection != nullptr){NewOtherSection->ProcIndexBuffer.Add(*SlicedOtherV[0]);NewOtherSection->ProcIndexBuffer.Add(*SlicedOtherV[1]);NewOtherSection->ProcIndexBuffer.Add(*SlicedOtherV[2]);}}// If partially culled, clip to create 1 or 2 new triangleselse{int32 FinalVerts[4];int32 NumFinalVerts = 0;int32 OtherFinalVerts[4];int32 NumOtherFinalVerts = 0;FUtilEdge3D NewClipEdge;int32 ClippedEdges = 0;float PlaneDist[3];PlaneDist[0] = VertDistance[BaseV[0]];PlaneDist[1] = VertDistance[BaseV[1]];PlaneDist[2] = VertDistance[BaseV[2]];for (int32 EdgeIdx = 0; EdgeIdx < 3; EdgeIdx++){int32 ThisVert = EdgeIdx;// If start vert is inside, add it.if (SlicedV[ThisVert] != nullptr){check(NumFinalVerts < 4);FinalVerts[NumFinalVerts++] = *SlicedV[ThisVert];}// If not, add to other sideelse if(bCreateOtherHalf){check(NumOtherFinalVerts < 4);OtherFinalVerts[NumOtherFinalVerts++] = *SlicedOtherV[ThisVert];}// If start and next vert are on opposite sides, add intersectionint32 NextVert = (EdgeIdx + 1) % 3;if ((SlicedV[EdgeIdx] == nullptr) != (SlicedV[NextVert] == nullptr)){// Find distance along edge that plane isfloat Alpha = -PlaneDist[ThisVert] / (PlaneDist[NextVert] - PlaneDist[ThisVert]);// Interpolate vertex params to that pointFProcMeshVertex InterpVert = InterpolateVert(BaseSection->ProcVertexBuffer[BaseV[ThisVert]], BaseSection->ProcVertexBuffer[BaseV[NextVert]], FMath::Clamp(Alpha, 0.0f, 1.0f));// Add to vertex bufferint32 InterpVertIndex = NewSection.ProcVertexBuffer.Add(InterpVert);// Update boundsNewSection.SectionLocalBox += InterpVert.Position;// Save vert index for this polycheck(NumFinalVerts < 4);FinalVerts[NumFinalVerts++] = InterpVertIndex;// If desired, add to the poly for the other half as wellif (NewOtherSection != nullptr){int32 OtherInterpVertIndex = NewOtherSection->ProcVertexBuffer.Add(InterpVert);NewOtherSection->SectionLocalBox += InterpVert.Position;check(NumOtherFinalVerts < 4);OtherFinalVerts[NumOtherFinalVerts++] = OtherInterpVertIndex;}// When we make a new edge on the surface of the clip plane, save it off.check(ClippedEdges < 2);if (ClippedEdges == 0){NewClipEdge.V0 = InterpVert.Position;}else{NewClipEdge.V1 = InterpVert.Position;}ClippedEdges++;}}// Triangulate the clipped polygon.for (int32 VertexIndex = 2; VertexIndex < NumFinalVerts; VertexIndex++){NewSection.ProcIndexBuffer.Add(FinalVerts[0]);NewSection.ProcIndexBuffer.Add(FinalVerts[VertexIndex - 1]);NewSection.ProcIndexBuffer.Add(FinalVerts[VertexIndex]);}// If we are making the other half, triangulate that as wellif (NewOtherSection != nullptr){for (int32 VertexIndex = 2; VertexIndex < NumOtherFinalVerts; VertexIndex++){NewOtherSection->ProcIndexBuffer.Add(OtherFinalVerts[0]);NewOtherSection->ProcIndexBuffer.Add(OtherFinalVerts[VertexIndex - 1]);NewOtherSection->ProcIndexBuffer.Add(OtherFinalVerts[VertexIndex]);}}check(ClippedEdges != 1); // Should never clip just one edge of the triangle// If we created a new edge, save that off here as wellif (ClippedEdges == 2){ClipEdges.Add(NewClipEdge);}}}// Remove 'other' section from array if no valid geometry for itif (NewOtherSection != nullptr && (NewOtherSection->ProcIndexBuffer.Num() == 0 || NewOtherSection->ProcVertexBuffer.Num() == 0)){OtherSections.RemoveAt(OtherSections.Num() - 1);}// If we have some valid geometry, update sectionif (NewSection.ProcIndexBuffer.Num() > 0 && NewSection.ProcVertexBuffer.Num() > 0){// Assign new geom to this sectionInProcMesh->SetProcMeshSection(SectionIndex, NewSection);}// If we don't, remove this sectionelse{InProcMesh->ClearMeshSection(SectionIndex);}}}}// Create cap geometry (if some edges to create it from)if (CapOption != EProcMeshSliceCapOption::NoCap && ClipEdges.Num() > 0){FProcMeshSection CapSection;int32 CapSectionIndex = INDEX_NONE;// If using an existing section, copy that info firstif (CapOption == EProcMeshSliceCapOption::UseLastSectionForCap){CapSectionIndex = InProcMesh->GetNumSections() - 1;CapSection = *InProcMesh->GetProcMeshSection(CapSectionIndex);}// Adding new section for capelse{CapSectionIndex = InProcMesh->GetNumSections();}// Project 3D edges onto slice plane to form 2D edgesTArray<FUtilEdge2D> Edges2D;FUtilPoly2DSet PolySet;FGeomTools::ProjectEdges(Edges2D, PolySet.PolyToWorld, ClipEdges, SlicePlane);// Find 2D closed polygons from this edge soupFGeomTools::Buid2DPolysFromEdges(PolySet.Polys, Edges2D, FColor(255, 255, 255, 255));// Remember start point for vert and index buffer before adding and cap geomint32 CapVertBase = CapSection.ProcVertexBuffer.Num();int32 CapIndexBase = CapSection.ProcIndexBuffer.Num();// Triangulate each polyfor (int32 PolyIdx = 0; PolyIdx < PolySet.Polys.Num(); PolyIdx++){// Generate UVs for the 2D polygon.FGeomTools::GeneratePlanarTilingPolyUVs(PolySet.Polys[PolyIdx], 64.f);// Remember start of vert buffer before adding triangles for this polyint32 PolyVertBase = CapSection.ProcVertexBuffer.Num();// Transform from 2D poly verts to 3DTransform2DPolygonTo3D(PolySet.Polys[PolyIdx], PolySet.PolyToWorld, CapSection.ProcVertexBuffer, CapSection.SectionLocalBox);// Triangulate this polygonTriangulatePoly(CapSection.ProcIndexBuffer, CapSection.ProcVertexBuffer, PolyVertBase, LocalPlaneNormal);}// Set geom for cap sectionInProcMesh->SetProcMeshSection(CapSectionIndex, CapSection);// If creating new section for cap, assign cap material to itif (CapOption == EProcMeshSliceCapOption::CreateNewSectionForCap){InProcMesh->SetMaterial(CapSectionIndex, CapMaterial);}// If creating the other half, copy cap geom into other half sectionsif (bCreateOtherHalf){// Find section we want to use for the cap on the 'other half'FProcMeshSection* OtherCapSection;if (CapOption == EProcMeshSliceCapOption::CreateNewSectionForCap){OtherSections.Add(FProcMeshSection());OtherMaterials.Add(CapMaterial);}OtherCapSection = &OtherSections.Last();// Remember current base index for verts in 'other cap section'int32 OtherCapVertBase = OtherCapSection->ProcVertexBuffer.Num();// Copy verts from cap section into other cap sectionfor (int32 VertIdx = CapVertBase; VertIdx < CapSection.ProcVertexBuffer.Num(); VertIdx++){FProcMeshVertex OtherCapVert = CapSection.ProcVertexBuffer[VertIdx];// Flip normal and tangent TODO: FlipY?OtherCapVert.Normal *= -1.f;OtherCapVert.Tangent.TangentX *= -1.f;// Add to other cap v bufferOtherCapSection->ProcVertexBuffer.Add(OtherCapVert);// And update bounding boxOtherCapSection->SectionLocalBox += OtherCapVert.Position;}// Find offset between main cap verts and other cap vertsint32 VertOffset = OtherCapVertBase - CapVertBase;// Copy indices over as wellfor (int32 IndexIdx = CapIndexBase; IndexIdx < CapSection.ProcIndexBuffer.Num(); IndexIdx += 3){// Need to offset and change windingOtherCapSection->ProcIndexBuffer.Add(CapSection.ProcIndexBuffer[IndexIdx + 0] + VertOffset);OtherCapSection->ProcIndexBuffer.Add(CapSection.ProcIndexBuffer[IndexIdx + 2] + VertOffset);OtherCapSection->ProcIndexBuffer.Add(CapSection.ProcIndexBuffer[IndexIdx + 1] + VertOffset);}}}// Array of sliced collision shapesTArray< TArray<FVector> > SlicedCollision;TArray< TArray<FVector> > OtherSlicedCollision;UBodySetup* ProcMeshBodySetup = InProcMesh->GetBodySetup();for (int32 ConvexIndex = 0; ConvexIndex < ProcMeshBodySetup->AggGeom.ConvexElems.Num(); ConvexIndex++){FKConvexElem& BaseConvex = ProcMeshBodySetup->AggGeom.ConvexElems[ConvexIndex];int32 BoxCompare = BoxPlaneCompare(BaseConvex.ElemBox, SlicePlane);// If box totally clipped, add to other half (if desired)if (BoxCompare == -1){if (bCreateOtherHalf){OtherSlicedCollision.Add(BaseConvex.VertexData);}}// If box totally valid, just keep mesh as iselse if (BoxCompare == 1){SlicedCollision.Add(BaseConvex.VertexData);}// Need to actually slice the convex shapeelse{TArray<FVector> SlicedConvexVerts;SliceConvexElem(BaseConvex, SlicePlane, SlicedConvexVerts);// If we got something valid, add itif (SlicedConvexVerts.Num() >= 4){SlicedCollision.Add(SlicedConvexVerts);}// Slice again to get the other half of the collision, if desiredif (bCreateOtherHalf){TArray<FVector> OtherSlicedConvexVerts;SliceConvexElem(BaseConvex, SlicePlane.Flip(), OtherSlicedConvexVerts);if (OtherSlicedConvexVerts.Num() >= 4){OtherSlicedCollision.Add(OtherSlicedConvexVerts);}}}}// Update collision of proc meshInProcMesh->SetCollisionConvexMeshes(SlicedCollision);// If creating other half, create component nowif (bCreateOtherHalf){// Create new component with the same outer as the proc mesh passed inOutOtherHalfProcMesh = NewObject<UProceduralMeshComponent>(InProcMesh->GetOuter());// Set transform to match source componentOutOtherHalfProcMesh->SetWorldTransform(InProcMesh->GetComponentTransform());// Add each section of geometryfor (int32 SectionIndex = 0; SectionIndex < OtherSections.Num(); SectionIndex++){OutOtherHalfProcMesh->SetProcMeshSection(SectionIndex, OtherSections[SectionIndex]);OutOtherHalfProcMesh->SetMaterial(SectionIndex, OtherMaterials[SectionIndex]);}// Copy collision settings from input meshOutOtherHalfProcMesh->SetCollisionProfileName(InProcMesh->GetCollisionProfileName());OutOtherHalfProcMesh->SetCollisionEnabled(InProcMesh->GetCollisionEnabled());OutOtherHalfProcMesh->bUseComplexAsSimpleCollision = InProcMesh->bUseComplexAsSimpleCollision;// Assign sliced collisionOutOtherHalfProcMesh->SetCollisionConvexMeshes(OtherSlicedCollision);// Finally registerOutOtherHalfProcMesh->RegisterComponent();}}
}

ue4 中KismetProceduralMeshLibrary SliceProceduralMesh的原理相关推荐

  1. ue4小白人骨骼定义_动画短片在UE4中的工作流程都有哪些?来看游戏建模师如何分析的...

    CG摄影师兼导演Jeffy Zachariah谈到了他的动画短片WAKE的制作:在UE4中与Sequencer合作,摄像机设置,资产制作等. 想法 将动画视为通过运动说出来的故事或表情,甚至可以只通过 ...

  2. ue4 离线渲染_[译]Real Shading in Unreal Engine 4(UE4中的真实渲染)(2)

    利用假期接着把剩下的部分搞完吧,其实,纯粹的翻译应该还是比较简单的,但是,为了更好地理解,我一般都会多找一些资料来进行互相印证.在上面一部分Shader Model的改变过程中,我主要是参考了一些PB ...

  3. UE4中使用真实天空插件——TrueSky

    UE4中使用真实天空插件--TrueSky 1.简述 TrueSKY是一个软件开发套件,可以在各种平台上实时渲染逼真的天空,云彩和大气效果.经过多年研究和开发,它基于光散射和吸收的物理原理,并针对速度 ...

  4. 在UE4中实现锥体下雨效果

    在UE4中实现锥体下雨效果 终于不懒,打起精神更新一下前段时间做过的一些东西.. 本文主要讲述一个特别的下雨效果在UE4中的制作过程.这个效果是模仿<天涯明月刀>手游的下雨效果做的,一开始 ...

  5. ue4中隐藏灯光和相机图标_UE4中的光线追踪和SSGI照明研究

    AitorRández在最新研究中解释了他如何在UE4中进行照明工作,并共享了设置和场景以供下载.我叫AitorRández,我是比利时数字艺术与娱乐(DAE)最后一年的学生.我对环境艺术及其涉及的一 ...

  6. UE4中的PBR材质

    PBR材质系统原理简介 一.自然界材质 要学会使用PBR首先需要了解什么是PBR,需要从真实世界的这些PBR材质特有的属性拆分开来去了解他们,这样我们就需要了解光,物体表面材质以及光是如何与材质交互的 ...

  7. 在UE4中创建CG动画 How to create a movie in Unreal Engine 4 using Metahuman

    MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz 语言:英语+中英文字幕(根据原英文字幕机译更准确)|大小解压后:1.55 GB |时长:1h 16m 你会学到什么 如何在 ...

  8. ue4中面部动画制作视频教程 Facial Animation More In Unreal Engine 4

    ue4中面部动画制作视频教程 Facial Animation & More In Unreal Engine 4 时长4h 包含项目文件 1920X1080 MP4 大小解压后:5.75G ...

  9. ue4蓝图节点手册中文_在UE4中播放视频

    简介: 在日常使用UE4做项目时,会遇到在UE4里播放视频文件的需求,在UE4中可以使用媒体框架(Media Framework)来实现这一功能.这里介绍两种简单的方法来使用这一功能,分别是在场景里播 ...

  10. jQuery中getJSON跨域原理详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp28 jQuery中getJSON跨域原理详解 前几天我再开发一个叫 河蟹工 ...

最新文章

  1. 多传感器融合之滤波(一)——卡尔曼滤波(KF)推导
  2. windows下python2.7.14版本的安装
  3. Exchange企业实战技巧(5)配置OWA域名简写
  4. @poj - 1509@ Glass Beads
  5. JavaScript比较中应使用哪个等于运算符(== vs ===)?
  6. strcat()函数常见问题
  7. python对象编程例子-python编程进阶之类和对象用法实例分析
  8. 学生系统优化(二)- - 窗体代码
  9. Python基础——PyCharm版本——第五章、循环(for、while、break、continue)
  10. 面向对象课程 - T-shirt
  11. 【今日头条】【抖音火山】前端开发实习生
  12. DB2常用函数:字符串函数
  13. SpringCloudStream整合rabbitMq
  14. Linux 命令(104)—— crontab 命令
  15. 使用JAVA工程和KEmulator模拟器开发J2ME项目
  16. kk5.0电脑版 服务器信息,1 月 2017 累积更新 5.0.8308.984 Lync Server 2013 web 组件服务器...
  17. 一文理清集成运算放大器 ---- 总结篇
  18. 应用层协议和传输层协议
  19. 信号分析的短时傅里叶变换(scipy.signal.stft)
  20. 在x86下交叉编译mips程序

热门文章

  1. 滴滴如何调度_滴滴智能调度浅析
  2. 学生学籍管理系统(c语言)
  3. 阶乘的0 【南阳 oj 题目84】
  4. 获取计算机用户名称的方法,javascript读取用户名和计算机名
  5. 自然语言处理NLP中的N-gram模型
  6. Java多线程系列--【JUC锁08】-共享锁和ReentrantReadWriteLock
  7. 博途IEC TIME数据类型_基于博途V15 西门子S7-1200数据处理指令应用-移动操作
  8. OSChina 周三乱弹 —— 你们的女神宣布结婚了
  9. 【nvidia】1.命令行方式安装nvidia显卡驱动
  10. kk5.0服务器信息怎么填,蓝凌KK5.0:企业大连接的IT落地支撑平台