Хорошо, здесь идет расширенный ответ.
Причина, по которой это иногда случается, а иногда не зависит от порядка ваших сущностей.Если вы экспериментируете с двумя простыми сферами, одна прозрачная, а другая нет, вы увидите, что когда прозрачная сфера будет добавлена позже, она будет нарисована над непрозрачным объектом - так, как вы этого хотите.
Это происходит потому, что непрозрачный объект будет нарисован первым (он появляется первым в графе сцены), а затем прозрачный объект, который даст вам желаемый результат.В другом случае, когда прозрачный объект рисуется первым, непрозрачный объект рисуется выше, потому что QPhongAlphaMaterial
имеет состояние визуализации QNoDepthMask
, которое говорит ему не записывать вбуфер глубины.Таким образом, непрозрачный объект всегда проходит тест глубины, на котором прозрачный объект фактически уже нарисован.Вам нужно еще немного поработать, чтобы правильно нарисовать прозрачные объекты для произвольных графиков сцены и положения камеры.
График рендеринга Qt3D
Чтобы понять, что вам нужно сделать, вы должны понять, как рендеринг Qt3Dграфик выложен.Если вы уже знаете это, вы можете пропустить эту часть.
Курсивные слова ссылки на элементы в графическом изображении в следующем тексте.
Если вы используете Qt3DWindow
, вы не сможете получить доступ к корневому узлу графика рендеринга .Поддерживается окном.Вы можете получить доступ к корневому узлу QRenderSettings и вашего фрейма графа через функции activeFramegraph()
и renderSettings()
, которые вы оба можете вызвать в окне.Вы также можете установить корневой узел графа сцены с помощью функции setRootEntity()
Qt3DWindow
.Внутренне окно имеет QAspectEngine
, где оно устанавливает корневой узел всего графа, который является корневым узлом графа рендеринга на изображении графа выше.
Если вы хотите вставить узел фрейма графа в существующий фреймграф 3D-окна, вы должны добавить его в качестве родителя активного фрейма графа, который я объясню в следующем разделе.Если у вас есть свой собственный фреймграф, который вы установили в окне через 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);
Проблема с этим кодом заключается в том, что эта политика сортировки сортирует объекты по расстоянию между их центрами до камеры.Если один из непрозрачных объектов находится ближе к камере, чем прозрачный объект, он все равно рисуется позже и перекрывает прозрачный объект.См. Изображения ниже для графического объяснения.
Красная и черная сферы находятся дальше от камеры, чем тор, поэтому они рисуются первыми и не закрывают тор.
Нет, центр красной сферы ближе к камере, чем центр тора.Он обрабатывается позже тора и закрывает его.
Использование двух ветвей фрейма графа
Вы можете решить проблему выше, если используете два фрейма графаветви.Тот, который рисует все непрозрачные объекты, и тот, который рисует все прозрачные.Чтобы достичь этого, вы должны использовать QLayer
и QLayerFilter
.Вы можете прикрепить слои к объектам, а затем добавить фильтры слоев в свой фреймграф.Таким образом, вы можете исключить объекты из определенной ветки вашего фрейма.
Допустим, вы создали два слоя, один для непрозрачных объектов и один для прозрачных:
Qt3DRender::QLayer *transparentLayer = new Qt3DRender::QLayer;
Qt3DRender::QLayer *opaqueLayer = new Qt3DRender::QLayer;
Вы должныприкрепите прозрачный слой к каждому прозрачному объекту, а непрозрачный слой к каждому непрозрачному объекту как компоненту (используя addComponent()
).
К сожалению, вам нужно специальное дерево фрейма графа, чтобы включить два соответствующих фильтра слоя (опять же, при условии, что Qt3DWindow
- это ваш *1090*):
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
.Вы можете увидеть иллюстрацию примера framegraphs здесь .
Теперь вам нужно создать два конечных узла, которые содержат фильтры слоев.Движок 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);
Результат: