如何使用C++(非QML)在Qt3D中实现形状轮廓效果
纯C++实现Qt3D形状轮廓绘制
针对QCuboidMesh这类凸多边形网格,最轻量化的实现方式是双实体叠加渲染,不需要修改网格源码、不需要写自定义着色器,全程用Qt3D C++ API即可完成,效果完全匹配透明本体+外轮廓的需求。
核心逻辑
- 复用同一个长方体网格生成两个渲染实体,二者共用同一个位置变换组件,保证完全重合
- 第一个实体渲染半透明本体,关闭深度写入避免遮挡轮廓线
- 第二个实体开启线框模式+背面剔除,通过多边形偏移消除Z轴闪烁,只渲染外轮廓边线
完整实现代码
头文件引用
#include <Qt3DCore/QEntity> #include <Qt3DCore/QTransform> #include <Qt3DExtras/QCuboidMesh> #include <Qt3DExtras/QDiffuseSpecularMaterial> #include <Qt3DExtras/QPhongMaterial> #include <Qt3DRender/QRenderPass> #include <Qt3DRender/QEffect> #include <Qt3DRender/QTechnique> #include <Qt3DRender/QCullFace> #include <Qt3DRender/QPolygonOffset> #include <Qt3DRender/QWireframe> #include <Qt3DRender/QNoDepthMask> #include <QColor>
核心构建代码
// 根实体为已创建的Qt3D场景根节点 Qt3DCore::QEntity* rootEntity = /* 对应场景根节点指针 */; // 1. 创建共享的长方体网格,两个实体复用减少显存占用 Qt3DExtras::QCuboidMesh* cuboidMesh = new Qt3DExtras::QCuboidMesh(); cuboidMesh->setXExtents(2.0f); cuboidMesh->setYExtents(2.0f); cuboidMesh->setZExtents(2.0f); // 共用变换组件,保证两个实体位置、旋转、缩放完全一致 Qt3DCore::QTransform* cuboidTransform = new Qt3DCore::QTransform(); // 2. 构建半透明本体 Qt3DCore::QEntity* solidCuboid = new Qt3DCore::QEntity(rootEntity); Qt3DExtras::QDiffuseSpecularMaterial* transparentMat = new Qt3DExtras::QDiffuseSpecularMaterial(); // 设置本体颜色与透明度,alpha设为0就是完全透明仅显示轮廓 transparentMat->setDiffuse(QColor(80, 170, 255, 30)); transparentMat->setAlphaBlendingEnabled(true); // 关闭本体深度写入,避免遮挡上层轮廓线 Qt3DRender::QNoDepthMask* noDepthMask = new Qt3DRender::QNoDepthMask(); auto solidEffect = const_cast<Qt3DRender::QEffect*>(transparentMat->effect()); auto solidTech = solidEffect->techniques().first(); solidTech->renderPasses().first()->addRenderState(noDepthMask); solidCuboid->addComponent(cuboidMesh); solidCuboid->addComponent(transparentMat); solidCuboid->addComponent(cuboidTransform); // 3. 构建轮廓线实体 Qt3DCore::QEntity* outlineCuboid = new Qt3DCore::QEntity(rootEntity); Qt3DExtras::QPhongMaterial* outlineMat = new Qt3DExtras::QPhongMaterial(); // 轮廓线颜色 outlineMat->setAmbient(QColor(0, 120, 220)); // 配置轮廓渲染状态 Qt3DRender::QCullFace* cullBack = new Qt3DRender::QCullFace(); cullBack->setMode(Qt3DRender::QCullFace::Back); // 剔除背面,避免显示内部三角边 Qt3DRender::QWireframe* wireframeMode = new Qt3DRender::QWireframe(); // 开启线框渲染 Qt3DRender::QPolygonOffset* offset = new Qt3DRender::QPolygonOffset(); offset->setFactor(-1.0f); offset->setUnits(-1.0f); // 轻微偏移轮廓位置,消除Z-fighting闪烁 auto outlineEffect = const_cast<Qt3DRender::QEffect*>(outlineMat->effect()); auto outlineTech = outlineEffect->techniques().first(); Qt3DRender::QRenderPass* outlinePass = outlineTech->renderPasses().first(); outlinePass->addRenderState(cullBack); outlinePass->addRenderState(wireframeMode); outlinePass->addRenderState(offset); outlineCuboid->addComponent(cuboidMesh); outlineCuboid->addComponent(outlineMat); outlineCuboid->addComponent(cuboidTransform);
适配说明
- 该方案对所有凸多边形网格(立方体、球体、圆锥、凸多面体)都生效,如果是凹多边形或复杂模型,背面剔除可能会漏出内部三角边,可替换为模板缓冲轮廓法:先渲染实体写入模板值,再将模型轻微放大渲染背面纯色,最后渲染本体即可得到干净的外轮廓,不需要线框模式。
- 需要调整轮廓粗细时,可以加入
Qt3DRender::QLineWidth组件设置线宽,注意部分OpenGL ES平台对大于1的线宽支持有限。 - 如果需要完全隐藏本体,只需要把透明材质的diffuse alpha值设为0即可。
内容的提问来源于stack exchange,提问作者AverageQtCPPUser
相关产品推荐
相关产品推荐

