Rigidbody wall slide without velocity loss

I’ve some test scene set up like this, once unity enter play-mode sphere 1 & 2 will start moving forward using the same velocity. Sphere 1 will bump into some cubes along the way. The outcome I expect is both spheres will always have the same z position value, which means no speed loss during the collision for sphere 1.

Rigidbody of both sphere setting are :
Mass = 1, Drag = 0, angular drag = 0, use gravity = false,is kinematic = false, Interpolate = Interpolate, Collision Detection = Continuous.

Physics material of both cubes and spheres are using :

Dynamic friction = 0,
Static friction = 0,
Bounciness = 0,
Friction Combine = Minimum,
Bounce Combine = Maximum.

I have been using following code to handle collision and velocity changes :

	private void OnCollisionEnter(Collision other)
	{
		Debug.Log(body.velocity);
		body.constraints = RigidbodyConstraints.FreezeRotation
		                   | RigidbodyConstraints.FreezePositionY;
		body.velocity = Vector3.forward * 5f + Vector3.left * 5f;
		Debug.Log(body.velocity);
	}

	private void OnCollisionExit(Collision other)
	{
		body.constraints = RigidbodyConstraints.FreezeRotation
		                   | RigidbodyConstraints.FreezePositionY
		                   | RigidbodyConstraints.FreezePositionX;
		Debug.Log(body.velocity);
	}

According to the log message, the velocity of sphere 1 has been reduced most of the time when it collide with the cude in OnCollisionEnter().
113696-15220398521.png

As result, sphere 1’s Z position is incremetally behind sphere 2.

Is there something I been missing out or did I missunderstood how velocity of a rigidbody work?

The problem is that you’re freezing the X position whenever it’s not colliding, so the instant it does collide, it has no option but to come to a stop, untill your OnCollisionEnter script enables it to move again. That’s why the debug shows a low Y velocity combined with a zero X velocity first, then a correct velocity on both at the end of the method (in the second debug)

Try removing the FreezePositionX altogether, and instead OnCollisionExit just make it so
body.velocity = Vector3.forward * 5f;

In case anyone has the same problem, I’ve managed to fix this with the following script :

using UnityEngine;

public class TestBoundaryCollision : MonoBehaviour
{
	public float Speed;
	public bool Moving = false;
	private Rigidbody body;
	private SphereCollider sc;
	private RaycastHit castHit;

	// Use this for initialization
	void Start()
	{
		body = GetComponent<Rigidbody>();
		sc = GetComponent<SphereCollider>();
	}

	private void FixedUpdate()
	{
		if (!Moving)
		{
			return;
		}

		if (Physics.SphereCast(body.position,
								sc.radius + Speed * Time.fixedDeltaTime,
								transform.forward,
								out castHit,
								Speed * Time.fixedDeltaTime))
		{
			body.velocity = new Vector3(Mathf.Sign(castHit.normal.x) * Speed, 0f, Speed);
		}
		else
		{
			body.velocity = transform.forward * Speed;
		}
	}
}