| 223 | } |
| 224 | |
| 225 | bool Cloth::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) |
| 226 | { |
| 227 | #if MODEL_USE_PRECISE_MESH_INTERSECTS |
| 228 | if (!Actor::IntersectsItself(ray, distance, normal)) |
| 229 | return false; |
| 230 | #if WITH_CLOTH |
| 231 | if (_cloth) |
| 232 | { |
| 233 | // Precise per-triangle intersection |
| 234 | const ModelInstanceActor::MeshReference meshRef = GetMesh(); |
| 235 | if (meshRef.Actor == nullptr) |
| 236 | return false; |
| 237 | MeshAccessor accessor; |
| 238 | MeshBufferType bufferTypes[1] = { MeshBufferType::Index }; |
| 239 | if (accessor.LoadMesh(meshRef.Get(), false, ToSpan(bufferTypes, 1))) |
| 240 | return false; |
| 241 | auto indices = accessor.Index(); |
| 242 | auto indicesData = indices.GetData(); |
| 243 | PhysicsBackend::LockClothParticles(_cloth); |
| 244 | const Span<const Float4> particles = PhysicsBackend::GetClothParticles(_cloth); |
| 245 | const Transform transform = GetTransform(); |
| 246 | const bool indices16bit = indices.GetFormat() == PixelFormat::R16_UInt; |
| 247 | const int32 trianglesCount = indices.GetCount() / 3; |
| 248 | bool result = false; |
| 249 | distance = MAX_Real; |
| 250 | for (int32 triangleIndex = 0; triangleIndex < trianglesCount; triangleIndex++) |
| 251 | { |
| 252 | const int32 index = triangleIndex * 3; |
| 253 | int32 i0, i1, i2; |
| 254 | if (indices16bit) |
| 255 | { |
| 256 | i0 = indicesData.Get<uint16>()[index]; |
| 257 | i1 = indicesData.Get<uint16>()[index + 1]; |
| 258 | i2 = indicesData.Get<uint16>()[index + 2]; |
| 259 | } |
| 260 | else |
| 261 | { |
| 262 | i0 = indicesData.Get<uint32>()[index]; |
| 263 | i1 = indicesData.Get<uint32>()[index + 1]; |
| 264 | i2 = indicesData.Get<uint32>()[index + 2]; |
| 265 | } |
| 266 | const Vector3 v0 = transform.LocalToWorld(Vector3(particles[i0])); |
| 267 | const Vector3 v1 = transform.LocalToWorld(Vector3(particles[i1])); |
| 268 | const Vector3 v2 = transform.LocalToWorld(Vector3(particles[i2])); |
| 269 | Real d; |
| 270 | if (CollisionsHelper::RayIntersectsTriangle(ray, v0, v1, v2, d) && d < distance) |
| 271 | { |
| 272 | result = true; |
| 273 | normal = Vector3::Normalize((v1 - v0) ^ (v2 - v0)); |
| 274 | distance = d; |
| 275 | |
| 276 | // Flip normal if needed as cloth is two-sided |
| 277 | const Vector3 hitPos = ray.GetPoint(d); |
| 278 | if (Vector3::DistanceSquared(hitPos + normal, ray.Position) > Math::Square(d)) |
| 279 | normal = -normal; |
| 280 | } |
| 281 | } |
| 282 | PhysicsBackend::UnlockClothParticles(_cloth); |
nothing calls this directly
no test coverage detected