Example #1
0
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;
}