You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 &center, float radius, const b2Color &color) { }
void DebugDrawer::DrawSolidCircle(const b2Vec2 &center, 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 &center, float radius, const b2Color &color) { }
void DebugDrawer::DrawSolidCircle(const b2Vec2 &center, 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 10:15:50