Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: ixSci от Март 31, 2009, 11:03



Название: Direct3D widget
Отправлено: ixSci от Март 31, 2009, 11:03
Всем привет,

Мне нужно сделать виджет внутри которога можно будет рисоват с помощью Direct3D
делаю так:
.h
Код
C++ (Qt)
class Direct3DWidget : public QWidget
{
Q_OBJECT
 
public:
Direct3DWidget(QWidget *parent = 0);
~Direct3DWidget();
 
bool InitDirect3D();
public slots:
bool Rendering();
private:
 
void paintEvent(QPaintEvent *p)
{
Rendering();
}
QPaintEngine* paintEngine()
{
return NULL;
}
 
LPDIRECT3D9 m_pD3D;
LPDIRECT3DDEVICE9 m_pd3dDevice;
};
.cpp
Код
C++ (Qt)
Direct3DWidget::Direct3DWidget(QWidget *parent /* = 0 */)
{
setFixedSize(200, 200);
setAutoFillBackground(false);
setAttribute(Qt::WA_PaintOnScreen, true);
}
Direct3DWidget::~Direct3DWidget()
{
if( m_pd3dDevice != NULL)
m_pd3dDevice->Release();
 
if( m_pD3D != NULL)
m_pD3D->Release();
}
bool Direct3DWidget::InitDirect3D()
{
m_pD3D = Direct3DCreate9( D3D_SDK_VERSION);
if( !m_pD3D)
return false;
 
D3DPRESENT_PARAMETERS d3dpp = {0};
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 hr = m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, winId(),
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&d3dpp, &m_pd3dDevice );
if( FAILED(hr) || !m_pd3dDevice)
return false;
}
bool Direct3DWidget::Rendering()
{
if(m_pd3dDevice == NULL)
return false;
m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255, 255, 0), 1.0f, 0);
if(SUCCEEDED(m_pd3dDevice->BeginScene()))
{
m_pd3dDevice->EndScene();
}
m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
return true;
}
 
main
Код
C++ (Qt)
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
 
QMainWindow window;
Direct3DWidget* widget = new Direct3DWidget(&window);
 
window.show();
widget->InitDirect3D();
return a.exec();
}

В результате ничего не рисуется  >:(
Кто нибудь может сказать, что не так в моем коде?
Принимаются любые советы по скрещиванию QT+Direct3D, если у кого нибудь есть готовые примеры был бы очень благодарен.


Название: Re: Direct3D widget
Отправлено: Sergeich от Март 31, 2009, 14:49
Попробуй добавить аттрибут Qt::WA_MSWindowsUseDirect3D


Название: Re: Direct3D widget
Отправлено: ixSci от Март 31, 2009, 15:26
не помогло


Название: Re: Direct3D widget
Отправлено: Sergeich от Март 31, 2009, 21:50
Гмм... даже не знаю че сказать, я всю жисть на OpenGL всю трехмерку делал. То, что оно с кутей скрещивается - это точно. По крайней мере их PaintEngine на этом говне точно работает. Как вариант попробуй создать виджет с direct3d атрибутом и в пайнт ивенте какие-нить его команды заюзать. И лучше всего в отладчике глянь на каком движке QPainter рисует, там у пайнтера свойство engine будет. Если QRaster... - то direct3d оно не юзает. А какая кутиха, кстати?


Название: Re: Direct3D widget
Отправлено: ixSci от Март 31, 2009, 21:55
Цитировать
Как вариант попробуй создать виджет с direct3d атрибутом и в пайнт ивенте какие-нить его команды заюзать
команды кого?, если директа, то я так и делаю.
Цитировать
И лучше всего в отладчике глянь на каком движке QPainter рисует, там у пайнтера свойство engine будет. Если QRaster... - то direct3d оно не юзает
попробую, спасибо
Цитировать
А какая кутиха, кстати?
4.5


Название: Re: Direct3D widget
Отправлено: ixSci от Апрель 01, 2009, 10:35
Sergeich, что то я не нашел как  посмотреть какой движок используется, пока жи на примере пожалуйста.

Немного изменил код
юр
Код
C++ (Qt)
class Direct3DWidget : public QWidget
{
Q_OBJECT
public:
Direct3DWidget(QWidget *parent = 0);
~Direct3DWidget();
public slots:
bool Rendering();
public:
 
void InitDirect3D();
void paintEvent(QPaintEvent *p)
{
Rendering();
}
QPaintEngine* paintEngine()
{
return 0;
}
private:
CComPtr<IDirect3D9> m_pD3D;
CComPtr<IDirect3DDevice9> m_pd3dDevice;
};
 
.cpp
Код
C++ (Qt)
Direct3DWidget::Direct3DWidget(QWidget *parent /* = 0 */)
{
/*
setFixedSize(200, 200);
setAutoFillBackground(false);
setAttribute(Qt::WA_PaintOnScreen, true);
setAttribute(Qt::WA_MSWindowsUseDirect3D, true);
setAttribute(Qt::WA_NoSystemBackground, true);*/

 
//InitDirect3D();
}
Direct3DWidget::~Direct3DWidget()
{
}
void Direct3DWidget::InitDirect3D()
{
m_pD3D = Direct3DCreate9( D3D_SDK_VERSION);
 
D3DPRESENT_PARAMETERS d3dpp = {0};
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;
m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, winId(),
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&d3dpp, &m_pd3dDevice );
}
bool Direct3DWidget::Rendering()
{
if(m_pd3dDevice == 0)
return false;
m_pd3dDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255, 255, 0), 1.0f, 0);
if(SUCCEEDED(m_pd3dDevice->BeginScene()))
{
m_pd3dDevice->EndScene();
}
m_pd3dDevice->Present( 0, 0, 0, 0 );
return true;
}
main
Код
C++ (Qt)
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow window;
Direct3DWidget* widget = new Direct3DWidget(&window);
//widget->setMinimumSize(20, 20);
window.setAttribute(Qt::WA_PaintOnScreen);
   window.setAttribute(Qt::WA_NoSystemBackground);
window.setCentralWidget(widget);
widget->InitDirect3D();
window.show();
QTimer *timer = new QTimer();
QObject::connect(timer, SIGNAL( timeout() ), widget, SLOT( Rendering() ) );
timer->start();
 
return a.exec();
}
при таком коде отрисовка происходит нормально(экран заливает желтым цветом).
Если я убираю либо таймер, либо setCentralWidget отрисовка пропадает.
В связи с этим два вопроса:
1. Почему нет отрисовки через paintEvent, но есть вне его. В чем может быть разница?
2. Почему не отрисовывает если не является центральным виджетом? Мне бы хотелось совмещать различные виджеты, не просто иметь окно куда я могу рисовать..


Название: Re: Direct3D widget
Отправлено: pastor от Апрель 01, 2009, 10:50
2. Почему не отрисовывает если не является центральным виджетом? Мне бы хотелось совмещать различные виджеты, не просто иметь окно куда я могу рисовать..

Вот примечание из ассистанта:

Цитировать
Note: Creating a main window without a central widget is not supported. You must have a central widget even if it is just a placeholder.



Так что во всех случаях, central widget ДОЛЖЕН быть установлен


Название: Re: Direct3D widget
Отправлено: spirit от Апрель 01, 2009, 10:54
ага, возьми, для примера, помести в лэйаут свой виджет для рендеринга при помощи direct3d и помести еще несколько других виджетов.
а вот с таймером непонятно.


Название: Re: Direct3D widget
Отправлено: ixSci от Апрель 01, 2009, 11:45
так дело сдвинулось с мертвой точки :)
Заменил основное окно с QMainWindow на Qwidget. Убрал все аттрибуты(они не влияют никак). И убрал таймер, при ресайзе происходит отрисовка виджета, но потом заливается фоном, т.е при ресайзе получается мерцание. Как можно это побороть?:)
вот что я пробовал выставлять
Код
C++ (Qt)
/*
window.setAttribute(Qt::WA_PaintOnScreen);
window.setAttribute(Qt::WA_NoSystemBackground);
window.setAttribute(Qt::WA_MSWindowsUseDirect3D, true);
window.setAutoFillBackground(false);*/

 


Название: Re: Direct3D widget
Отправлено: spirit от Апрель 01, 2009, 11:46
почитай про "Double Buffered Graphics Driver Example" в ассистанте.


Название: Re: Direct3D widget
Отправлено: ixSci от Апрель 01, 2009, 12:05
у меня не просто мерцание, изображения на экране не остается. Если принцип double buffer'а в QT не отличается от других либ, то проблема не в этом.


Название: Re: Direct3D widget
Отправлено: ixSci от Апрель 01, 2009, 13:07
почитал про двойную буферизацию в QT, к моей проблеме она отношения не имеет(к тому же двойная буферизация это нативная часть Direct3D). У меня получается, что после отрбаотки paintevent происходит заливка цветом фона виджета, как ее можно убрать?


Название: Re: Direct3D widget
Отправлено: pastor от Апрель 01, 2009, 13:52
Установка аттрибута Qt::WA_NoSystemBackground не помогает?

Цитировать
Indicates that the widget has no background, i.e. when the widget receives paint events, the background is not automatically repainted. Note: Unlike WA_OpaquePaintEvent, newly exposed areas are never filled with the background (e.g., after showing a window for the first time the user can see "through" it until the application processes the paint events). This flag is set or cleared by the widget's author.


Название: Re: Direct3D widget
Отправлено: ixSci от Апрель 01, 2009, 14:03
не помогает


Название: Re: Direct3D widget
Отправлено: pastor от Апрель 02, 2009, 10:45
А такой вопросец, Qt сконфигурирована с флагом -direct3d?


Название: Re: Direct3D widget
Отправлено: ixSci от Апрель 02, 2009, 10:49
я делал просто configure -platform win32-msvc2008
здесь еще нужно отдельный флаг указывать? Если да, то дайте ссыль, пожалуйста, на то какие флаги могут быть, чтобы я не собирал под каждый новаый флаг :)


Название: Re: Direct3D widget
Отправлено: pastor от Апрель 02, 2009, 11:06
Это всеголишь моя догадка. Выполни:

configure -help

В списке возможный параметров для венды будет:

Цитировать
-direct3d .......... Compile in Direct3D support (experimental - see INSTALL for more info)

Вот что говорится в INSTALL:

Цитировать
If you are using the "-direct3d" option, make sure that you have
    the Direct3D SDK installed, and that you have run the
    %DXSDK_DIR%\Utilities\Bin\dx_setenv.cmd command, before attempting
    to run configure.

И что в ассистанте:

Цитировать
The Windows version of Qt also support one additional command line option, if Direct3D support has been compiled into Qt:
-direct3d will make the Direct3D paint engine the default widget paint engine in Qt. This functionality is experimental.

Также смущает вот этот код:

Код
C++ (Qt)
QPaintEngine* paintEngine()
{
   return 0;
}

а именно то, что paintEngine == 0. Если взглянуть на OPenGL реализацию, то создан свой paintEngine, наследник QPaintEngine.

Если закаментить этот код и возвращать paintEngine по умолчанию?


Название: Re: Direct3D widget
Отправлено: ixSci от Апрель 02, 2009, 11:10
Цитировать
Если закаментить этот код и возвращать paintEngine по умолчанию?
ничего не изменится, я про такой способо вычитал тут (http://www.gamedev.net/community/forums/topic.asp?topic_id=477580)
Цитировать
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)

Сейчас попробую пересобрать, спасибо за совет.


Название: Re: Direct3D widget
Отправлено: ixSci от Апрель 02, 2009, 20:38
виват! Проблема решена, пересобрал Qt, запускаю приложение с ключом -direct3d + убрал обнуляющий paintEngine. Теперь все работает как надо.
pastor, огромное тебе спасибо. Так же спасибо остальным за попытку помочь.


Название: Re: Direct3D widget
Отправлено: pastor от Апрель 02, 2009, 21:16
Незачто!

Интересно бы было офрмить это все в статью и выложить на вики. :)


Название: Re: Direct3D widget
Отправлено: ixSci от Апрель 02, 2009, 21:25
ок, подретуширую чуть чуть и, думаю, на выходных выложу.


Название: Re: Direct3D widget
Отправлено: ixSci от Апрель 04, 2009, 13:33
http://prog.org.ru/wiki/index.php?title=QDirect3DWidget


Название: Re: Direct3D widget
Отправлено: pastor от Апрель 04, 2009, 14:07
Отлично! Спасибо за статью!

У меня есть небольшой коментарий к коду:

Код
C++ (Qt)
void Direct3DWidget::paintEvent(QPaintEvent *pEvent)
{
//For suppressing warning about the unused variable
sizeof(pEvent);
Rendering();
}

В Qt есть специальный макрос Q_UNUSED(), т.е. код можно переписать так:

Код
C++ (Qt)
void Direct3DWidget::paintEvent(QPaintEvent *pEvent)
{
//For suppressing warning about the unused variable
Q_UNUSED(pEvent);
Rendering();
}


Название: Re: Direct3D widget
Отправлено: Khs от Апрель 04, 2009, 14:16
Ишо б скрин приложить экзампла, для полного счастья :)


Название: Re: Direct3D widget
Отправлено: ixSci от Апрель 04, 2009, 14:36
код поправил, ссылку на скрин добавил. Как туда картинку вставить я так и не понял :(


Название: Re: Direct3D widget
Отправлено: pastor от Апрель 04, 2009, 14:59
В  вики на данный момент проблема с картинками. Решим проблему  немного позже