씬 그래프 - RHI 텍스처 항목
QRhi 렌더링된 텍스처를 표시하는 커스텀 QQuickItem 을 구현하는 방법을 보여줍니다.
이 예제에서는 QRhi API를 사용하여 크로스 플랫폼 휴대용 3D 렌더링을 텍스처로 수행한 다음 해당 이미지를 표시하는 항목을 구현하는 방법을 보여 줍니다.
참고: 이 예제에서는 Qt GUI 모듈의 호환성이 제한적으로 보장되는 API를 사용하면서 휴대용 크로스 플랫폼 3D 렌더링을 수행하는 고급 저수준 기능을 보여줍니다. QRhi API를 사용하기 위해 애플리케이션은 Qt::GuiPrivate
으로 연결되며 <rhi/qrhi.h>
을 포함합니다.
다른 접근 방식과의 비교
RHI Under QML 예제는 Qt Quick 씬 그래프의 자체 렌더링 전에 사용자 지정 렌더링을 실행하여 효과적으로 "언더레이"를 제공하는 방식으로 QRhi API를 사용하여 이식 가능한 크로스 플랫폼 3D 렌더링을 구현하는 방법을 보여줍니다. 이 접근 방식은 추가 렌더 타깃과 렌더 패스가 필요하고, 씬 그래프의 자체 그리기 호출 전에 사용자 지정 렌더링이 메인 렌더링 패스에 삽입되므로 효율적입니다.
반면 이 예제에서는 별도의 렌더 타깃인 QRhiTexture, dimensions 이 씬에서 QQuickItem 의 크기와 일치하며 전체 렌더 패스를 사용하여 해당 텍스처를 지운 다음 그리는 데 사용됩니다. 그런 다음 텍스처는 메인 렌더 패스에서 샘플링되어 쿼드 텍스처링에 사용되어 2D 이미지를 효과적으로 표시합니다.
언더레이/오버레이 접근 방식과 비교하면 여기에는 진정한 QQuickItem 이 있으므로 3D 렌더링의 평면화된 2D 이미지를 Qt Quick 씬의 어느 곳에서나 표시, 블렌딩 및 변형할 수 있습니다. 하지만 텍스처를 먼저 렌더링해야 하므로 리소스 및 성능 측면에서 비용이 더 많이 든다는 단점이 있습니다.
개요
이 예제는 QQuickRhiItem 와 QQuickRhiItemRenderer 을 사용하여 구현되었습니다. QQuickRhiItem 는 하위 클래스로서 QSGSimpleTextureNode 을 사용하여 QRhiTexture 의 내용을 표시하는 완전한 기능을 갖춘 사용자 정의 QQuickItem 를 쉽고 빠르게 얻을 수 있는 편의 클래스입니다. 텍스처의 내용은 QQuickRhiItemRenderer 서브클래스에 구현된 애플리케이션 제공 로직에 의해 생성됩니다.
ExampleRhiItem
는 angle
및 backgroundAlpha
와 같은 몇 가지 프로퍼티를 제공하는 QQuickRhiItem 서브클래스입니다. 이러한 프로퍼티는 QML에서 읽고, 쓰고, 애니메이션화할 것입니다. Qt Quick 의 스레드 렌더링 모델을 지원하기 위해 QQQuickRhiItemRenderer에는 QQuickRhiItem (메인/GUI 스레드에 속함)와 QQuickRhiItemRenderer (렌더 스레드가 있는 경우 렌더 스레드에 속함) 간에 데이터 복사를 안전하게 수행하기 위해 다시 구현할 수 있는 가상 synchronize() 함수가 있습니다.
QQuickRhiItemRenderer *ExampleRhiItem::createRenderer() { return new ExampleRhiItemRenderer; } void ExampleRhiItem::setAngle(float a) { if (m_angle == a) return; m_angle = a; emit angleChanged(); update(); } void ExampleRhiItem::setBackgroundAlpha(float a) { if (m_alpha == a) return; m_alpha = a; emit backgroundAlphaChanged(); update(); } void ExampleRhiItemRenderer::synchronize(QQuickRhiItem *rhiItem) { ExampleRhiItem *item = static_cast<ExampleRhiItem *>(rhiItem); if (item->angle() != m_angle) m_angle = item->angle(); if (item->backgroundAlpha() != m_alpha) m_alpha = item->backgroundAlpha(); }
initialize()는 렌더링()을 처음 호출하기 전에 적어도 한 번 호출되지만 실제로는 QQuickItem 지오메트리가 변경되는 경우(일부 레이아웃 변경, 창 크기 조정 등으로 인해), 설정이 변경되는 경우 등 여러 번 호출될 수 있습니다.샘플 수 및 텍스처 형식과 같은 QQuickRhiItem 설정이 변경되거나 항목이 새로운 QQuickWindow 에 속하도록 부모가 변경되는 경우, 이러한 모든 경우 하나 이상의 QQuickRhiItem-관리 리소스가 변경되어 하위 클래스에도 영향을 미치기 때문에 초기화() 호출을 다시 트리거합니다. 여기 예제 코드는 이러한 특수한 상황( QRhi 변경 , 샘플 수 변경, 텍스처 형식 변경)을 처리하기 위해 준비되었습니다. (컬러 버퍼로 사용된 텍스처를 유지하지 않으므로 크기가 달라져 텍스처가 다시 생성되는 경우는 특별한 처리가 필요하지 않습니다).
void ExampleRhiItemRenderer::initialize(QRhiCommandBuffer *cb) { if (m_rhi != rhi()) { m_rhi = rhi(); m_pipeline.reset(); } if (m_sampleCount != renderTarget()->sampleCount()) { m_sampleCount = renderTarget()->sampleCount(); m_pipeline.reset(); } QRhiTexture *finalTex = m_sampleCount > 1 ? resolveTexture() : colorTexture(); if (m_textureFormat != finalTex->format()) { m_textureFormat = finalTex->format(); m_pipeline.reset(); }
초기화()의 나머지 부분은 간단한 QRhi 기반 코드입니다.
3D 장면은 편의를 위해 QRhiRenderTarget 에서 쿼리한 출력 크기를 기반으로 계산된 원근 투영을 사용합니다(멀티샘플링 사용 여부와 관계없이 작동하지만 colorTexture() 및 msaaColorBuffer()에 액세스하려면 어떤 오브젝트가 유효한지에 따라 분기 로직이 필요하기 때문입니다).
3D 그래픽 API 간의 좌표계 차이에 대응하기 위해 QRhi::clipSpaceCorrMatrix()를 사용한다는 점에 유의하세요.
if (!m_pipeline) { m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData))); m_vbuf->create(); m_ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64)); m_ubuf->create(); m_srb.reset(m_rhi->newShaderResourceBindings()); m_srb->setBindings({ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, m_ubuf.get()), }); m_srb->create(); m_pipeline.reset(m_rhi->newGraphicsPipeline()); m_pipeline->setShaderStages({ { QRhiShaderStage::Vertex, getShader(QLatin1String(":/scenegraph/rhitextureitem/shaders/color.vert.qsb")) }, { QRhiShaderStage::Fragment, getShader(QLatin1String(":/scenegraph/rhitextureitem/shaders/color.frag.qsb")) } }); QRhiVertexInputLayout inputLayout; inputLayout.setBindings({ { 5 * sizeof(float) } }); inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } }); m_pipeline->setSampleCount(m_sampleCount); m_pipeline->setVertexInputLayout(inputLayout); m_pipeline->setShaderResourceBindings(m_srb.get()); m_pipeline->setRenderPassDescriptor(renderTarget()->renderPassDescriptor()); m_pipeline->create(); QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch(); resourceUpdates->uploadStaticBuffer(m_vbuf.get(), vertexData); cb->resourceUpdate(resourceUpdates); } const QSize outputSize = renderTarget()->pixelSize(); m_viewProjection = m_rhi->clipSpaceCorrMatrix(); m_viewProjection.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f); m_viewProjection.translate(0, 0, -4);
render()의 구현은 단일 삼각형의 드로잉을 기록합니다. 회전 각도가 변경될 것으로 예상되므로 4x4 매트릭스가 있는 균일 버퍼는 매번 업데이트됩니다. 투명 색상에는 항목에서 제공한 배경 알파가 구워져 있습니다. 빨강, 초록, 파랑 컴포넌트에도 알파 값을 미리 곱해야 한다는 점을 기억하세요.
void ExampleRhiItemRenderer::render(QRhiCommandBuffer *cb) { QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch(); QMatrix4x4 modelViewProjection = m_viewProjection; modelViewProjection.rotate(m_angle, 0, 1, 0); resourceUpdates->updateDynamicBuffer(m_ubuf.get(), 0, 64, modelViewProjection.constData()); // Qt Quick expects premultiplied alpha const QColor clearColor = QColor::fromRgbF(0.5f * m_alpha, 0.5f * m_alpha, 0.7f * m_alpha, m_alpha); cb->beginPass(renderTarget(), clearColor, { 1.0f, 0 }, resourceUpdates); cb->setGraphicsPipeline(m_pipeline.get()); const QSize outputSize = renderTarget()->pixelSize(); cb->setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height())); cb->setShaderResources(); const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0); cb->setVertexInput(0, 1, &vbufBinding); cb->draw(3); cb->endPass(); }
QQuickRhiItem, 씬 그래프 - QML 아래의 RHI 및 씬 그래프 - 커스텀 QSGRenderNode도참조하세요 .
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.