如何在C++ Qt3D中显示图像?求纹理绑定极简示例
用C++ Qt3D加载图像到纹理并绑定到tex0的极简示例
我之前刚好做过类似的Qt3D纹理绑定需求,给你一个纯C++的极简实现示例——完全不用QML,核心就是把图像(摄像头)数据塞进Qt3D的纹理缓冲区,再绑定到材质的tex0上。
步骤1:搭建基础Qt3D场景
先把最基本的窗口、根实体、相机这些核心结构搭起来:
#include <QGuiApplication> #include <Qt3DExtras/Qt3DWindow> #include <Qt3DCore/QEntity> #include <Qt3DRender/QCamera> #include <Qt3DRender/QCameraLens> #include <Qt3DExtras/QPhongMaterial> #include <Qt3DRender/QTexture2D> #include <Qt3DRender/QTextureImage> #include <Qt3DRender/QBuffer> #include <Qt3DRender/QTextureDataGenerator> #include <Qt3DExtras/QPlaneMesh> // 先提前声明自定义纹理生成器类 class CustomTextureDataGenerator; int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); // 创建Qt3D显示窗口 Qt3DExtras::Qt3DWindow view; view.defaultFrameGraph()->setClearColor(QColor(Qt::black)); // 场景根实体 Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity(); view.setRootEntity(rootEntity); // 设置相机参数 Qt3DRender::QCamera *camera = view.camera(); camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f); camera->setPosition(QVector3D(0, 0, 5.0f)); camera->setViewCenter(QVector3D(0, 0, 0));
步骤2:准备图像数据并创建纹理
这里我模拟了一张渐变测试图,你直接把这段替换成你从摄像头拿到的像素数组就行,注意要是RGBA格式(每个像素4字节):
// 模拟摄像头输出的图像数据(640x480分辨率) const int imgWidth = 640; const int imgHeight = 480; QByteArray imageData; imageData.resize(imgWidth * imgHeight * 4); // RGBA占4字节/像素 // 生成测试渐变图(替换成你的摄像头像素数据即可) uchar *pixelData = reinterpret_cast<uchar*>(imageData.data()); for (int y = 0; y < imgHeight; ++y) { for (int x = 0; x < imgWidth; ++x) { pixelData[(y * imgWidth + x) * 4 + 0] = qMin(x * 255 / imgWidth, 255); // R通道 pixelData[(y * imgWidth + x) * 4 + 1] = qMin(y * 255 / imgHeight, 255); // G通道 pixelData[(y * imgWidth + x) * 4 + 2] = 255; // B通道 pixelData[(y * imgWidth + x) * 4 + 3] = 255; // 透明度通道 } } // 创建2D纹理对象 Qt3DRender::QTexture2D *texture = new Qt3DRender::QTexture2D(rootEntity); texture->setWidth(imgWidth); texture->setHeight(imgHeight); texture->setFormat(Qt3DRender::QAbstractTexture::RGBA8_UNorm); texture->setWrapMode(Qt3DRender::QTextureWrapMode(Qt3DRender::QTextureWrapMode::ClampToEdge)); texture->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear); texture->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear); // 创建存储图像数据的缓冲区 Qt3DRender::QBuffer *dataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, texture); dataBuffer->setData(imageData); // 创建纹理图像,绑定缓冲区 Qt3DRender::QTextureImage *textureImage = new Qt3DRender::QTextureImage(texture); textureImage->setDataGenerator(Qt3DRender::QTextureDataGeneratorPtr(new CustomTextureDataGenerator(dataBuffer, imgWidth, imgHeight))); texture->addTextureImage(textureImage);
步骤3:实现自定义纹理数据生成器
这个类是Qt3D读取缓冲区数据生成纹理的关键,必须实现指定的接口:
// 自定义纹理数据生成器——负责从缓冲区读取数据并生成Qt3D可识别的纹理格式 class CustomTextureDataGenerator : public Qt3DRender::QTextureDataGenerator { public: CustomTextureDataGenerator(Qt3DRender::QBuffer *buffer, int width, int height) : m_dataBuffer(buffer), m_width(width), m_height(height) {} Qt3DRender::QTextureDataPtr operator ()() override { auto textureData = Qt3DRender::QTextureDataPtr::create(); textureData->setWidth(m_width); textureData->setHeight(m_height); textureData->setDepth(1); textureData->setFormat(Qt3DRender::QAbstractTexture::RGBA8_UNorm); textureData->setTarget(Qt3DRender::QAbstractTexture::Target2D); textureData->setPixelFormat(Qt3DRender::QTextureData::RGBA); textureData->setPixelType(Qt3DRender::QTextureData::UInt8); textureData->setData(m_dataBuffer->data()); return textureData; } bool operator ==(const Qt3DRender::QTextureDataGenerator &other) const override { const auto otherGenerator = qobject_cast<const CustomTextureDataGenerator*>(&other); return otherGenerator && m_dataBuffer == otherGenerator->m_dataBuffer && m_width == otherGenerator->m_width && m_height == otherGenerator->m_height; } QT3D_FUNCTOR(CustomTextureDataGenerator) private: Qt3DRender::QBuffer *m_dataBuffer; int m_width; int m_height; };
步骤4:绑定纹理到平面实体
最后把纹理贴到一个平面上,用Phong材质的diffuse通道绑定纹理(对应着色器里的tex0):
// 创建平面网格(尺寸对应640:480的比例) Qt3DExtras::QPlaneMesh *planeMesh = new Qt3DExtras::QPlaneMesh(); planeMesh->setWidth(4.0f); planeMesh->setHeight(3.0f); // 创建材质并绑定纹理 Qt3DExtras::QPhongMaterial *material = new Qt3DExtras::QPhongMaterial(rootEntity); material->setDiffuse(texture); // 这里就把纹理绑定到了tex0通道 // 创建平面实体,把网格和材质挂上去 Qt3DCore::QEntity *planeEntity = new Qt3DCore::QEntity(rootEntity); planeEntity->addComponent(planeMesh); planeEntity->addComponent(material); // 显示窗口 view.show(); return app.exec(); }
实时更新摄像头画面的关键提示
如果要实时刷新摄像头数据,只需要两步:
- 定期把新的摄像头像素数据更新到
dataBuffer里(调用dataBuffer->setData(newPixelData)) - 调用
textureImage->update()触发纹理重新生成
这样就能实现AR应用里的实时摄像头画面显示了。
内容的提问来源于stack exchange,提问作者Ben Hoff
相关产品推荐
相关产品推荐

