gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:39:19 24 4
gpt4 key购买 nike

我有一个可以通过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<int>(sizeof(float)));
float *positions = reinterpret_cast<float*>(bufferBytes.data());

for(auto point : triangles){
*positions++ = static_cast<float>(point.x());
*positions++ = 0.0f; //We need to drow only on the surface
*positions++ = static_cast<float>(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<int>(sizeof(unsigned int))); // start to end
unsigned int *indices = reinterpret_cast<unsigned int*>(indexBytes.data());

for(unsigned int i = 0; i < static_cast<unsigned int>(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<unsigned int>(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 << QPointF( 0 ,-1000) << QPointF(0 ,1000) << QPointF(1000, -1000);
drawTriangles(triangle1, Qt::black);

QPolygonF triangle2;
triangle2 << QPointF(-1000,-1000) << QPointF(-100,1000) << QPointF(-100,-1000);
drawTriangles(triangle2, Qt::red);
}

map 清除功能clearMap():
void clearMap()
{
if(mapEntity_){
delete mapEntity_;
mapEntity_ = nullptr;
mapEntity_ = new Qt3DCore::QEntity(view3dRootEntity_);
}
}

最佳答案

好的,这是扩展答案。
有时发生这种情况,有时不发生这种情况的原因取决于您实体的顺序。如果您尝试使用两个简单的球体,一个是透明球体,一个不是透明球体,那么您会发现,稍后添加透明球体时,它将在不透明对象上方绘制-就像您想要的那样。
发生这种情况是因为将首先绘制不透明的对象(它在场景图中首先出现),然后再绘制透明的对象,这将为您提供所需的结果。在其他情况下,首先绘制透明对象,因为 QPhongAlphaMaterial 具有 QNoDepthMask 渲染状态,该状态指示其不写入深度缓冲区,所以将不透明对象绘制在上方。因此,不透明对象始终通过深度测试,而透明对象实际上已经吸引到该深度测试。您需要做更多的工作才能为任意场景图和摄像机位置正确绘制透明对象。
Qt3D渲染图
要了解您必须做什么,您应该了解Qt3D渲染图的布局。如果您已经知道这一点,则可以跳过此部分。
enter image description here
斜体字在以下文本中引用了图形图像中的项目。
如果使用Qt3DWindow,则无法访问渲染图的根节点。它由窗口维护。您可以通过函数activeFramegraph()renderSettings()来访问QRenderSettings和框架图的根节点,这两个函数都可以在窗口上调用。您还可以通过setRootEntity()Qt3DWindow函数设置场景图的根节点。窗口内部有一个 QAspectEngine ,它在其中设置整个图的根节点,这是上面图图像中渲染图的根节点。
如果要在3D窗口的现有框架图中插入框架图节点,则必须将其添加为 Activity 框架图的父级,这将在下一部分中进行解释。如果您有自己的自定义框架图形,可以通过setActiveFramegraph()在窗口中设置,然后将其附加到末尾,就足够了。
使用QSortPolicy正如您已经根据其他问题发现的那样,您可以在框架图中使用QSortPolicy按与相机的距离对实体进行排序。您可以按如下所示添加排序策略(假设view是您的Qt3DWindow,而scene是您的场景图的根实体,尽管我不知道为什么必须这样做):

Qt3DRender::QFrameGraphNode *framegraph = view.activeFrameGraph();
Qt3DRender::QSortPolicy *sortPolicy = new Qt3DRender::QSortPolicy(scene);
framegraph->setParent(sortPolicy);
QVector<Qt3DRender::QSortPolicy::SortType> sortTypes =
QVector<Qt3DRender::QSortPolicy::SortType>() << Qt3DRender::QSortPolicy::BackToFront;
sortPolicy->setSortTypes(sortTypes);
view.setActiveFrameGraph(framegraph);
此代码的问题在于,这种排序策略是按照实体的中心到相机的距离对它们进行排序的。如果其中一个不透明对象比透明对象更靠近摄影机,则无论如何它稍后都会被绘制并遮住透明对象。有关图形说明,请参见下面的图像。
红色和黑色球体比圆环离相机更远,这就是为什么它们先被绘制并且不遮盖圆环的原因。
no occlusion
没有红色球体的中心比圆环的中心更靠近相机。它比圆环晚渲染并封闭。
occlusion
使用两个框架分支
如果使用两个框架图分支,则可以解决上述问题。一种绘制所有不透明的实体,另一种绘制所有透明的实体。为此,您必须使用 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,它现在是您的框架图中的同级。您可以看到示例框架图 here的图示。
现在,您必须创建两个包含层过滤器的叶节点。 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首先绘制不透明的对象,然后,由于它使用相同的视口(viewport)并且所有内容都将在上方绘制透明的对象。它将正确绘制它们(即不在透明对象实际位于的不透明对象的前面,因为我们没有再次清除深度缓冲区->仅在相机节点上才拆分框架图)。
现在在 Qt3DWindow上设置新的framegaph:
view.setActiveFrameGraph(renderSurfaceSelector);
结果:
enter image description here

关于c++ - Qt3d。在三角形上绘制透明的QSphereMesh,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55002979/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com