Matrix4 Camera::CreatePerspectiveMatrix_() { // http://www.gamedev.net/topic/264248-building-a-projection-matrix-without-api/ const Vector2 frustumOffset(0.0f, 0.0f); Matrix4 retval = Matrix4::ZERO; Radian thetaY (field_of_view_ * 0.5f); float32 tanThetaY = std::tan(thetaY.ValueRadians()); float32 tanThetaX = tanThetaY * aspect_ratio_; float32 nearFocal = near_distance_ / focal_length_; float32 nearOffsetX = frustumOffset.x * nearFocal; float32 nearOffsetY = frustumOffset.y * nearFocal; float32 half_w = tanThetaX * near_distance_; float32 half_h = tanThetaY * near_distance_; float32 left = - half_w + nearOffsetX; float32 right = + half_w + nearOffsetX; float32 bottom = - half_h + nearOffsetY; float32 top = + half_h + nearOffsetY; // The code below will dealing with general projection // parameters, similar glFrustum and glOrtho. // Doesn't optimize manually except division operator, so the // code self-explanatory. float32 inv_w = 1 / (right - left); float32 inv_h = 1 / (top - bottom); float32 inv_d = 1 / (far_distance_ - near_distance_); // Calc matrix elements float32 A = 2 * near_distance_ * inv_w; float32 B = 2 * near_distance_ * inv_h; float32 C = (right + left) * inv_w; float32 D = (top + bottom) * inv_h; float32 q, qn; if (far_distance_ == 0) { // Infinite far plane q = Frustum::INFINITE_FAR_PLANE_ADJUST - 1; qn = near_distance_ * (Frustum::INFINITE_FAR_PLANE_ADJUST - 2); } else { q = - (far_distance_ + near_distance_) * inv_d; qn = -2 * (far_distance_ * near_distance_) * inv_d; } // NB: This creates 'uniform' perspective projection matrix, // which depth range [-1,1], right-handed rules // // [ A 0 C 0 ] // [ 0 B D 0 ] // [ 0 0 q qn ] // [ 0 0 -1 0 ] // // A = 2 * near / (right - left) // B = 2 * near / (top - bottom) // C = (right + left) / (right - left) // D = (top + bottom) / (top - bottom) // q = - (far + near) / (far - near) // qn = - 2 * (far * near) / (far - near) retval[0][0] = A; retval[0][2] = C; retval[1][1] = B; retval[1][2] = D; retval[2][2] = q; retval[2][3] = qn; retval[3][2] = -1; return retval; }