microsoftxiao

记忆 流逝

导航

ViewPort视图[转]

Working with the Viewport - 使用视图工作,视图是一个矩形区域,由于无知我还以为视图可以进行坐标变换呢。但是视图却可以实现类似3DS Max那样的前视,侧视,俯视的效果。

After you have finished the three transformation steps, the device still needs to determine how the data is finally mapped to each pixel. You help the device do this by defining a viewport. By default, the viewport is defined by the size of the window in a windowed application or the resolution of the screen in a full-screen application. Therefore, you often don't need to set it explicitly. However, Direct3D also allows you to specify a portion of the window as a viewport. This is useful when you are rendering multiple views in the same window, as shown earlier in this chapter in the 1steps2.exe example. The four viewports were made visible in Figure 6.17 by painting two white lines.

Click To expand
Figure 6.17: Viewports

You define a viewport with the D3DVIEWPORT9 structure.

typedef struct _D3DVIEWPORT9
{
DWORD X;
DWORD Y;
DWORD Width;
DWORD Height;
float MinZ;
float MaxZ;
} D3DVIEWPORT9;

The X, Y, Width, and Height values correspond to the viewport rectangle (see Figure 6.18).


Figure 6.18: The viewport rectangle

This structure defines the rectangular position of the viewport within the window or screen, as well as two additional members that indicate the depth ranges into which the scene will be rendered. Direct3D assumes that the x value ranges from 1.0f to 1.0f and that the y value ranges from 1.0f to 1.0f. These values indicate the depth range into which the scene will be rendered, and are not used for clipping. (This change was introduced in DirectX 8; in DirectX 7, these members were used for clipping.) Normally these members are set to 0.0f and 1.0f to render to the entire range of depth values in the depth buffer. To render a heads-up display, for example, you might set both values to 0.0f to force the system to render it in the foreground. Before you set a new viewport, you should save the old viewport with GetViewport() so you can reset the viewport when you are finished rendering.

HRESULT GetViewport(D3DVIEWPORT9 *pViewport);

With a copy of the old viewport, you can set a new one with the SetViewport() function, which has the same syntax as GetViewport().

HRESULT SetViewport(D3DVIEWPORT9 *pViewport);

This defines a new subsection of the window; drawing occurs in that rectangle. If a new viewport is outside the boundaries of the device, SetViewport() will fail. Please note that the aspect (width-to-height ratio) of the viewport rectangle should match the aspect of the projection matrix, or the objects might look squished.

The source code of the example 1steps2 shows the use of four viewports. These viewports are declared in the application class.

D3DVIEWPORT9 m_RViewport;
D3DVIEWPORT9 m_SRTViewport;
D3DVIEWPORT9 m_TRViewport;
D3DVIEWPORT9 m_RTRSViewport;

The first viewport will hold the view that shows the quad transformed by the rotation matrix only, as the capital R in the name implies. The second viewport will hold the view that shows the quad transformed by a scale-rotate-translate matrix, as the capital SRT in the name implies. The third viewport will hold the view that shows the quad transformed by a translate-rotate matrix, as the capital TR implies. The fourth viewport will hold the view that shows the quad transformed by a rotate-translate-rotate-scale matrix, as the capital RTRS implies. The size of the four viewports is set in RestoreDeviceObjects(), which means that every change of the window size will recalculate these sizes.

// Setup the sub-viewports
D3DVIEWPORT9 MainViewport;
m_pd3dDevice->GetViewport(&MainViewport);
// Each viewport fills a quarter of the window
m_RViewport.Width =
m_SRTViewport.Width =
m_TRViewport.Width =
m_RTRSViewport.Width = MainViewport.Width / 2;
m_RViewport.Height =
m_SRTViewport.Height =
m_TRViewport.Height =
m_RTRSViewport.Height = MainViewport.Height / 2;
m_RViewport.Y = m_SRTViewport.Y = 0;
m_RViewport.X = m_TRViewport.X = 0;
m_TRViewport.Y = m_RTRSViewport.Y = MainViewport.Height / 2;
m_SRTViewport.X = m_RTRSViewport.X = MainViewport.Width / 2;
// Set the full Z range for each viewport
m_RViewport.MinZ =
m_SRTViewport.MinZ =
m_TRViewport.MinZ =
m_RTRSViewport.MinZ = 0.0f;
m_RViewport.MaxZ =
m_SRTViewport.MaxZ =
m_TRViewport.MaxZ =
m_RTRSViewport.MaxZ = 1.0f;

In this code, the current viewport is retrieved first. This viewport should hold the size of the window's client area. Next, the rectangle is divided into four equal rectangles, and the four viewports are provided with the values of these four rectangles. Please note that you must use capitalized variables to provide the .X and .Y values.

The DrawPrimitiveIndex() functions draw the quad in Render() into the viewport after each viewport is set.

// Draw the rotated data
m_pd3dDevice->SetViewport(&m_RViewport);
m_matWorld = RotationMatrix1;
m_pd3dDevice->SetTransform(D3DTS_WORLD, &m_matWorld);
m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,
0,
0,
4,  // number of vertices
0,
2); // number of primitives

You are familiar with the DrawIndexedPrimitive() function from Chapter 5. After you draw the quad, you draw all the text that displays information about the graphics card or marks the different viewports. You must do this in the original viewport that spans the entire window's client area. You do this with a call to SetViewport().

// Set the viewport back to the full window. This ensures
// that any other processing (such as Clear or the DrawText functions) takes place
// over the full window.
m_pd3dDevice->SetViewport(&MainViewport);
// Output statistics
m_pFont->DrawText( 2, 0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
m_pFont->DrawText( 2, 40, D3DCOLOR_ARGB(255,255,255,255), _T("RotMat1 alone") );
m_pFont->DrawText( m_SRTViewport.X, m_SRTViewport.Y, D3DCOLOR_ARGB(255,255,255,255),
_T("TransMat * RotMat1 * ScalMat") );
m_pFont->DrawText( m_TRViewport.X, m_TRViewport.Y, D3DCOLOR_ARGB(255,255,255,255),
_T("RotMat1 * TransMat") );
m_pFont->DrawText( m_RTRSViewport.X, m_RTRSViewport.Y, D3DCOLOR_ARGB(255,255,255,255),
_T("ScalMat * RotMat2 * TransMat * RotMat1") );

I used the viewport dimensions to position the text at the respective viewport edges. You don't need to release the viewports in the DeleteDeviceObjects() or FinalCleanup() functions because they are not COM objects.

To summarize the usage of viewports in a few words: By retrieving the viewport data via GetViewport(), you fill a viewport structure with the size of the viewport and the MinX and MinY values, which are provided to the depth buffer. You set a viewport with SetViewport() just before the DrawPrimitive*() command. After you have finished drawing, you should restore the original viewport to clear the entire render target in one pass and to enable text drawing with the font class provided by the Direct3D framework.

Now you are coming to an important feature that I used throughout the examples in this chapter but did not present up to this point—depth buffering.

posted on 2006-03-27 21:50  龙巢NET刀  阅读(848)  评论(0)    收藏  举报