void CreateCubes()
    {
        Profiler.BeginSample("CreateCubes");

        Vector3 origin = GetOrigin();

        for (int i = 0; i < Constants.NumCubes; i++)
        {
            if (!cubes[i])
            {
                // cube initial create

                cubes[i] = (GameObject)Instantiate(cubePrefab, cubePositions[i] + origin, Quaternion.identity);

                cubes[i].layer = this.gameObject.layer;

                var rigidBody = cubes[i].GetComponent <Rigidbody>();

                rigidBody.maxDepenetrationVelocity = Constants.PushOutVelocity;           // this is *extremely* important to reduce jitter in the remote view of large stacks of rigid bodies

                NetworkInfo networkInfo = cubes[i].GetComponent <NetworkInfo>();

                networkInfo.touching.layer = GetTouchingLayer();

                networkInfo.Initialize(this, i);
            }
            else
            {
                // cube already exists: force it back to initial state

                var rigidBody = cubes[i].GetComponent <Rigidbody>();

                if (rigidBody.IsSleeping())
                {
                    rigidBody.WakeUp();
                }

                rigidBody.position        = cubePositions[i] + origin;
                rigidBody.rotation        = Quaternion.identity;
                rigidBody.velocity        = Vector3.zero;
                rigidBody.angularVelocity = Vector3.zero;

                ResetCubeRingBuffer(i);

                NetworkInfo networkInfo = cubes[i].GetComponent <NetworkInfo>();

                networkInfo.DetachCubeFromPlayer();

                networkInfo.SetAuthorityIndex(0);
                networkInfo.SetAuthoritySequence(0);
                networkInfo.SetOwnershipSequence(0);

                Renderer renderer = networkInfo.smoothed.GetComponent <Renderer>();

                renderer.material = authorityMaterials[0];

                networkInfo.m_positionError = Vector3.zero;
                networkInfo.m_rotationError = Quaternion.identity;

                cubes[i].transform.parent = null;
            }
        }

        Profiler.EndSample();
    }