Однажды, у меня появилась необходимость использования Direct3D совместно с Qt. После нескольких дней поисков в интернете, я нашел всего лишь какие-то обрывки информации. Полноценного описания механизма использования Direct3D не было нигде. В результате, после долгих изысканий я добился того, чего хотел:)
Под катом находится инструкция «сближения“ Direct3D и Qt, а так же код виджета, который можно использовать as is
При написании данной статьи использовались следующие средства:
Если Вы используете другую. IDE, то момент сборки будет несколько отличаться. Я привожу пример сборки, только для VS2008. Если вы уверены, что в вашей сборке присутствует поддержка direct3d engine, тогда пропустите шаг конфигурирования и сборки Qt.
Direct3DWidget.h
Direct3DWidget.cpp
Пример использования:
Казалось бы теперь есть все, чтобы спокойно использовать direct3d с отличным фреймворком Qt, но, к сожалению, мною были обнаружены некоторые подводные камни.
После того, как я стал использовать Direct3d, на некоторых компьютерах, вместо картинки отрисованной Direct3d был экран, зарисованный цветом фона. Я перебрал все комбинации аттрибутов, но убрать данный дефект так и не смог. Так же не удалось выявить причину неправильной работы direct3d engine на некоторых машинах. Т.к документация по Qt утверждает, что «This functionality is experimental.», то можно предположить, что дело в сыроватости поддержки direct3d.
Но, данный недостаток не может быть причиной не использования Direct3D:). Пока trolltech допиливает direct3d до stable state можно воспользоваться следующим workaround’ом:
Закомментируем вызов Rendering () в paintEvent:
и в место использования добавим следующий код:
я добавил этот код в код примера, приведенного мною выше.
Так же не забудьте включить заголовок QTimer
Приятного Вам использования Direct3d API в Qt, и не забывайте, что приложение, должно быть запущено с опцией -direct3d, я включил эту опцию в код моего примера использования.
Под катом находится инструкция «сближения“ Direct3D и Qt, а так же код виджета, который можно использовать as is
При написании данной статьи использовались следующие средства:
- Qt 4.5.0
- VS2008 SP1
- DirectX SDK August 2008
Если Вы используете другую. IDE, то момент сборки будет несколько отличаться. Я привожу пример сборки, только для VS2008. Если вы уверены, что в вашей сборке присутствует поддержка direct3d engine, тогда пропустите шаг конфигурирования и сборки Qt.
Конфигурирование и сборка Qt
- Первым шагом необходимо настроить переменные окружения для DirectX, для этого в консоли выполняем следующую команду:
> "%DXSDK_DIR%\Utilities\Bin\dx_setenv.cmd“ -
Переходим в каталог Qt и конфигурируем его. В моем случае это выглядело так > configure -direct3d -platform win32-msvc2008
-direct3d можно опустить, этот параметр должен быть вычислен конфигуратором.
Если все прошло нормально, то в появившемся выводе конфигуратора будет: Direct3D support…yes
- Делаем nmake, и если не будет проблем то дожидаемся конца сборки. Я столкнулся с проблемой, при сборке была ошибка unresolved external связанная с Direct3D. Чтобы ее исправить, идем в %QTDIR%\src\gui\ и в обоих Makefile’ах(release и debug) меняем dxguid.lib на "%DXSDK_DIR%\Lib\x86\dxguid.lib»(или x64 в зависимости от того, под какую платформу вы собираете). После этого проблема должна исчезнуть так что дожидаемся окончания сборки.
Код виджета
Direct3DWidget.h
#ifndef DIRECT3DWIDGET_H
#define DIRECT3DWIDGET_H
#include
#include
#include
class Direct3DWidget : public QWidget
{
Q_OBJECT
CComPtr m_pD3D;
CComPtr m_pd3dDevice;
public:
Direct3DWidget(QWidget *parent = );
~Direct3DWidget();
bool InitDirect3D();
public slots:
bool Rendering();
private:
void paintEvent(QPaintEvent *pEvent);
};
#endif
Direct3DWidget.cpp
#include "Direct3DWidget.h"
Direct3DWidget::Direct3DWidget(QWidget *parent /* = 0 */): QWidget(parent)
{
setAttribute(Qt::WA_PaintOnScreen);
}
Direct3DWidget::~Direct3DWidget()
{
}
bool Direct3DWidget::InitDirect3D()
{
m_pD3D = Direct3DCreate9( D3D_SDK_VERSION);
if(!m_pD3D)
return false;
D3DPRESENT_PARAMETERS d3dpp = {};
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
HRESULT hrResult = m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, winId(),
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&d3dpp, &m_pd3dDevice );
if(FAILED(hrResult))
return false;
return true;
}
bool Direct3DWidget::Rendering()
{
if(m_pd3dDevice == )
return false;
m_pd3dDevice->Clear(, , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255, 255, ), 1.0f, );
if(SUCCEEDED(m_pd3dDevice->BeginScene()))
{
m_pd3dDevice->EndScene();
}
m_pd3dDevice->Present( , , , );
return true;
}
void Direct3DWidget::paintEvent(QPaintEvent *pEvent)
{
Q_UNUSED(pEvent);
Rendering();
}
Пример использования:
#include <QtGui/QWidget>
#include <QtGui/QApplication>
#include <QtGui/QHBoxLayout>
#include "Direct3DWidget.h"
int main(int argc, char *argv[])
{
//------------------------------Start initialization
//Additional parameters, just add a parameter separated by comma
std::string aAdditionalParameters[] = {"-direct3d"};
int iRealArgumentAmount = argc + sizeof(aAdditionalParameters)/sizeof(std::string);
//This double pointer will contain parameters from argv and
//statical parameters which necessary for this application
char** pArguments = new char*[iRealArgumentAmount];
//Copy all source(from the command line) parameters
for(int i = ; i < argc; ++i)
{
*(pArguments + i) = new char[ strlen(argv[i]) + 1 ];
strcpy( *(pArguments + i), argv[i] );
}
//Append parameters we want to add
for(int i = argc, j = ; i < iRealArgumentAmount; ++i, ++j)
{
*(pArguments + i) = new char[ aAdditionalParameters[j].size() + 1 ];
strcpy( *(pArguments + i), aAdditionalParameters[j].c_str() );
}
QApplication xApplication(iRealArgumentAmount, pArguments);
for(int i = ; i < iRealArgumentAmount; ++i)
delete []*(pArguments + i);
delete []pArguments;
//--------------------------------Initialization complete
QWidget xMainWindow;
Direct3DWidget* xScene = new Direct3DWidget(&xMainWindow);
QHBoxLayout* xMainLayout = new QHBoxLayout;
xMainLayout->addWidget(xScene);
xMainWindow.setLayout(xMainLayout);
//It is important to initialize the Direct3d after the widget was embedded to the window
xScene->InitDirect3D();
xMainWindow.show();
return xApplication.exec();
}
Казалось бы теперь есть все, чтобы спокойно использовать direct3d с отличным фреймворком Qt, но, к сожалению, мною были обнаружены некоторые подводные камни.
После того, как я стал использовать Direct3d, на некоторых компьютерах, вместо картинки отрисованной Direct3d был экран, зарисованный цветом фона. Я перебрал все комбинации аттрибутов, но убрать данный дефект так и не смог. Так же не удалось выявить причину неправильной работы direct3d engine на некоторых машинах. Т.к документация по Qt утверждает, что «This functionality is experimental.», то можно предположить, что дело в сыроватости поддержки direct3d.
Но, данный недостаток не может быть причиной не использования Direct3D:). Пока trolltech допиливает direct3d до stable state можно воспользоваться следующим workaround’ом:
Закомментируем вызов Rendering () в paintEvent:
void Direct3DWidget::paintEvent(QPaintEvent *pEvent)
{
Q_UNUSED(pEvent);
//Rendering();
}
и в место использования добавим следующий код:
...
//It is important to initialize the Direct3d after the widget was embedded to the window
xScene->InitDirect3D();
xMainWindow.show();
QTimer xTimer;
QWidget::connect(&xTimer, SIGNAL(timeout()), xScene, SLOT(Rendering()));
xTimer.start(100);
return xApplication.exec();
...
я добавил этот код в код примера, приведенного мною выше.
Так же не забудьте включить заголовок QTimer
Приятного Вам использования Direct3d API в Qt, и не забывайте, что приложение, должно быть запущено с опцией -direct3d, я включил эту опцию в код моего примера использования.
via habrahabr
Очень подробно описал!Но для чего может пригодится использование Direct3D совместно с Qt?
ReplyDeleteДля простоты разработки, например.
ReplyDeleteЭта статья может пригодится
ReplyDeleteХорошо написал, буду изучать.
ReplyDeleteпрестижно, модно, молодежно! Но непонятно для чего
ReplyDeleteГодно, давно искал что-то подобное, спасибо.
ReplyDeleteПолезная инфа, как раз сейчас вникаю в QT.
ReplyDelete