本文大部分内容转自七星重剑的
在Qt窗口里用D3D画转动的三角形一文,加上点滴个人研究笔记。
先上个自己的运行结果图吧:
现在的问题是只有“脏”了才画,也就是才去调用如下的method;不是三角形没动,是动了但是没画出来,我们看不见。
1 void QD3DWidget::paintEvent(QPaintEvent *)
2 {
3 if (updatesEnabled())
4 {
5 d3dDraw();
6 }
7 }
用个timer去解决这个问题?
这老外的帖子对我帮助很大,不搞下面的两条整个QD3DWidget都看不到:
Using
Direct3D 9 with Qt - flicker problem
According to
the Qt docs, if you want to use GDI or Direct3D on Windows with Qt, you need
to: 1) Override QWidget::paintEngine to return
NULL 2) Call QWidget::setAttribute(Qt::WA_PaintOnScreen, true)
完整代码:
D3D相关代码
1 #pragma once
2
3 #include <d3d9.h>
4 #include <d3dx9.h>
5 #include <mmsystem.h>
6
7 #pragma comment(lib, "d3d9.lib")
8 #pragma comment(lib, "d3dx9.lib")
9 #pragma comment(lib, "winmm.lib")
10
11 LPDIRECT3D9 g_pD3D;
12 LPDIRECT3DDEVICE9 g_pDevice;
13 LPDIRECT3DVERTEXBUFFER9 g_pVB;
14
15 //const DWORD D3DFVF_CUSTOMVERTEX = (D3DFVF_XYZ | D3DFVF_DIFFUSE);
16 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)
17
18 struct CUSTOMVERTEX
19 {
20 float x;
21 float y;
22 float z;
23 DWORD color;
24 };
25
26 // 此代码模块中包含的函数的前向声明:
27 ATOM MyRegisterClass(HINSTANCE hInstance);
28 BOOL InitInstance(HINSTANCE, int);
29 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
30 INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
31
32 LRESULT InitD3D(HWND hWnd)
33 {
34 if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
35 {
36 return E_FAIL;
37 }
38
39 D3DPRESENT_PARAMETERS d3dpp;
40
41 ZeroMemory(&d3dpp, sizeof (D3DPRESENT_PARAMETERS));
42
43 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
44 d3dpp.Windowed = true;
45 d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
46 d3dpp.EnableAutoDepthStencil = TRUE;
47 d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
48
49 if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, // 图形适配器索引。
50 D3DDEVTYPE_HAL, // 设备类型。
51 hWnd, // 渲染主窗口。
52 D3DCREATE_HARDWARE_VERTEXPROCESSING, // 顶点处理类型。
53 &d3dpp, // D3DPRESENT_PARAMETERS。
54 &g_pDevice))) // g_pDevice,D3D设备指针。
55 {
56 return E_FAIL;
57 }
58
59 g_pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
60 g_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
61 g_pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
62 return D3D_OK;
63 }
64
65 LRESULT InitVB()
66 {
67 CUSTOMVERTEX vertices[3] =
68 {
69 { -1.0f,-1.0f, 0.0f, 0xffff0000},
70 { 1.0f,-1.0f, 0.0f, 0xff0000ff},
71 { 0.0f, 1.0f, 0.0f, 0xffffffff}
72 };
73
74
75
76 if (FAILED(g_pDevice->CreateVertexBuffer(3 * sizeof (CUSTOMVERTEX), // 要创建的缓冲区大小(自定义定点结构体大小 * 数目)。
77 0, // D3DUSAGE_*。
78 D3DFVF_CUSTOMVERTEX, // 自定义顶点标志。
79 D3DPOOL_DEFAULT, // 资源类型。
80 &g_pVB, // g_pVB,顶点缓冲指针。
81 NULL)))
82 {
83 return E_FAIL;
84 }
85
86 void* pVertices;
87
88 if (FAILED(g_pVB->Lock(0, sizeof (vertices), (void**)&pVertices, 0)))
89 {
90 return E_FAIL;
91 }
92
93 memcpy(pVertices, vertices, sizeof (vertices));
94
95 g_pVB->Unlock();
96
97 return D3D_OK;
98 }
99
100 void Render()
101 {
102 D3DXMATRIX matWorld;
103 D3DXMATRIX matProj;
104 D3DXMATRIX matView;
105
106 UINT iTime = timeGetTime() % 1000;
107 FLOAT fAngle = iTime * ( 2.0f * D3DX_PI ) / 1000.0f;
108 D3DXMatrixRotationY( &matWorld, fAngle );
109
110 g_pDevice->SetTransform( D3DTS_WORLD, &matWorld );
111
112 // Create and set the view matrix
113 D3DXMatrixLookAtLH(&matView,
114 &D3DXVECTOR3(0.0f, 0.0f, -2.0f),
115 &D3DXVECTOR3(0.0f, 0.0f, 0.0f),
116 &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
117
118 g_pDevice->SetTransform(D3DTS_VIEW, &matView);
119
120 // Create and set the projection matrix
121 D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4.0f, 1.33333f, 1.0f, 1000.0f);
122
123 g_pDevice->SetTransform(D3DTS_PROJECTION, &matProj);
124
125 g_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);
126
127 g_pDevice->BeginScene();
128
129 g_pDevice->SetStreamSource(0, g_pVB, 0, sizeof (CUSTOMVERTEX));
130 g_pDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
131 g_pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 1);
132
133 g_pDevice->EndScene();
134
135 g_pDevice->Present(NULL, NULL, NULL, NULL);
136 }
137
138 void Cleanup()
139 {
140 if (g_pVB != NULL)
141 {
142 g_pVB->Release();
143 }
144
145 if (g_pDevice != NULL)
146 {
147 g_pDevice->Release();
148 }
149
150 if (g_pD3D != NULL)
151 {
152 g_pD3D->Release();
153 }
154 }
1 // QD3DWidget.h
2
3 #pragma once
4
5 #include <Qt/qwidget.h>
6
7 class QD3DWidget : public QWidget
8 {
9 Q_OBJECT
10
11 public:
12 QD3DWidget(QWidget* parent = 0);
13 ~QD3DWidget();
14
15 QPaintEngine* paintEngine() const;
16
17 protected:
18 virtual void initializeD3D();
19 virtual void paintD3D();
20
21 void paintEvent(QPaintEvent *);
22
23 virtual void d3dInit();
24 virtual void d3dDraw();
25
26 bool initialized() const {return m_bInit;}
27
28 void MsgBox();
29 private:
30 bool m_bInit;
31 };
1 // QD3DWidget.cpp
2
3 #include "QtD3DWidget.h"
4 #include "D3D.h"
5 #include <qtimer.h>
6
7 void QD3DWidget::MsgBox()
8 {
9 QMessageBox mb(this);
10
11 mb.exec();
12 }
13
14 QD3DWidget::QD3DWidget(QWidget* parent /* = 0 */) : QWidget(parent), m_bInit(false)
15 {
16 resize(QSize(400, 300));
17 setAttribute(Qt::WA_PaintOnScreen, true);
18
19 QTimer *timer = new QTimer(this);
20 connect(timer, SIGNAL(timeout()), this, SLOT(update()));
21 timer->start(20);
22 }
23
24 QD3DWidget::~QD3DWidget()
25 {
26
27 }
28
29 void QD3DWidget::initializeD3D()
30 {
31 InitD3D(winId());
32 InitVB();
33
34 m_bInit = true;
35 }
36
37 void QD3DWidget::paintD3D()
38 {
39 Render();
40 }
41
42 void QD3DWidget::paintEvent(QPaintEvent *)
43 {
44 if (updatesEnabled())
45 {
46 d3dDraw();
47 }
48 }
49
50 void QD3DWidget::d3dInit()
51 {
52 initializeD3D();
53 }
54
55 void QD3DWidget::d3dDraw()
56 {
57 if (!initialized())
58 {
59 d3dInit();
60 }
61
62 paintD3D();
63 }
64
65 QPaintEngine* QD3DWidget::paintEngine() const
66 {
67 return NULL;
68 }
红字部分是根据原作者的文章自己研究后加上去的,现在的代码已经可以实现窗体中三角型的转动,关键就是利用定时器每隔20ms强制窗体重绘(update()),因为不太熟悉Qt,搞了半天才知道是update这个函数。
用如下测试代码就可以得到开头的结果画面:
1 #include "stdafx.h"
2 #include "QtD3DWidget.h"
3 #include <qapplication.h>
4
5 int _tmain(int argc, char* argv[])
6 {
7 QApplication app(argc, argv);
8
9 QD3DWidget* d3dWidget = new QD3DWidget();
10
11 d3dWidget->show();
12
13 return app.exec();
14 }