(The specific order will depend on the multiplication conventions in your environment, but left = more global / right = more local is a common choice)
This is equivalent to storing up the net total yaw and total pitch you want, then always applying the net result all at once, from scratch (provided you keep totalPitch clamped):
// Form a view vector using total pitch & yaw as spherical coordinates. Vector3 forward = new Vector3( Mathf.cos(pitchtotalPitch) * Mathf.sin(yawtotalYaw), Mathf.sin(pitchtotalPitch), Mathf.cos(pitchtotalPitch) * Mathf.cos(yawtotalYaw)); // Construct an orientation or view matrix pointing in that direction. transform.rotation = Quaternion.LoockRotationLookRotation(forward, new Vector3(0, 1, 0));
This global/local hybrid strategy isn't always the right fix. For example, in a game with 3D flight/swimming, you might want to be able to point straight up / straight down and still have full control. But with this setup you'll hit gimbal lock - your yaw axis (global up) becomes parallel to your roll axis (local forward), and you have no way to look left or right without twisting.
What you can do instead in cases like this is to use pure local rotations like we started with in the question above (so your controls feel the same no matter where you're looking), which will initially let some roll creep in - but then we correct for it.
For example, we can use local rotations to update our forward"forward" vector, then use that forward vector together with a reference up"up" vector to construct our final orientation. (Using, for example, Unity's Quaternion.LookRotation method, or manually constructing an orthonormal matrix from these vectors) By controlling the up vector, we control the roll or twist.