void StaticModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results) { RayQueryLevel level = query.level_; switch (level) { case RAY_AABB: Drawable::ProcessRayQuery(query, results); break; case RAY_OBB: case RAY_TRIANGLE: case RAY_TRIANGLE_UV: Matrix3x4 inverse(node_->GetWorldTransform().Inverse()); Ray localRay = query.ray_.Transformed(inverse); float distance = localRay.HitDistance(boundingBox_); Vector3 normal = -query.ray_.direction_; Vector2 geometryUV; unsigned hitBatch = M_MAX_UNSIGNED; if (level >= RAY_TRIANGLE && distance < query.maxDistance_) { distance = M_INFINITY; for (unsigned i = 0; i < batches_.Size(); ++i) { Geometry* geometry = batches_[i].geometry_; if (geometry) { Vector3 geometryNormal; float geometryDistance = level == RAY_TRIANGLE ? geometry->GetHitDistance(localRay, &geometryNormal) : geometry->GetHitDistance(localRay, &geometryNormal, &geometryUV); if (geometryDistance < query.maxDistance_ && geometryDistance < distance) { distance = geometryDistance; normal = (node_->GetWorldTransform() * Vector4(geometryNormal, 0.0f)).Normalized(); hitBatch = i; } } } } if (distance < query.maxDistance_) { RayQueryResult result; result.position_ = query.ray_.origin_ + distance * query.ray_.direction_; result.normal_ = normal; result.textureUV_ = geometryUV; result.distance_ = distance; result.drawable_ = this; result.node_ = node_; result.subObject_ = hitBatch; results.Push(result); } break; } }
void CustomGeometry::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results) { RayQueryLevel level = query.level_; switch (level) { case RAY_AABB: Drawable::ProcessRayQuery(query, results); break; case RAY_OBB: case RAY_TRIANGLE: { Matrix3x4 inverse(node_->GetWorldTransform().Inverse()); Ray localRay = query.ray_.Transformed(inverse); float distance = localRay.HitDistance(boundingBox_); Vector3 normal = -query.ray_.direction_; if (level == RAY_TRIANGLE && distance < query.maxDistance_) { distance = M_INFINITY; for (unsigned i = 0; i < batches_.Size(); ++i) { Geometry* geometry = batches_[i].geometry_; if (geometry) { Vector3 geometryNormal; float geometryDistance = geometry->GetHitDistance(localRay, &geometryNormal); if (geometryDistance < query.maxDistance_ && geometryDistance < distance) { distance = geometryDistance; normal = (node_->GetWorldTransform() * Vector4(geometryNormal, 0.0f)).Normalized(); } } } } if (distance < query.maxDistance_) { RayQueryResult result; result.position_ = query.ray_.origin_ + distance * query.ray_.direction_; result.normal_ = normal; result.distance_ = distance; result.drawable_ = this; result.node_ = node_; result.subObject_ = M_MAX_UNSIGNED; results.Push(result); } } break; case RAY_TRIANGLE_UV: ATOMIC_LOGWARNING("RAY_TRIANGLE_UV query level is not supported for CustomGeometry component"); break; } }
void StaticModelGroup::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results) { // If no bones or no bone-level testing, use the Drawable test RayQueryLevel level = query.level_; if (level < RAY_AABB) { Drawable::ProcessRayQuery(query, results); return; } // Check ray hit distance to AABB before proceeding with more accurate tests // GetWorldBoundingBox() updates the world transforms if (query.ray_.HitDistance(GetWorldBoundingBox()) >= query.maxDistance_) return; for (unsigned i = 0; i < numWorldTransforms_; ++i) { // Initial test using AABB float distance = query.ray_.HitDistance(boundingBox_.Transformed(worldTransforms_[i])); // Then proceed to OBB and triangle-level tests if necessary if (level >= RAY_OBB && distance < query.maxDistance_) { Matrix3x4 inverse = worldTransforms_[i].Inverse(); Ray localRay = query.ray_.Transformed(inverse); distance = localRay.HitDistance(boundingBox_); if (level == RAY_TRIANGLE && distance < query.maxDistance_) { distance = M_INFINITY; for (unsigned j = 0; j < batches_.Size(); ++j) { Geometry* geometry = batches_[j].geometry_; if (geometry) { float geometryDistance = geometry->GetHitDistance(localRay); if (geometryDistance < query.maxDistance_ && geometryDistance < distance) distance = geometryDistance; } } } } if (distance < query.maxDistance_) { RayQueryResult result; result.drawable_ = this; result.node_ = node_; result.distance_ = distance; result.subObject_ = i; results.Push(result); } } }
void StaticModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results) { RayQueryLevel level = query.level_; switch (level) { case RAY_AABB_NOSUBOBJECTS: case RAY_AABB: Drawable::ProcessRayQuery(query, results); break; case RAY_OBB: case RAY_TRIANGLE: Matrix3x4 inverse(node_->GetWorldTransform().Inverse()); Ray localRay = query.ray_.Transformed(inverse); float distance = localRay.HitDistance(boundingBox_); if (distance < query.maxDistance_) { if (level == RAY_TRIANGLE) { for (unsigned i = 0; i < batches_.Size(); ++i) { Geometry* geometry = batches_[i].geometry_; if (geometry) { distance = geometry->GetHitDistance(localRay); if (distance < query.maxDistance_) { RayQueryResult result; result.drawable_ = this; result.node_ = node_; result.distance_ = distance; result.subObject_ = M_MAX_UNSIGNED; results.Push(result); break; } } } } else { RayQueryResult result; result.drawable_ = this; result.node_ = node_; result.distance_ = distance; result.subObject_ = M_MAX_UNSIGNED; results.Push(result); } } break; } }