Qt6+OpenGL3中Box2D的b2Draw类使用问题:DrawSegment未调用
Box2D调试绘制DrawSegment方法未被调用的问题
我尝试为Box2D绘制碰撞器,当前示例仅实现物理逻辑未添加图形。编写了继承自b2Draw的DebugDrawer类,实现了DrawSegment等方法(其中DrawSegment会打印“hello”),在Widget中设置了调试绘制器及相关标志,调用了m_pWorld->DebugDraw(),但DrawSegment方法始终未被调用。
完整代码
DebugDrawer.cpp
#include "DebugDrawer.h" #include <QtCore/QDebug> DebugDrawer::DebugDrawer() { } void DebugDrawer::DrawSegment(const b2Vec2 &p1, const b2Vec2 &p2, const b2Color &color) { qDebug() << "hello"; } void DebugDrawer::DrawSolidPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) { } void DebugDrawer::DrawPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) { } void DebugDrawer::DrawPoint(const b2Vec2 &p, float size, const b2Color &color) { } void DebugDrawer::DrawCircle(const b2Vec2 ¢er, float radius, const b2Color &color) { } void DebugDrawer::DrawSolidCircle(const b2Vec2 ¢er, float radius, const b2Vec2 &axis, const b2Color &color) { } void DebugDrawer::DrawTransform(const b2Transform &xf) { }
DebugDrawer.h
#ifndef DEBUGDRAWER_H #define DEBUGDRAWER_H #include "box2d/b2_draw.h" class DebugDrawer : public b2Draw { public: DebugDrawer(); private: // virtual void DrawSegment(b2Vec2& p1, b2Vec2& p2, b2Color& color) override; void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color); void DrawPoint (const b2Vec2 &p, float size, const b2Color &color); void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color); void DrawCircle(const b2Vec2& center, float radius, const b2Color& color); void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color); void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color); void DrawTransform(const b2Transform& xf); }; #endif // DEBUGDRAWER_H
Widget.cpp
#include "Widget.h" #include <QtCore/QDebug> Widget::Widget(QWidget *parent) : QOpenGLWidget(parent) { setWindowTitle("Box2D, OpenGL3, Qt6, C++"); setFixedSize(QSize(500, 500)); b2Vec2 gravity(0.f, 9.8f); m_pWorld = new b2World(gravity); } Widget::~Widget() { delete m_pWorld; delete m_pDebugDrawer; } void Widget::initializeGL() { initializeOpenGLFunctions(); glClearColor(0.2f, 0.2f, 0.2f, 1.f); glEnable(GL_DEPTH_TEST); m_pDebugDrawer = new DebugDrawer(); m_pWorld->SetDebugDraw(m_pDebugDrawer); uint32 flags = 0; flags += b2Draw::e_shapeBit; flags += b2Draw::e_jointBit; flags += b2Draw::e_centerOfMassBit; flags += b2Draw::e_aabbBit; flags += b2Draw::e_pairBit; m_pDebugDrawer->SetFlags(flags); // m_pDebugDrawer->SetFlags(b2Draw::e_shapeBit); b2PolygonShape shape; shape.SetAsBox(50.f / WORLD_SCALE, 50.f / WORLD_SCALE); b2BodyDef bdef; bdef.type = b2_staticBody; m_pBody = m_pWorld->CreateBody(&bdef); m_pBody->CreateFixture(&shape, 2.f); connect(&m_timer, &QTimer::timeout, this, &Widget::animationLoop); m_timer.start(1000.f/60.f); m_elapsedTimer.start(); } void Widget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); m_pWorld->DebugDraw(); } void Widget::resizeGL(int w, int h) { glViewport(0, 0, w, h); } void Widget::animationLoop() { m_deltaTime = m_elapsedTimer.elapsed() / 1000.f; m_elapsedTimer.restart(); m_pWorld->Step(m_deltaTime, 8, 3); update(); }
Widget.h
#ifndef WIDGET_H #define WIDGET_H #include "box2d/box2d.h" #include <QtCore/QElapsedTimer> #include <QtCore/QTimer> #include <QtOpenGLWidgets/QOpenGLWidget> #include <QtGui/QOpenGLFunctions> #include "DebugDrawer.h" class Widget : public QOpenGLWidget, QOpenGLFunctions { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void animationLoop(); private: void initializeGL() override; void paintGL() override; void resizeGL(int w, int h) override; private: const float WORLD_SCALE = 30.f; b2World *m_pWorld; DebugDrawer *m_pDebugDrawer; b2Body *m_pBody; QElapsedTimer m_elapsedTimer; QTimer m_timer; float m_deltaTime; }; #endif // WIDGET_H
main.cpp
#ifdef _WIN32 #include <windows.h> extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; #endif #include <QtGui/QSurfaceFormat> #include <QtWidgets/QApplication> #include "Widget.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); QSurfaceFormat format; format.setSamples(8); Widget w; w.setFormat(format); w.show(); return a.exec(); }
.pro
QT += core gui openglwidgets win32: LIBS += -lopengl32 INCLUDEPATH += "E:\Libs\box2d-2.4.1-mingw-64-bit\include" LIBS += -L"E:\Libs\box2d-2.4.1-mingw-64-bit\lib" LIBS += -lbox2d greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++11 # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ DebugDrawer.cpp \ main.cpp \ Widget.cpp HEADERS += \ DebugDrawer.h \ Widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target
问题原因与修复方案
核心问题
DebugDrawer类没有正确重写b2Draw基类的虚函数。b2Draw中的所有绘图方法都是纯虚函数,子类必须显式声明重写这些函数,否则Box2D的调试绘制系统无法正确调用子类的实现。
修复步骤
1. 修改DebugDrawer.h
给所有重写的方法添加override关键字(C++11及以上支持),确保编译器能识别这是对基类虚函数的重写,同时保证参数签名与基类完全匹配:
#ifndef DEBUGDRAWER_H #define DEBUGDRAWER_H #include "box2d/b2_draw.h" class DebugDrawer : public b2Draw { public: DebugDrawer(); private: void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override; void DrawPoint(const b2Vec2 &p, float size, const b2Color &color) override; void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override; void DrawCircle(const b2Vec2& center, float radius, const b2Color& color) override; void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color) override; void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) override; void DrawTransform(const b2Transform& xf) override; }; #endif // DEBUGDRAWER_H
2. 可选:在DebugDrawer.cpp中添加override
虽然.cpp文件中不需要强制添加,但加上能让编译器进一步检查重写是否正确:
#include "DebugDrawer.h" #include <QtCore/QDebug> DebugDrawer::DebugDrawer() { } void DebugDrawer::DrawSegment(const b2Vec2 &p1, const b2Vec2 &p2, const b2Color &color) { qDebug() << "hello"; } void DebugDrawer::DrawSolidPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) { } void DebugDrawer::DrawPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) { } void DebugDrawer::DrawPoint(const b2Vec2 &p, float size, const b2Color &color) { } void DebugDrawer::DrawCircle(const b2Vec2 ¢er, float radius, const b2Color &color) { } void DebugDrawer::DrawSolidCircle(const b2Vec2 ¢er, float radius, const b2Vec2 &axis, const b2Color &color) { } void DebugDrawer::DrawTransform(const b2Transform &xf) { }
额外检查点
- 确认
WORLD_SCALE缩放合理:当前设置为30.f,SetAsBox(50.f/30,50.f/30)对应Box2D单位约1.66x1.66,在500x500窗口中可见。 - 调试标志设置正确:已添加
e_shapeBit等必要标志,无需修改。 - 确认
m_pWorld->DebugDraw()在paintGL()中被正确调用,且update()触发了重绘。
修复后运行程序,DrawSegment方法会被正常调用并打印“hello”。
内容的提问来源于stack exchange,提问作者8Observer8
相关产品推荐
相关产品推荐

