This is the set of methods that we have currently:
public static void OrthoLH(float width, float height, float znear, float zfar, out Matrix result){}public static Matrix OrthoLH(float width, float height, float znear, float zfar){}public static void OrthoRH(float width, float height, float znear, float zfar, out Matrix result){}public static Matrix OrthoRH(float width, float height, float znear, float zfar){}public static void OrthoOffCenterLH(float left, float right, float bottom, float top, float znear, float zfar, out Matrix result){}public static Matrix OrthoOffCenterLH(float left, float right, float bottom, float top, float znear, float zfar){}public static void OrthoOffCenterRH(float left, float right, float bottom, float top, float znear, float zfar, out Matrix result){}public static Matrix OrthoOffCenterRH(float left, float right, float bottom, float top, float znear, float zfar){}public static void PerspectiveLH(float width, float height, float znear, float zfar, out Matrix result){}public static Matrix PerspectiveLH(float width, float height, float znear, float zfar){}public static void PerspectiveRH(float width, float height, float znear, float zfar, out Matrix result){}public static Matrix PerspectiveRH(float width, float height, float znear, float zfar){}public static void PerspectiveFovLH(float fov, float aspect, float znear, float zfar, out Matrix result){}public static Matrix PerspectiveFovLH(float fov, float aspect, float znear, float zfar){}public static void PerspectiveFovRH(float fov, float aspect, float znear, float zfar, out Matrix result){}public static Matrix PerspectiveFovRH(float fov, float aspect, float znear, float zfar){}public static void PerspectiveOffCenterLH(float left, float right, float bottom, float top, float znear, float zfar, out Matrix result){}public static Matrix PerspectiveOffCenterLH(float left, float right, float bottom, float top, float znear, float zfar){}public static void PerspectiveOffCenterRH(float left, float right, float bottom, float top, float znear, float zfar, out Matrix result){}public static Matrix PerspectiveOffCenterRH(float left, float right, float bottom, float top, float znear, float zfar){}
As you can see, there are quite a few. We double each method to provide a ref version for those who want very high speeds and a normal version for people who don't care as much.
My new proposed version looks like this:
public static Matrix PerspectiveFov(Handedness handedness, float fov, float aspect, float znear, float zfar){ float yScale = (float)(1.0 / Math.Tan(fov / 2.0f)); float xScale = yScale / aspect; float width = 2 * znear / xScale; float height = 2 * znear / yScale; return Projection(ProjectionType.Perspective, handedness, -width / 2.0f, width / 2.0f, -height / 2.0f, height / 2.0f, znear, zfar);}public static Matrix Perspective(Handedness handedness, float width, float height, float znear, float zfar){ return Projection(ProjectionType.Perspective, handedness, -width / 2.0f, width / 2.0f, -height / 2.0f, height / 2.0f, znear, zfar);}public static Matrix Orthographic(Handedness handedness, float width, float height, float znear, float zfar){ return Projection(ProjectionType.Orthographic, handedness, -width / 2.0f, width / 2.0f, -height / 2.0f, height / 2.0f, znear, zfar);}public static Matrix Projection(ProjectionType type, Handedness handedness, float left, float right, float bottom, float top, float znear, float zfar){ Matrix result = new Matrix(); result.M11 = 2.0f / (right - left); result.M22 = 2.0f / (top - bottom); result.M33 = 1.0f / (zfar - znear); result.M43 = znear / (znear - zfar); if (type == ProjectionType.Orthographic) { result.M41 = (left + right) / (left - right); result.M42 = (top + bottom) / (bottom - top); result.M44 = left; } else { result.M11 *= znear; result.M22 *= znear; result.M33 *= -zfar; result.M43 *= zfar; result.M31 = (left + right) / (left - right); result.M32 = (top + bottom) / (bottom - top); result.M34 = 1.0f; } if (handedness == Handedness.Right) { result.M31 *= -1.0f; result.M32 *= -1.0f; result.M33 *= -1.0f; result.M34 *= -1.0f; } return result;}
Note that I haven't listed the ref overloads here. With ref overloads, the new method would have 8 total functions, whereas the old method has 20. Now, ignoring the actual creation of the matrix in there, since I haven't quite tested it yet, which design do you think is better? Here is my thought process so far:
First, the pros. The new method has drastically less functions to maintain, and everything boils down to the one actual method for implementation. Additionally, it better follows the design guidelines of .NET by not encoding functional information into the name and instead allowing users to specify it via enum. I find it to be a slightly cleaner method over all.
Now the cons. The new method is slightly less optimal due to the extra branches occurring. This is less bad than it seems, however, since creating projection matrices is never done more than several times over the course of a frame, and usually much less than that, so it's unlikely to make any sort of impact on performance. If this were determined to be a huge issue, I have a slightly more hackish version of Projection that avoids the branches by making tricky use of the enum values [grin] Also, the new version breaks all existing code using SlimDX, since we'd be relying on these slightly new names. As said before, we have a new "2.0" version coming that will encapsulate all of these breaking changes, but it could still be considered an issue.
Ultimately the pros and cons nearly balance each other, and I think it comes down to a style issue, so I'm trying to take a poll here. Which do you prefer? I've talked to several people already, and the responses have been all over the board. Some people like the new methods and say the style is cleaner, some people want the old ones back, and a few people have said that the new method is better but they still prefer the old one due to stylistic reasons. How about you? What's your opinion?
I vote for the newer one. I think it's a cleaner interface, and allows more flexibility for the app in terms of how it creates its projection matrices.