void AHair::UpdateSegment(AHairSegment* InSegment) { if (!InSegment || InSegment->Spline->GetNumberOfSplinePoints() < 2) return; InSegment->ProceduralMesh->ClearAllMeshSections(); ClearMeshData(InSegment); // Update node rotations to match spline for (int i = 0; i < InSegment->Spline->GetNumberOfSplinePoints(); i++) { FRotator Rot = InSegment->Spline->GetRotationAtSplinePoint(i, ESplineCoordinateSpace::World); InSegment->Nodes[i]->SetActorRotation(Rot); } // Populate new data if (!MiddleMeshData) return; for (int i = 0; i <= InSegment->NumSegments; i++) { float TotalDistance = InSegment->Spline->GetSplineLength(); float Distance = (TotalDistance / InSegment->NumSegments)*i; float NextDistance = (TotalDistance / InSegment->NumSegments)*i+1; AssignPositions(InSegment->Spline->GetLocationAtDistanceAlongSpline(Distance, ESplineCoordinateSpace::Local), InSegment->Spline->GetLocationAtDistanceAlongSpline(NextDistance, ESplineCoordinateSpace::Local)); //Weight = 1.0f - Distance / TotalDistance; float Displacement = InSegment->FallOff - 1.0f; Weight = 1.0f + (Distance / TotalDistance)*Displacement; // Interpolate distance to closest spline point index float Delta = ((InSegment->Spline->GetNumberOfSplinePoints() - 1)*1.0f) / (InSegment->NumSegments*1.0f); int Index = FGenericPlatformMath::RoundToInt(i*Delta); if (i == 0) { AddVertices(0, MiddleMeshData->Vertices, InSegment, Distance); AddTriangles(InSegment); AddUVs(InSegment, true); } else { AddVertices(2, MiddleMeshData->Vertices, InSegment, Distance); AddTriangles(InSegment); AddUVs(InSegment, false); } } // Create mesh InSegment->ProceduralMesh->CreateMeshSection(0, InSegment->ProceduralMeshData->Vertices, InSegment->ProceduralMeshData->Triangles, TArray<FVector>(), InSegment->ProceduralMeshData->UVs, TArray<FColor>(), TArray<FProcMeshTangent>(), true); // Duplicate for outline as custom depth not available for translucent materials InSegment->OutlineMesh->CreateMeshSection(0, InSegment->ProceduralMeshData->Vertices, InSegment->ProceduralMeshData->Triangles, TArray<FVector>(), InSegment->ProceduralMeshData->UVs, TArray<FColor>(), TArray<FProcMeshTangent>(), true); }
void TriangleTesselationCache::AddQuads(const carray<Vec3f>& pos, const carray<Vec3f>& normal, const carray<Vec2f>& uv, const carray<Vec4i>& quads) { // check if they have normals if(!normal.empty()) { AddTriangles(pos, normal, uv, ElementOperations::QuadsToTriangles(quads)); } else { carray<Vec4i> newQuads; ElementOperations::UnshareForFaceNormals(pos, (!uv.empty())?uv:carray<Vec2f>(pos.size(),Vec2f(0,0)), ElementOperations::QuadNormals(pos, quads), quads, this->pos, this->normal, this->uv, newQuads); this->triangles = ElementOperations::QuadsToTriangles(newQuads); } _UpdateBBox(); }
void Collision::Triangles(D3Dmodel* model, XMMATRIX world) { AddTriangles(model->ModelAsTriangles(world)); }
void Mesh::AddData(const Mesh& mesh, const ezTransform& transform) { ezMat4 transformMat = transform.GetAsMat4(); ezMat4 normalTransformMat = transformMat.GetInverse(0.0f).GetTranspose(); // Create new triangles. ezUInt32 oldTriangleCount = GetNumTriangles(); AddTriangles(mesh.GetNumTriangles()); ezArrayPtr<const Mesh::Triangle> sourceTriangles = mesh.GetTriangles(); ezArrayPtr<const Mesh::Triangle> targetTriangles = GetTriangles().GetSubArray(oldTriangleCount); EZ_ASSERT_DEBUG(sourceTriangles.GetCount() == targetTriangles.GetCount(), "Something is wrong with triangle allocation!"); for (auto it = mesh.m_VertexDataStreams.GetIterator(); it.IsValid(); ++it) { const VertexDataStream* sourceStream = it.Value(); VertexDataStream* targetStream = AddDataStream(static_cast<ezGALVertexAttributeSemantic::Enum>(it.Key()), sourceStream->GetNumElementsPerVertex(), sourceStream->GetElementType()); if (!targetStream) { ezLog::SeriousWarning("Cannot merge mesh {0} properly since it has a vertex data stream with semantic {1} that uses {2} elements " "instead of 'unkown' which is used by the merge target. Skipping this data stream.", mesh.m_Name, it.Key(), sourceStream->GetNumElementsPerVertex()); continue; } // Copy data. ezUInt32 targetBaseDataIndex = targetStream->m_Data.GetCount(); targetStream->m_Data.PushBackRange(sourceStream->m_Data); // Transform data. if (!transform.IsIdentical(ezTransform::IdentityTransform())) { const ezUInt32 attributeSize = targetStream->GetAttributeSize(); // Positions if (it.Key() == ezGALVertexAttributeSemantic::Position) { for (ezUInt32 i = targetBaseDataIndex; i < targetStream->m_Data.GetCount(); i += attributeSize) { ezVec3& pos = *reinterpret_cast<ezVec3*>(&targetStream->m_Data[i]); pos = transformMat.TransformPosition(pos); } } // Directions else if (it.Key() == ezGALVertexAttributeSemantic::Normal || it.Key() == ezGALVertexAttributeSemantic::Tangent || it.Key() == ezGALVertexAttributeSemantic::BiTangent) { for (ezUInt32 i = targetBaseDataIndex; i < targetStream->m_Data.GetCount(); i += attributeSize) { ezVec3& dir = *reinterpret_cast<ezVec3*>(&targetStream->m_Data[i]); dir = normalTransformMat.TransformDirection(dir); } } } // Set mapping for (ezUInt32 tri = 0; tri < sourceTriangles.GetCount(); ++tri) { for (int v = 0; v < 3; ++v) { VertexDataIndex sourceDataIndex = sourceStream->GetDataIndex(sourceTriangles[tri].m_Vertices[v]); if (sourceDataIndex.IsValid()) targetStream->SetDataIndex(targetTriangles[tri].m_Vertices[v], targetBaseDataIndex + sourceDataIndex.GetValue()); } } } // Add submeshes. ezUInt32 oldSubMeshCount = m_SubMeshes.GetCount(); m_SubMeshes.PushBackRange(mesh.m_SubMeshes); for (ezUInt32 i = oldSubMeshCount; i < m_SubMeshes.GetCount(); ++i) { m_SubMeshes[i].m_uiFirstTriangle += oldTriangleCount; } // Add skeleton if existent // TODO: What if multiple, incompatible skeletons are found(?) // For now: Remove skeleton and import unskinned // if (mesh.m_pSkeleton) //{ // if (m_pSkeleton) // { // if (!m_pSkeleton->IsCompatibleWith(mesh.m_pSkeleton.Borrow())) // { // ezLog::Warning("Found incompatible skeletons during mesh merging in mesh '{0}', import will be without skeletons!", // m_Name.GetData()); m_pSkeleton.Reset(); // } // } // else // { // m_pSkeleton = EZ_DEFAULT_NEW(ezSkeleton, *mesh.m_pSkeleton); // } //} }