热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Qt3d。在三角形上绘制透明的QSphereMesh

如何解决《Qt3d。在三角形上绘制透明的QSphereMesh》经验,为你挑选了1个好方法。

我有一个可以通过OpenGL绘制三角形的函数

我通过按下一个按钮绘制两个三角形(函数on_drawMapPushButton_clicked())。

然后我在这些三角形上方绘制一个球体。现在我看到,该球体正确地绘制在第一个三角形上,但是第二个三角形却绘制了该球体,反之亦然。

如果我第二次按下按钮,则会在第一个和第二个三角形上正确绘制spehere。

当我第三次按下按钮时,第二个三角形再次在球体上绘制。

当我第四次按下按钮时,会在第一个和第二个三角形上正确绘制spehere,依此类推。

如果我在SphereMesh QPhongMaterial而不是QPhongAlphaMaterial中使用,则始终在第一个和第二个三角形上正确绘制spehere。喜欢它必须是。

我不明白我为使球体总是绘制在三角形上做错了什么。

绘制透明球体的代码:

selectModel_ = new Qt3DExtras::QSphereMesh(selectEntity_);
selectModel_->setRadius(75);
selectModel_->setSlices(150);

selectMaterial_ = new Qt3DExtras::QPhongAlphaMaterial(selectEntity_);
selectMaterial_->setAmbient(QColor(28, 61, 136));
selectMaterial_->setDiffuse(QColor(11, 56, 159));
selectMaterial_->setSpecular(QColor(10, 67, 199));
selectMaterial_->setShininess(0.8f);

selectEntity_->addComponent(selectModel_);
selectEntity_->addComponent(selectMaterial_);

函数drawTriangles:

void drawTriangles(QPolygonF triangles, QColor color){
    int numOfVertices = triangles.size();

    // Create and fill vertex buffer
    QByteArray bufferBytes;
    bufferBytes.resize(3 * numOfVertices * static_cast(sizeof(float)));
    float *positiOns= reinterpret_cast(bufferBytes.data());

    for(auto point : triangles){
        *positions++ = static_cast(point.x());
        *positions++ = 0.0f; //We need to drow only on the surface
        *positions++ = static_cast(point.y());
    }

    geometry_ = new Qt3DRender::QGeometry(mapEntity_);
    auto *buf = new Qt3DRender::QBuffer(geometry_);
    buf->setData(bufferBytes);

    positionAttribute_ = new Qt3DRender::QAttribute(mapEntity_);
    positionAttribute_->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
    positionAttribute_->setVertexBaseType(Qt3DRender::QAttribute::Float); //In our buffer we will have only floats
    positionAttribute_->setVertexSize(3); // Size of a vertex
    positionAttribute_->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); // Attribute type
    positionAttribute_->setByteStride(3 * sizeof(float));
    positionAttribute_->setBuffer(buf); 
    geometry_->addAttribute(positionAttribute_); // Add attribute to ours  Qt3DRender::QGeometry

    // Create and fill an index buffer
    QByteArray indexBytes;
    indexBytes.resize(numOfVertices * static_cast(sizeof(unsigned int))); // start to end
    unsigned int *indices = reinterpret_cast(indexBytes.data());

    for(unsigned int i = 0; i (numOfVertices); ++i) {
        *indices++ = i;
    }

    auto *indexBuffer = new Qt3DRender::QBuffer(geometry_);
    indexBuffer->setData(indexBytes);

    indexAttribute_ = new Qt3DRender::QAttribute(geometry_);
    indexAttribute_->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt); //In our buffer we will have only unsigned ints
    indexAttribute_->setAttributeType(Qt3DRender::QAttribute::IndexAttribute); // Attribute type
    indexAttribute_->setBuffer(indexBuffer);
    indexAttribute_->setCount(static_cast(numOfVertices)); // Set count of our vertices
    geometry_->addAttribute(indexAttribute_); // Add the attribute to ours Qt3DRender::QGeometry

    shape_ = new Qt3DRender::QGeometryRenderer(mapEntity_);
    shape_->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
    shape_->setGeometry(geometry_); 

    //Create material
    material_ = new Qt3DExtras::QPhongMaterial(mapEntity_);
    material_->setAmbient(color);

    trianglesEntity_ = new Qt3DCore::QEntity(mapEntity_);
    trianglesEntity_->addComponent(shape_); 
    trianglesEntity_->addComponent(material_);
}

按下按钮处理程序on_drawMapPushButton_clicked():

void on_drawMapPushButton_clicked()
{
    clearMap(); //Implementation is above
    QPolygonF triangle1;
    triangle1 <

地图清除功能clearMap():

void clearMap()
{
    if(mapEntity_){
        delete mapEntity_;
        mapEntity_ = nullptr;
        mapEntity_ = new Qt3DCore::QEntity(view3dRootEntity_);
    }
}

Florian Blum.. 6

好的,这是扩展答案。

有时发生这种情况,有时不发生这种情况的原因取决于您实体的顺序。如果您尝试使用两个简单的球体,一个是透明球体,另一个不是透明球体,那么您会发现,稍后添加透明球体时,它会绘制在不透明对象上方,就像您想要的那样。

发生这种情况是因为将首先绘制不透明对象(在场景图中它首先出现),然后再绘制透明对象,这将为您提供所需的结果。在其他情况下,首先绘制透明对象,不透明对象则绘制在上方,因为透明对象QPhongAlphaMaterial具有QNoDepthMask呈现状态,该状态指示其不写入深度缓冲区。因此,不透明对象始终通过深度测试,而该透明对象实际上已经吸引到该位置。您需要做更多的工作才能为任意场景图和摄像机位置正确绘制透明对象。

Qt3D渲染图

要了解您必须执行的操作,您应该了解Qt3D渲染图的布局。如果您已经知道这一点,则可以跳过此部分。

斜体字在以下文本中引用了图形图像中的项目。

如果使用a Qt3DWindow,则无法访问渲染图根节点。它由窗口维护。您可以通过函数访问QRenderSettings框架图的根节点,activeFramegraph()并且renderSettings()都可以在窗口上调用它们。您还可以通过的功能设置场景图根节点。窗口内部有一个,它在其中设置整个图的根节点,这是上图图像中渲染图根节点setRootEntity()Qt3DWindowQAspectEngine

如果要在3D窗口的现有框架图中插入框架图节点,则必须将其添加为活动框架图的父级,这将在下一部分中进行解释。如果您在窗口中设置了自己的自定义框架图形,setActiveFramegraph()则只需将其附加到末尾,就足够了。

使用 QSortPolicy

正如您已经根据其他问题发现的那样,您可以QSortPolicy在框架图中使用到照相机的距离对实体进行排序。您可以按如下所示添加排序策略(假设这view是您,Qt3DWindow并且scene是场景图的实体,尽管我不知道为什么必须这样做):

Qt3DRender::QFrameGraphNode *framegraph = view.activeFrameGraph();
Qt3DRender::QSortPolicy *sortPolicy = new Qt3DRender::QSortPolicy(scene);
framegraph->setParent(sortPolicy);
QVector sortTypes = 
      QVector() <setSortTypes(sortTypes);
view.setActiveFrameGraph(framegraph);

此代码的问题在于,这种分类策略是按照实体的中心到相机的距离对它们进行排序。如果不透明对象之一比透明对象更靠近摄影机,则无论如何它都会稍后被绘制并遮住透明对象。有关图形说明,请参见下面的图像。

红色和黑色的球体比圆环离相机更远,这就是为什么它们先被绘制且不遮盖圆环的原因。

没有红色球体的中心比圆环的中心更靠近相机。它比圆环晚渲染并封闭。

使用两个框架图分支

如果您使用两个框架图分支,则可以解决上述问题。一种绘制所有不透明的实体,另一种绘制所有透明的实体。为此,您必须使用QLayerQLayerFilter。您可以将图层附加到实体,然后将图层过滤器添加到框架图。这样,您可以排除实体进入框架图的某个分支。

假设您创建了两层,一层用于不透明对象,一层用于透明​​对象:

Qt3DRender::QLayer *transparentLayer = new Qt3DRender::QLayer;
Qt3DRender::QLayer *opaqueLayer = new Qt3DRender::QLayer;

您必须将透明层作为一个组件附加到每个透明对象,并将不透明层附加到每个不透明对象作为组件(使用addComponent())。

不幸的是,您需要一棵特殊的框架图树来包括两个相应的图层过滤器(同样,假设view是您的Qt3DWindow):

Qt3DRender::QRenderSurfaceSelector *renderSurfaceSelector
        = new Qt3DRender::QRenderSurfaceSelector();
renderSurfaceSelector->setSurface(&view);
Qt3DRender::QClearBuffers *clearBuffers 
        = new Qt3DRender::QClearBuffers(renderSurfaceSelector);
clearBuffers->setBuffers(Qt3DRender::QClearBuffers::AllBuffers);
clearBuffers->setClearColor(Qt::white);

这是清除缓冲区的第一个分支。现在,添加以下代码:

Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(renderSurfaceSelector);
Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector(viewport);
Qt3DRender::QCamera *camera = new Qt3DRender::QCamera(cameraSelector);
// set your camera parameters here
cameraSelector->setCamera(camera);

由于您创建的QViewport子项,QRenderSurfaceSelector因此相对于,您现在是框架图中的同级项QClearBuffers。您可以在此处看到示例框架图的图示。

现在,您必须创建两个包含层过滤器的叶节点。Qt3D引擎到达叶子时始终执行整个分支。这意味着首先绘制不透明的对象,然后绘制透明的对象。

// not entirely sure why transparent filter has to go first
// I would have expected the reversed order of the filters but this works...

Qt3DRender::QLayerFilter *transparentFilter = new Qt3DRender::QLayerFilter(camera);
transparentFilter->addLayer(transparentLayer);

Qt3DRender::QLayerFilter *opaqueFilter = new Qt3DRender::QLayerFilter(camera);
opaqueFilter->addLayer(opaqueLayer);

现在,两层滤镜是您的框架图分支中的叶节点,并且Qt3D首先绘制不透明的对象,然后再绘制,因为它使用相同的视口并且所有内容都将在上面绘制透明的对象。它将正确地绘制它们(即不在透明对象实际位于的不透明对象的前面,因为我们没有再次清除深度缓冲区->拆分框架图仅在相机节点上发生)。

现在在您的上设置新的framegaph Qt3DWindow

view.setActiveFrameGraph(renderSurfaceSelector);

结果:



1> Florian Blum..:

好的,这是扩展答案。

有时发生这种情况,有时不发生这种情况的原因取决于您实体的顺序。如果您尝试使用两个简单的球体,一个是透明球体,另一个不是透明球体,那么您会发现,稍后添加透明球体时,它会绘制在不透明对象上方,就像您想要的那样。

发生这种情况是因为将首先绘制不透明对象(在场景图中它首先出现),然后再绘制透明对象,这将为您提供所需的结果。在其他情况下,首先绘制透明对象,不透明对象则绘制在上方,因为透明对象QPhongAlphaMaterial具有QNoDepthMask呈现状态,该状态指示其不写入深度缓冲区。因此,不透明对象始终通过深度测试,而该透明对象实际上已经吸引到该位置。您需要做更多的工作才能为任意场景图和摄像机位置正确绘制透明对象。

Qt3D渲染图

要了解您必须执行的操作,您应该了解Qt3D渲染图的布局。如果您已经知道这一点,则可以跳过此部分。

斜体字在以下文本中引用了图形图像中的项目。

如果使用a Qt3DWindow,则无法访问渲染图根节点。它由窗口维护。您可以通过函数访问QRenderSettings框架图的根节点,activeFramegraph()并且renderSettings()都可以在窗口上调用它们。您还可以通过的功能设置场景图根节点。窗口内部有一个,它在其中设置整个图的根节点,这是上图图像中渲染图根节点setRootEntity()Qt3DWindowQAspectEngine

如果要在3D窗口的现有框架图中插入框架图节点,则必须将其添加为活动框架图的父级,这将在下一部分中进行解释。如果您在窗口中设置了自己的自定义框架图形,setActiveFramegraph()则只需将其附加到末尾,就足够了。

使用 QSortPolicy

正如您已经根据其他问题发现的那样,您可以QSortPolicy在框架图中使用到照相机的距离对实体进行排序。您可以按如下所示添加排序策略(假设这view是您,Qt3DWindow并且scene是场景图的实体,尽管我不知道为什么必须这样做):

Qt3DRender::QFrameGraphNode *framegraph = view.activeFrameGraph();
Qt3DRender::QSortPolicy *sortPolicy = new Qt3DRender::QSortPolicy(scene);
framegraph->setParent(sortPolicy);
QVector sortTypes = 
      QVector() <setSortTypes(sortTypes);
view.setActiveFrameGraph(framegraph);

此代码的问题在于,这种分类策略是按照实体的中心到相机的距离对它们进行排序。如果不透明对象之一比透明对象更靠近摄影机,则无论如何它都会稍后被绘制并遮住透明对象。有关图形说明,请参见下面的图像。

红色和黑色的球体比圆环离相机更远,这就是为什么它们先被绘制且不遮盖圆环的原因。

没有红色球体的中心比圆环的中心更靠近相机。它比圆环晚渲染并封闭。

使用两个框架图分支

如果您使用两个框架图分支,则可以解决上述问题。一种绘制所有不透明的实体,另一种绘制所有透明的实体。为此,您必须使用QLayerQLayerFilter。您可以将图层附加到实体,然后将图层过滤器添加到框架图。这样,您可以排除实体进入框架图的某个分支。

假设您创建了两层,一层用于不透明对象,一层用于透明​​对象:

Qt3DRender::QLayer *transparentLayer = new Qt3DRender::QLayer;
Qt3DRender::QLayer *opaqueLayer = new Qt3DRender::QLayer;

您必须将透明层作为一个组件附加到每个透明对象,并将不透明层附加到每个不透明对象作为组件(使用addComponent())。

不幸的是,您需要一棵特殊的框架图树来包括两个相应的图层过滤器(同样,假设view是您的Qt3DWindow):

Qt3DRender::QRenderSurfaceSelector *renderSurfaceSelector
        = new Qt3DRender::QRenderSurfaceSelector();
renderSurfaceSelector->setSurface(&view);
Qt3DRender::QClearBuffers *clearBuffers 
        = new Qt3DRender::QClearBuffers(renderSurfaceSelector);
clearBuffers->setBuffers(Qt3DRender::QClearBuffers::AllBuffers);
clearBuffers->setClearColor(Qt::white);

这是清除缓冲区的第一个分支。现在,添加以下代码:

Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(renderSurfaceSelector);
Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector(viewport);
Qt3DRender::QCamera *camera = new Qt3DRender::QCamera(cameraSelector);
// set your camera parameters here
cameraSelector->setCamera(camera);

由于您创建的QViewport子项,QRenderSurfaceSelector因此相对于,您现在是框架图中的同级项QClearBuffers。您可以在此处看到示例框架图的图示。

现在,您必须创建两个包含层过滤器的叶节点。Qt3D引擎到达叶子时始终执行整个分支。这意味着首先绘制不透明的对象,然后绘制透明的对象。

// not entirely sure why transparent filter has to go first
// I would have expected the reversed order of the filters but this works...

Qt3DRender::QLayerFilter *transparentFilter = new Qt3DRender::QLayerFilter(camera);
transparentFilter->addLayer(transparentLayer);

Qt3DRender::QLayerFilter *opaqueFilter = new Qt3DRender::QLayerFilter(camera);
opaqueFilter->addLayer(opaqueLayer);

现在,两层滤镜是您的框架图分支中的叶节点,并且Qt3D首先绘制不透明的对象,然后再绘制,因为它使用相同的视口并且所有内容都将在上面绘制透明的对象。它将正确地绘制它们(即不在透明对象实际位于的不透明对象的前面,因为我们没有再次清除深度缓冲区->拆分框架图仅在相机节点上发生)。

现在在您的上设置新的framegaph Qt3DWindow

view.setActiveFrameGraph(renderSurfaceSelector);

结果:


推荐阅读
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • 为了确保iOS应用能够安全地访问网站数据,本文介绍了如何在Nginx服务器上轻松配置CertBot以实现SSL证书的自动化管理。通过这一过程,可以确保应用始终使用HTTPS协议,从而提升数据传输的安全性和可靠性。文章详细阐述了配置步骤和常见问题的解决方法,帮助读者快速上手并成功部署SSL证书。 ... [详细]
  • 解决Unreal Engine中UMG按钮长时间按住自动释放的问题
    本文探讨了在Unreal Engine中使用UMG按钮时,长时间按住按钮会导致自动释放的问题,并提供了详细的解决方案。 ... [详细]
  • 一个建表一个执行crud操作建表代码importandroid.content.Context;importandroid.database.sqlite.SQLiteDat ... [详细]
  • 为什么多数程序员难以成为架构师?
    探讨80%的程序员为何难以晋升为架构师,涉及技术深度、经验积累和综合能力等方面。本文将详细解析Tomcat的配置和服务组件,帮助读者理解其内部机制。 ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • 实验九:使用SharedPreferences存储简单数据
    本实验旨在帮助学生理解和掌握使用SharedPreferences存储和读取简单数据的方法,包括程序参数和用户选项。 ... [详细]
  • 开发技巧:在Interface Builder中实现UIButton文本居中对齐的方法与步骤
    开发技巧:在Interface Builder中实现UIButton文本居中对齐的方法与步骤 ... [详细]
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • 在《ChartData类详解》一文中,我们将深入探讨 MPAndroidChart 中的 ChartData 类。本文将详细介绍如何设置图表颜色(Setting Colors)以及如何格式化数据值(Formatting Data Values),通过 ValueFormatter 的使用来提升图表的可读性和美观度。此外,我们还将介绍一些高级配置选项,帮助开发者更好地定制和优化图表展示效果。 ... [详细]
  • 本文介绍了如何利用Struts1框架构建一个简易的四则运算计算器。通过采用DispatchAction来处理不同类型的计算请求,并使用动态Form来优化开发流程,确保代码的简洁性和可维护性。同时,系统提供了用户友好的错误提示,以增强用户体验。 ... [详细]
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • 在Linux系统中,网络配置是至关重要的任务之一。本文详细解析了Firewalld和Netfilter机制,并探讨了iptables的应用。通过使用`ip addr show`命令来查看网卡IP地址(需要安装`iproute`包),当网卡未分配IP地址或处于关闭状态时,可以通过`ip link set`命令进行配置和激活。此外,文章还介绍了如何利用Firewalld和iptables实现网络流量控制和安全策略管理,为系统管理员提供了实用的操作指南。 ... [详细]
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
author-avatar
fenfei2702936060
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有