Here is my code:

take degrees for X and Y

if (mouseInput.MouseState.RightButton.Down) { basicCamera.RotateX(-mouseInput.MouseState.DeltaX * mouseRotationSpeed); basicCamera.RotateY(-mouseInput.MouseState.DeltaY * mouseRotationSpeed); }Then do quaternion multiply:

public void RotateX(float _degree_angle) { if (cameraType == CamType.ThirdPerson) { _degree_angle = -_degree_angle; } qRotation = Quaternion.Multiply(Quaternion.RotationAxis(Vector3.UnitX, MathUtil.DegreesToRadians(_degree_angle)), qRotation); UpdateViewMatrix(); } public void RotateY(float _degree_angle) { if (cameraType == CamType.ThirdPerson) { _degree_angle = -_degree_angle; } qRotation = Quaternion.Multiply(qRotation, Quaternion.RotationAxis(Vector3.UnitY, MathUtil.DegreesToRadians(_degree_angle))); UpdateViewMatrix(); }FInally update view matrix:

private void UpdateViewMatrix() { qRotation = Quaternion.Normalize(qRotation); if (CameraType == CamType.ThirdPerson) { ViewMatrix = Matrix.Translation(Vector3.Negate(position)) * Matrix.RotationQuaternion(qRotation); position -= new Vector3(ViewMatrix.M13, ViewMatrix.M23, ViewMatrix.M33) * radius; ViewMatrix = Matrix.LookAtLH(position, lookAt, new Vector3(ViewMatrix.M12, ViewMatrix.M22, ViewMatrix.M32)); } else { ViewMatrix = Matrix.Translation(Vector3.Negate(position)) * Matrix.RotationQuaternion(qRotation); } }P.S. quaternion multiply order in Y rotation changed because it prevent camera to move around its z-axis, but it causes it to turn upside down when moving on diagonal. If I dont change the order, then moving on diagonal is good, but camera is rotating on z-axis each time I move it around x and y axis.

You aren't actually creating accumulators and building the matrix each frame from scratch. You're modifying "qRotation" every time you call RotateX/RotateY, so if you rotate 45 degrees on the X and Y, next frame if you do the same you're going to be rotating from within that previous "diagonal" space. Building it from scratch prevents you from ever rotating outside of the unit X/Y/Z space.