Platform SDK: DirectX |
The D3DUtil_SetViewMatrix helper function, from the D3dutil.cpp source file that is included with this SDK, creates a view matrix based on the camera location and a look-at point passed to it. It uses the Magnitude, CrossProduct, and DotProduct D3D_OVERLOADS helper functions.
HRESULT D3DUtil_SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom, D3DVECTOR& vAt, D3DVECTOR& vWorldUp ) { // Get the z basis vector, which points straight ahead. This is the // difference from the eyepoint to the lookat point. D3DVECTOR vView = vAt - vFrom; FLOAT fLength = Magnitude( vView ); if( fLength < 1e-6f ) return E_INVALIDARG; // Normalize the z basis vector vView /= fLength; // Get the dot product, and calculate the projection of the z basis // vector onto the up vector. The projection is the y basis vector. FLOAT fDotProduct = DotProduct( vWorldUp, vView ); D3DVECTOR vUp = vWorldUp - fDotProduct * vView; // If this vector has near-zero length because the input specified a // bogus up vector, let's try a default up vector if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) { vUp = D3DVECTOR( 0.0f, 1.0f, 0.0f ) - vView.y * vView; // If we still have near-zero length, resort to a different axis. if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) { vUp = D3DVECTOR( 0.0f, 0.0f, 1.0f ) - vView.z * vView; if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) return E_INVALIDARG; } } // Normalize the y basis vector vUp /= fLength; // The x basis vector is found simply with the cross product of the y // and z basis vectors D3DVECTOR vRight = CrossProduct( vUp, vView ); // Start building the matrix. The first three rows contains the basis // vectors used to rotate the view to point at the lookat point D3DUtil_SetIdentityMatrix( mat ); mat._11 = vRight.x; mat._12 = vUp.x; mat._13 = vView.x; mat._21 = vRight.y; mat._22 = vUp.y; mat._23 = vView.y; mat._31 = vRight.z; mat._32 = vUp.z; mat._33 = vView.z; // Do the translation values (rotations are still about the eyepoint) mat._41 = - DotProduct( vFrom, vRight ); mat._42 = - DotProduct( vFrom, vUp ); mat._43 = - DotProduct( vFrom, vView ); return S_OK; }
As with the world transformation, you call the IDirect3DDevice7::SetTransform method to set the view transformation, specifying the D3DTRANSFORMSTATE_VIEW flag in the first parameter. See Setting Transformations, for more information.
Visual Basic applications use the DirectX7.ViewMatrix method to create view matrix based on the camera location, a look-at point, an "up" vector (usually 0,1,0), and a roll value specified in radians.
The following example code, written in Visual Basic, shows how the ViewMatrix method can be used.
' For this example, the g_dx variable contains a valid reference ' to a global DirectX7 object. Dim matView As D3DMATRIX Dim vFrom As D3DVECTOR, _ vTo As D3DVECTOR, _ vUp As D3DVECTOR vFrom.x = 0: vFrom.y = 0: vFrom.z = -15 vTo.x = 0: vTo.y = 0: vTo.z = 0 vUp.x = 0: vUp.y = 1: vUp.z = 0 ' Initialize the matrix to the identity. g_dx.IdentityMatrix matView ' Create a view matrix with a camera at 0,0,-15, that points at the ' world-origin, with no rotation around the vFrom->vTo vector. Call g_dx.ViewMatrix(matView, vFrom, vTo, vUp, 0)
As with the world transformation, you call the Direct3DDevice7.SetTransform method to set the view transformation, specifying the D3DTRANSFORMSTATE_VIEW flag in the first parameter. See Setting Transformations, for more information.
Performance Optimization Direct3D uses the world and view matrices that you set to configure several of its internal data structures. Each time you set a new world or view matrix, the system recalculates the associated internal structures. Setting these matrices frequently—for example, 20000 times per frame—is computationally expensive. You can minimize the number of required calculations by concatenating your world and view matrices into a proverbial "world-view" matrix that you set as the world matrix, then set the view matrix to the identity. Keep cached copies of individual world and view matrices that you can modify, concatenate, and reset the world matrix as needed. (For clarity, Direct3D samples rarely employ this optimization.)