Как правильно определить две QRenderTargets в Qt3D для информации о глубине и цвете с помощью вершинного шейдера с двумя переменными out - PullRequest
1 голос
/ 16 октября 2019

Моя компания использует Qt3D для отображения графики CAD. Для этого приложения необходимо внедрить пиксельно-корректный Order-Independent-Transparency. В качестве первого шага для достижения этой цели я попытался написать небольшое приложение, которое отображает простую плоскость для глубинной текстуры и rgba-текстуры.

Это мой «маленький» пример приложения:

main.cpp

#include <QApplication>
#include <Qt3DRender/QTechniqueFilter>
#include <Qt3DCore/QTransform>
#include <Qt3DRender/QRenderSurfaceSelector>
#include <Qt3DRender/QParameter>
#include <Qt3DRender/QViewport>
#include <Qt3DRender/QTextureImage>
#include <Qt3DRender/QCamera>
#include <Qt3DRender/QCameraSelector>
#include <Qt3DRender/QClearBuffers>
#include <Qt3DRender/QTexture>
#include <Qt3DExtras/QPlaneMesh>
#include <Qt3DExtras/QTextureMaterial>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DRender/QParameter>
#include <Qt3DRender/QRenderTarget>
#include <Qt3DRender/QRenderTargetOutput>
#include <Qt3DRender/QRenderTargetSelector>
#include <QDebug>
#include "TextureMaterial.h"

namespace {
    Qt3DCore::QEntity* createPlane()
    {
        auto entity = new Qt3DCore::QEntity;

        auto mesh = new Qt3DExtras::QPlaneMesh;
        mesh->setWidth(0.3);
        mesh->setHeight(0.3);
        entity->addComponent(mesh);

        return entity;
    }
}

void main(int argc, char** args) {
    QApplication app(argc, args);

    auto view = new Qt3DExtras::Qt3DWindow();

    auto mClearBuffers = new Qt3DRender::QClearBuffers;
    auto mMainCameraSelector = new Qt3DRender::QCameraSelector;
    mMainCameraSelector->setCamera(view->camera());
    auto mRenderSurfaceSelector = new Qt3DRender::QRenderSurfaceSelector;
    auto mMainViewport = new Qt3DRender::QViewport;
    mMainViewport->setNormalizedRect(QRectF(0, 0, 1, 1));

    mClearBuffers->setClearColor(Qt::lightGray);
    mClearBuffers->setBuffers(Qt3DRender::QClearBuffers::BufferType::ColorDepthBuffer);
    mClearBuffers->setParent(mMainCameraSelector);

    mRenderSurfaceSelector->setParent(mMainViewport);
    mMainCameraSelector->setParent(mRenderSurfaceSelector);

    auto renderTargetSelector = new Qt3DRender::QRenderTargetSelector(mMainCameraSelector);
    auto renderTarget = new Qt3DRender::QRenderTarget(renderTargetSelector);
    { // Depth Texture Output

        auto depthTexture = new Qt3DRender::QTexture2D;
        depthTexture->setSize(400, 300);
        depthTexture->setFormat(Qt3DRender::QAbstractTexture::TextureFormat::DepthFormat);

        auto renderTargetOutput = new Qt3DRender::QRenderTargetOutput;
        renderTargetOutput->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::AttachmentPoint::Depth);
        renderTargetOutput->setTexture(depthTexture);

        renderTarget->addOutput(renderTargetOutput);
    }
    {// Image Texture Output
        auto imageTexture = new Qt3DRender::QTexture2D;

        imageTexture->setSize(400, 300);
        imageTexture->setFormat(Qt3DRender::QAbstractTexture::TextureFormat::RGBA32F);
        auto renderTargetOutput = new Qt3DRender::QRenderTargetOutput;
        renderTargetOutput->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::AttachmentPoint::Color1);
        renderTargetOutput->setTexture(imageTexture);

        renderTarget->addOutput(renderTargetOutput);
    }

    view->setActiveFrameGraph(mMainViewport);
    view->activeFrameGraph()->dumpObjectTree();

    auto rootEntity = new Qt3DCore::QEntity();
    view->setRootEntity(rootEntity);

    auto cameraEntity = view->camera();
    cameraEntity->lens()->setPerspectiveProjection(45.0f, 1., 0.1f, 10000.0f);
    cameraEntity->setPosition(QVector3D(0, 0.3, 0));
    cameraEntity->setUpVector(QVector3D(0, 1, 0));
    cameraEntity->setViewCenter(QVector3D(0, 0, 0));

    {
        auto mat = new TextureMaterial;
        auto plane = createPlane();
        plane->setParent(rootEntity);
        auto trans = new Qt3DCore::QTransform;
        //trans->setTranslation(QVector3D(0, -2, 0));
        trans->setRotation(QQuaternion::fromAxisAndAngle({ 1,0,0 }, 80));
        plane->addComponent(trans);
        plane->addComponent(mat);
    }

    view->setWidth(400);
    view->setHeight(300);
    view->show();
    app.exec();

}

TextureMaterial.h

#pragma once

#include <Qt3DRender/QMaterial>

namespace Qt3DRender {
    class QTechnique;
    class QRenderPass;
    class QShaderProgram;
}

class TextureMaterial : public Qt3DRender::QMaterial
{
    Q_OBJECT

public:
    explicit TextureMaterial(Qt3DCore::QNode* parent = nullptr);
    ~TextureMaterial();
};

TextureMaterial.cpp

#include "TextureMaterial.h"

#include <Qt3DRender/QMaterial>
#include <Qt3DRender/QEffect>
#include <Qt3DRender/QTechnique>
#include <Qt3DRender/QShaderProgram>
#include <Qt3DRender/QParameter>
#include <Qt3DRender/QGraphicsApiFilter>
#include <Qt3DRender/QAbstractTexture>
#include <QUrl>

TextureMaterial::TextureMaterial(Qt3DCore::QNode* parent) : QMaterial(parent)
{
    auto colorParm = new Qt3DRender::QParameter(QStringLiteral("diffuseColor"), QColor::fromRgbF(0.0,1.0,0.1,0.8)); // Green!!!
    auto shaderProgram = new Qt3DRender::QShaderProgram;
    shaderProgram->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shader.vert"))));
    shaderProgram->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shader.frag"))));
    auto technique = new Qt3DRender::QTechnique;
    technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL);
    technique->graphicsApiFilter()->setMajorVersion(3);
    technique->graphicsApiFilter()->setMinorVersion(1);
    technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile);

    auto renderPass = new Qt3DRender::QRenderPass;
    renderPass->setShaderProgram(shaderProgram);

    technique->addRenderPass(renderPass);
    auto effect = new  Qt3DRender::QEffect;
    effect->addTechnique(technique);
    effect->addParameter(colorParm);

    setEffect(effect);
}

TextureMaterial::~TextureMaterial()
{
}

shader.frag

#version 150 core

uniform vec4 diffuseColor;
in vec3 position;

out vec4 blendedColor;
out float depth;

void main()
{
    depth=gl_FragCoord.z; 
    blendedColor=diffuseColor; 
}

shader.vert

#version 150 core

in vec3 vertexPosition;
out vec3 position;

uniform mat4 modelView;
uniform mat4 mvp;

void main()
{
    gl_Position = mvp * vec4( vertexPosition, 1.0 );
}

files.qrc

<!DOCTYPE RCC><RCC version="1.0">
    <qresource prefix="/">
      <file>shader.frag</file>
      <file>shader.vert</file>
    </qresource>
</RCC>

Поскольку все выходные данные фрагментного шейдера должны отображаться в этих двух текстурах, я ожидал, что внутри моего Qt3dWindow ничего не вижу.

Удивительно, но есть некоторые выходные данные, который зависит от порядка определений blendedColor и depth в моем фрагментном шейдере.

Если глубина определена первой, я увижу буфер глубины, и если blendedColor идет первым, я 'увидим diffuseColor.

Вот что я увижу:

depth out variable is defined first

blendedColor out variable is defined first

По сути, у меня есть два вопроса:

  1. Почему я могу видеть depth и blendedColor в моем средстве просмотра, если целью рендеринга является текстура?
  2. Как я могу проверить,что визуализируется в текстурах depthTexture и imageTexture?
    • Можно ли, например, сохранить эти текстуры как изображения?
...