| 116 | } |
| 117 | |
| 118 | void SplineModel::OnSplineUpdated() |
| 119 | { |
| 120 | // Skip updates when actor is disabled or something is missing |
| 121 | if (!_spline || !Model || !Model->IsLoaded() || !IsActiveInHierarchy() || _spline->GetSplinePointsCount() < 2) |
| 122 | { |
| 123 | _box = BoundingBox(_transform.Translation); |
| 124 | BoundingSphere::FromBox(_box, _sphere); |
| 125 | return; |
| 126 | } |
| 127 | PROFILE_CPU(); |
| 128 | |
| 129 | // Setup model instances over the spline segments |
| 130 | const auto& keyframes = _spline->Curve.GetKeyframes(); |
| 131 | const int32 segments = keyframes.Count() - 1; |
| 132 | const int32 chunksPerSegment = Math::Clamp(Math::CeilToInt(SPLINE_RESOLUTION * _quality), 2, 1024); |
| 133 | const float chunksPerSegmentInv = 1.0f / (float)chunksPerSegment; |
| 134 | const Transform splineTransform = GetTransform(); |
| 135 | _instances.Resize(segments, false); |
| 136 | BoundingBox localModelBounds(Vector3::Maximum, Vector3::Minimum); |
| 137 | { |
| 138 | auto& meshes = Model->LODs[0].Meshes; |
| 139 | Vector3 corners[8]; |
| 140 | for (int32 j = 0; j < meshes.Count(); j++) |
| 141 | { |
| 142 | const auto& mesh = meshes[j]; |
| 143 | mesh.GetBox().GetCorners(corners); |
| 144 | |
| 145 | for (int32 i = 0; i < 8; i++) |
| 146 | { |
| 147 | // Transform mesh corner using pre-transform but use double-precision to prevent issues when rotating model |
| 148 | Vector3 tmp = corners[i] * _preTransform.Scale; |
| 149 | double rotation[4] = { (double)_preTransform.Orientation.X, (double)_preTransform.Orientation.Y, (double)_preTransform.Orientation.Z, (double)_preTransform.Orientation.W }; |
| 150 | const double length = sqrt(rotation[0] * rotation[0] + rotation[1] * rotation[1] + rotation[2] * rotation[2] + rotation[3] * rotation[3]); |
| 151 | rotation[0] /= length; |
| 152 | rotation[1] /= length; |
| 153 | rotation[2] /= length; |
| 154 | rotation[3] /= length; |
| 155 | double pos[3] = { (double)tmp.X, (double)tmp.Y, (double)tmp.Z }; |
| 156 | const double x = rotation[0] + rotation[0]; |
| 157 | const double y = rotation[1] + rotation[1]; |
| 158 | const double z = rotation[2] + rotation[2]; |
| 159 | const double wx = rotation[3] * x; |
| 160 | const double wy = rotation[3] * y; |
| 161 | const double wz = rotation[3] * z; |
| 162 | const double xx = rotation[0] * x; |
| 163 | const double xy = rotation[0] * y; |
| 164 | const double xz = rotation[0] * z; |
| 165 | const double yy = rotation[1] * y; |
| 166 | const double yz = rotation[1] * z; |
| 167 | const double zz = rotation[2] * z; |
| 168 | tmp = Vector3( |
| 169 | (float)(pos[0] * (1.0 - yy - zz) + pos[1] * (xy - wz) + pos[2] * (xz + wy)) + _preTransform.Translation.X, |
| 170 | (float)(pos[0] * (xy + wz) + pos[1] * (1.0 - xx - zz) + pos[2] * (yz - wx)) + _preTransform.Translation.Y, |
| 171 | (float)(pos[0] * (xz - wy) + pos[1] * (yz + wx) + pos[2] * (1.0 - xx - yy)) + _preTransform.Translation.Z); |
| 172 | |
| 173 | localModelBounds.Minimum = Vector3::Min(localModelBounds.Minimum, tmp); |
| 174 | localModelBounds.Maximum = Vector3::Max(localModelBounds.Maximum, tmp); |
| 175 | } |
nothing calls this directly
no test coverage detected