私はqglwidgetを使って同様の問題を抱えていました。私が思い描いたソリューションは、正投影を使ってスクラッチコントロールをレンダリングしています。メイン描画関数の最後に、ビューを設定して2dビットを描画する別の関数を呼び出します。マウスイベントに関しては、メインウィジェットに送信されたイベントをキャプチャし、ヒットテスト、再帰座標オフセット、および擬似コールバックの組み合わせを使用して、コントロールをネストすることができます。私の実装では、一度に1つずつトップレベルのコントロール(主にスクロールボックス)にコマンドを転送しますが、コントロールを動的に追加する必要がある場合は、リンクリスト構造を簡単に追加できます。私は現在、部品をカラーパネルとしてレンダリングするためにクワッドを使用していますが、テクスチャを追加したり、ダイナミックライティングに対応する3Dコンポーネントにするのは簡単です。そこのコードの多くはだので、私はちょうどつもり作品に関連するビットを投げています:
ここ
void GLWidget::paintGL() {
if (isPaused) return;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glLightfv(GL_LIGHT0, GL_POSITION, FV0001);
gluLookAt(...);
// Typical 3d stuff
glCallList(Body::glGrid);
glPopMatrix();
//non3d bits
drawOverlay(); // <---call the 2d rendering
fpsCount++;
}
は、2Dレンダリングのためのモデルビュー/投影行列を設定するコードは次のとおりです。
void GLWidget::drawOverlay() {
glClear(GL_DEPTH_BUFFER_BIT);
glPushMatrix(); //reset
glLoadIdentity(); //modelview
glMatrixMode(GL_PROJECTION);//set ortho camera
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0,width()-2*padX,height()-2*padY,0); // <--critical; padx/y is just the letterboxing I use
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST); // <-- necessary if you want to draw things in the order you call them
glDisable(GL_LIGHTING); // <-- lighting can cause weird artifacts
drawHUD(); //<-- Actually does the drawing
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION); glPopMatrix();
glMatrixMode(GL_MODELVIEW); glPopMatrix();
}
このhudを処理する主な描画関数です。ドロー機能の大部分は大きな「バックラウンドパネル」チャンクに似ています。
void GLWidget::drawHUD() {
float gridcol[] = { 0.5, 0.1, 0.5, 0.9 };
float gridcolB[] = { 0.3, 0.0, 0.3, 0.9 };
//string caption
QString tmpStr = QString::number(FPS);
drawText(tmpStr.toAscii(),120+padX,20+padY);
//Markers
tGroup* tmpGroup = curGroup->firstChild;
while (tmpGroup != 0) {
drawMarker(tmpGroup->scrXYZ);
tmpGroup = tmpGroup->nextItem;
}
//Background panel
glEnable(GL_BLEND);
glTranslatef(0,height()*0.8,0);
glBegin(GL_QUADS);
glColor4fv(gridcol);
glVertex2f(0.0f, 0.0);
glVertex2f(width(), 0);
glColor4fv(gridcolB);
glVertex2f(width(), height()*0.2);
glVertex2f(0.0f, height()*0.2);
glEnd();
glDisable(GL_BLEND);
glLoadIdentity(); //nec b/c of translate ^^
glTranslatef(-padX,-padY,0);
//Controls
cargoBox->Draw();
sideBox->Draw();
econBox->Draw();
}
を今すぐコントロール自身のために:あなたは基本的にはモデルビュー行列を押し、popmatrixその後、コントロールをペイント、あなたが3Dで希望のように/回転/スケールを変換します。ボタン、スライダー、ラベルなどのすべてのコントロールは、空の仮想関数を持つ共通の基底クラスからすべてのものが入っていて、相互に相互作用することができます。ベースには、高さや座標などの典型的なものと、コールバックやテキストレンダリングを処理するためのポインタがあります。また、それがクリックされたかどうかを伝える一般的なhittest(x、y)関数も含まれています。楕円形のコントロールが必要な場合は、これを仮想的にすることができます。スライダーのような化合物のコントロールは複数のボタンがあり、scrollboxesはタイルとスライダーを持っているので、ここでは、基本クラス、hittest、簡単なボタンのコードです。:
class glBase {
public:
glBase(float tx, float ty, float tw, float th);
virtual void Draw() {return;}
virtual glBase* mouseDown(float xIn, float yIn) {return this;}
virtual void mouseUp(float xIn, float yIn) {return;}
virtual void mouseMove(float xIn, float yIn) {return;}
virtual void childCallBack(float vIn, void* caller) {return;}
bool HitTest(float xIn, float yIn);
float xOff, yOff;
float width, height;
glBase* parent;
static GLWidget* renderer;
protected:
glBase* callFwd;
};
bool glBase::HitTest(float xIn, float yIn) { //input should be relative to parents space
xIn -= xOff; yIn -= yOff;
if (yIn >= 0 && xIn >= 0) {
if (xIn <= width && yIn <= height) return true;
}
return false;
}
class glButton : public glBase {
public:
glButton(float tx, float ty, float tw, float th, char rChar);
void Draw();
glBase* mouseDown(float xIn, float yIn);
void mouseUp(float xIn, float yIn);
private:
bool isPressed;
char renderChar;
};
glButton::glButton(float tx, float ty, float tw, float th, char rChar) :
glBase(tx, ty, tw, th), isPressed(false), renderChar(rChar) {}
void glButton::Draw() {
float gridcolA[] = { 0.5, 0.6, 0.5, 1.0 };//up
float gridcolB[] = { 0.2, 0.3, 0.2, 1.0 };
float gridcolC[] = { 1.0, 0.2, 0.1, 1.0 };//dn
float gridcolD[] = { 1.0, 0.5, 0.3, 1.0 };
float* upState;
float* upStateB;
if (isPressed) {
upState = gridcolC;
upStateB = gridcolD;
} else {
upState = gridcolA;
upStateB = gridcolB;
}
glPushMatrix();
glTranslatef(xOff,yOff,0);
glBegin(GL_QUADS);
glColor4fv(upState);
glVertex2f(0, 0);
glVertex2f(width, 0);
glColor4fv(upStateB);
glVertex2f(width, height);
glVertex2f(0, height);
glEnd();
if (renderChar != 0) //center
renderer->drawChar(renderChar, (width - 12)/2, (height - 16)/2);
glPopMatrix();
}
glBase* glButton::mouseDown(float xIn, float yIn) {
isPressed = true;
return this;
}
void glButton::mouseUp(float xIn, float yIn) {
isPressed = false;
if (parent != 0) {
if (HitTest(xIn, yIn)) parent->childCallBack(0, this);
}
}
、それはすべての描画のために再帰的にする必要があります/マウスイベント。各コントロールには、値を渡すジェネリックコールバック関数と独自のアドレスもあります。これにより、親は子どものそれぞれを呼び出して誰が電話しているかを確認し、適切に応答することができます(例:上/下ボタン)。子コントロールは、c/dtorsのnew/deleteを使用して追加されます。また、子コントロールのdraw()関数は、親のdraw()呼び出しの間に呼び出され、すべてが自己完結型であることを可能にします。ここでは3つのサブボタンが含まミッドレベルのスライドバーから該当するコードされています
glBase* glSlider::mouseDown(float xIn, float yIn) {
xIn -= xOff; yIn -= yOff;//move from parent to local coords
if (slider->HitTest(xIn,yIn-width)) { //clicked slider
yIn -= width; //localize to field area
callFwd = slider->mouseDown(xIn, yIn);
dragMode = true;
dragY = yIn - slider->yOff;
} else if (upButton->HitTest(xIn,yIn)) {
callFwd = upButton->mouseDown(xIn, yIn);
} else if (downButton->HitTest(xIn,yIn)) {
callFwd = downButton->mouseDown(xIn, yIn);
} else {
//clicked in field, but not on slider
}
return this;
}//TO BE CHECKED (esp slider hit)
void glSlider::mouseUp(float xIn, float yIn) {
xIn -= xOff; yIn -= yOff;
if (callFwd != 0) {
callFwd->mouseUp(xIn, yIn); //ok to not translate b/c slider doesn't callback
callFwd = 0;
dragMode = false;
} else {
//clicked in field, not any of the 3 buttons
}
}
void glSlider::childCallBack(float vIn, void* caller) { //can use value blending for smooth
float tDelta = (maxVal - minVal)/(10);
if (caller == upButton) {//only gets callbacks from ud buttons
setVal(Value - tDelta);
} else {
setVal(Value + tDelta);
}
}
は、今、私たちは、OpenGLコンテキストにレンダリングする自己完結型のコントロールを持っていることを、すべてのことが必要なのは、トップレベルのコントロールからインターフェイスです例えば、glWidgetからのマウスイベント。
void GLWidget::mousePressEvent(QMouseEvent* event) {
if (cargoBox->HitTest(event->x()-padX, event->y()-padY)) { //if clicked first scrollbox
callFwd = cargoBox->mouseDown(event->x()-padX, event->y()-padY); //forward the click, noting which last got
return;
} else if (sideBox->HitTest(event->x()-padX, event->y()-padY)) {
callFwd = sideBox->mouseDown(event->x()-padX, event->y()-padY);
return;
} else if (econBox->HitTest(event->x()-padX, event->y()-padY)) {
callFwd = econBox->mouseDown(event->x()-padX, event->y()-padY);
return;
}
lastPos = event->pos(); //for dragging
}
void GLWidget::mouseReleaseEvent(QMouseEvent *event) {
if (callFwd != 0) { //Did user mousedown on something?
callFwd->mouseUp(event->x()-padX, event->y()-padY);
callFwd = 0; //^^^ Allows you to drag off a button before releasing w/o triggering its callback
return;
} else { //local
tBase* tmpPick = pickObject(event->x(), event->y());
//normal clicking, game stuff...
}
}
全体的に、このシステムは少しハックであり、私は、キーボードのレスポンスやサイズ変更などのいくつかの機能を追加していないが、これらの追加が容易であるべきで、多分コールバックに「イベントタイプ」を必要とする(すなわちマウスまたはキーボード)。あなたはglBaseを一番上のウィジェットにサブクラス化することもできますし、親子のchildcallbackを受け取ることさえ可能にします。それは大変な作業ですが、このシステムでは、バニラC++/OpenGLが必要で、ネイティブのQtのものよりもはるかに少ないCPU /メモリーリソースしか使用しません。それ以上の情報が必要な場合は、尋ねてください。あなたはqglwidget からクラスを継承を行う場合
私は、レンダーモードをパースペクティブではなく正規直交に設定することができることに気付きました。これにより、GUIシェーダーが不要になります。しかし、私は、Qt3Dでオーバーパインティングを行うための組み込みの方法が必要だと思います。(古いQGLWidgetのメソッドがあるので(これはQt5ウィジェットモジュールにあるので使いたくないのでできませんQGLPainterを使用してレンダリング))。 – leemes
これは可能性が高いようです(かなりいいですね):http://comments.gmane.org/gmane.comp.lib.qt.3d/264 – leemes