private void ApplyRigidbody() { if (_rigidbody == null) { return; } if (isOwnedLocally) { return; } // If we're using rigidbody extrapolation and we've collided with something, let the local rigidbody simulation run until we receive another packet or 500ms has passed if (_rigidbody != null && _extrapolation && _stopExtrapolatingAtRoomTime >= 0.0 && (realtime.room.time - _stopExtrapolatingAtRoomTime) < 0.5f) { return; } if (_rigidbody.useGravity != _model.useGravity) { _rigidbody.useGravity = _model.useGravity; } if (_rigidbody.isKinematic != _model.isKinematic) { _rigidbody.isKinematic = _model.isKinematic; } // If the model is owned by someone, we extrapolate & lerp. if (_model.ownerID != -1) { // Snapshot Vector3 position = _syncPosition ? _model.position : _rigidbody.position; Quaternion rotation = _syncRotation ? _model.rotation : _rigidbody.rotation; Vector3 scale = _syncScale ? _model.scale : transform.localScale; Vector3 velocity = _model.velocity; Vector3 angularVelocity = _model.angularVelocity; bool shouldExtrapolate = _model.shouldExtrapolate; bool useGravity = _model.useGravity; double timestamp = _model.timestamp; float deltaTime = (float)(realtime.room.time - timestamp); // If the last snapshot is too old, skip extrapolation. if (deltaTime > 1.0f) { shouldExtrapolate = false; } // Extrapolate if (shouldExtrapolate) { // Cap extrapolation time float extrapolateTimeMax = _model.isKinematic ? Time.fixedDeltaTime * 5.0f : 0.5f; // Limit to 5 frames if kinematic. 500ms if non-kinematic. deltaTime = Mathf.Clamp(deltaTime, 0.0f, extrapolateTimeMax); // Simulate // TODO: I suspect that this function is off even though I've checked it. I know the single frame one is good, but I'm worried this one is off which is causing switching to the local simulation on bounce to not work correctly. PhysXEmulation.SimulatePhysX(ref position, ref rotation, ref velocity, ref angularVelocity, useGravity, Physics.gravity, _rigidbody.drag, _rigidbody.angularDrag, _rigidbody.maxDepenetrationVelocity, _rigidbody.maxAngularVelocity, _rigidbody.constraints, deltaTime, Time.fixedDeltaTime); } // Apply float lerpFactor = 25.0f; // Set scale before position/rotation otherwise scale will get reset. if (_syncScale) { transform.localScale = Vector3.Lerp(transform.localScale, scale, lerpFactor * Time.fixedDeltaTime); } if (_syncPosition) { _rigidbody.MovePosition(Vector3.Lerp(_rigidbody.position, position, lerpFactor * Time.fixedDeltaTime)); } if (_syncRotation) { _rigidbody.MoveRotation(Quaternion.Slerp(_rigidbody.rotation, rotation, lerpFactor * Time.fixedDeltaTime)); } } else { // If the model isn't owned by anyone, set the transform position instantly. if (_syncScale) { transform.localScale = _model.scale; } if (_syncPosition) { _rigidbody.position = _model.position; } if (_syncRotation) { _rigidbody.rotation = _model.rotation; } if (_syncPosition) { _rigidbody.velocity = Vector3.zero; } if (_syncRotation) { _rigidbody.angularVelocity = Vector3.zero; } } }
// Apply private void ApplyTransform() { if (_rigidbody != null) { return; } if (isOwnedLocally) { return; } // If the model is owned by someone, we extrapolate & lerp. if (_model.ownerID != -1) { // Snapshot Vector3 position = _syncPosition ? _model.position : transform.localPosition; Quaternion rotation = _syncRotation ? _model.rotation : transform.localRotation; Vector3 scale = _syncScale ? _model.scale : transform.localScale; bool shouldExtrapolate = _model.shouldExtrapolate; double timestamp = _model.timestamp; float deltaTime = (float)(realtime.room.time - timestamp); // If the last snapshot is too old, skip extrapolation. if (deltaTime > 1.0f) { shouldExtrapolate = false; } // Extrapolate if (shouldExtrapolate) { // Calculate velocity & angularVelocity Vector3 velocity = Vector3.zero; Vector3 angularVelocity = Vector3.zero; Vector3 previousPosition = _model.previousPosition; Quaternion previousRotation = _model.previousRotation; double previousTimestamp = _model.previousTimestamp; // Only extrapolate if we have a previous frame, otherwise we'll have no data to extrapolate with. if (previousTimestamp > 0.0) { Vector3 positionDelta = position - previousPosition; Quaternion rotationDeltaQuaternion = Quaternion.Inverse(previousRotation) * rotation; Vector3 rotationDeltaDegrees = ReduceAngles(rotationDeltaQuaternion.eulerAngles); Vector3 rotationDelta = new Vector3(rotationDeltaDegrees.x * Mathf.Deg2Rad, rotationDeltaDegrees.y * Mathf.Deg2Rad, rotationDeltaDegrees.z * Mathf.Deg2Rad); float timeDelta = (float)(timestamp - previousTimestamp); if (timeDelta > 0.0f) { velocity = positionDelta / timeDelta; angularVelocity = rotationDelta / timeDelta; } // Cap extrapolation time float extrapolateTimeMax = Time.fixedDeltaTime * 10.0f; // Limit to 5 frames. deltaTime = Mathf.Clamp(deltaTime, 0.0f, extrapolateTimeMax); // Simulate PhysXEmulation.SimulatePhysX(ref position, ref rotation, ref velocity, ref angularVelocity, false, Vector3.zero, 0.0f, 0.0f, float.PositiveInfinity, float.PositiveInfinity, RigidbodyConstraints.None, deltaTime, Time.fixedDeltaTime); } } // Apply float lerpFactor = 25.0f; if (_syncPosition) { transform.localPosition = Vector3.Lerp(transform.localPosition, position, lerpFactor * Time.deltaTime); } if (_syncRotation) { transform.localRotation = Quaternion.Slerp(transform.localRotation, rotation, lerpFactor * Time.deltaTime); } if (_syncScale) { transform.localScale = Vector3.Lerp(transform.localScale, scale, lerpFactor * Time.deltaTime); } } else { // If the model isn't owned by anyone, set the transform position instantly. if (_syncPosition) { transform.localPosition = _model.position; } if (_syncRotation) { transform.localRotation = _model.rotation; } if (_syncScale) { transform.localScale = _model.scale; } } }