Qt3D中左手到右手坐标系

时间:2017-10-25 08:14:30

标签: c++ qt qml coordinate-systems qt3d

如何镜像 Qt3D 中的坐标系?

我使用略微修改加载了全景图(能够使用元信息(倾斜标题值来调整初始视图)并从自定义中解压缩单个面格式*.360(只有六个*.jpg - s))SkyboxEntity。突然间,所有的纹理信息都被错误地反映出来了。

Scene3D {
    aspects: ["input", "logic"]
    cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
    multisample: true

    entity: Entity {
        Camera {
            id: basicCamera

            projectionType: CameraLens.PerspectiveProjection
            fieldOfView: 60
            nearPlane: 0.1
            farPlane: 2.0 * Math.SQRT2
            position: Qt.vector3d(0.0, 0.0, 0.0)
            upVector: Qt.vector3d(0.0, 1.0, 0.0)
            viewCenter: Qt.vector3d(1.0, 0.0, 0.0)
        }

        FirstPersonCameraController {
            camera: basicCamera
            lookSpeed: -200.0
        }

        components: [
            RenderSettings {
                activeFrameGraph: ForwardRenderer {
                    camera: basicCamera
                    clearColor: "transparent"
                }
            },
            InputSettings {}
        ]

        PanoEntity {
            source: "file:///home/user/library.360"
        }
    }
}

panoentity.hpp

#pragma once

#include <Qt3DExtras>

class PanoEntity
        : public Qt3DCore::QEntity
{

    Q_OBJECT

    Q_PROPERTY(QUrl source MEMBER source NOTIFY sourceChanged)

public :

    explicit PanoEntity(Qt3DCore::QNode * const parent = Q_NULLPTR);

private Q_SLOTS :

    void reloadTexture(QUrl source);

Q_SIGNALS :

    void sourceChanged(const QUrl & path);

private :

    Qt3DRender::QEffect * const effect = ::new Qt3DRender::QEffect;
    Qt3DRender::QMaterial * const material = ::new Qt3DRender::QMaterial;
    Qt3DRender::QTextureCubeMap * const texture = ::new Qt3DRender::QTextureCubeMap;
    Qt3DRender::QTextureLoader * const textureLoader = ::new Qt3DRender::QTextureLoader;
    Qt3DRender::QShaderProgram * const shader = ::new Qt3DRender::QShaderProgram;
    Qt3DRender::QTechnique * const techinque = ::new Qt3DRender::QTechnique;
    Qt3DRender::QFilterKey * const filterKey = ::new Qt3DRender::QFilterKey;
    Qt3DRender::QRenderPass * const renderPass = ::new Qt3DRender::QRenderPass;
    Qt3DExtras::QCuboidMesh * const mesh = ::new Qt3DExtras::QCuboidMesh;
    Qt3DRender::QParameter * const textureParameter = ::new Qt3DRender::QParameter{QStringLiteral("skyboxTexture"), texture};
    Qt3DRender::QTextureImage * const posXImage = ::new Qt3DRender::QTextureImage;
    Qt3DRender::QTextureImage * const posYImage = ::new Qt3DRender::QTextureImage;
    Qt3DRender::QTextureImage * const posZImage = ::new Qt3DRender::QTextureImage;
    Qt3DRender::QTextureImage * const negXImage = ::new Qt3DRender::QTextureImage;
    Qt3DRender::QTextureImage * const negYImage = ::new Qt3DRender::QTextureImage;
    Qt3DRender::QTextureImage * const negZImage = ::new Qt3DRender::QTextureImage;
    Qt3DCore::QTransform * const transform = ::new Qt3DCore::QTransform;

    QUrl source;

};

panoentity.cpp

#include "panoentity.h"

#include "configurator.hpp"
#include "pano.h"
#include "common.hpp"
#include "utility.hpp"

using namespace Qt3DCore;
using namespace Qt3DExtras;
using namespace Qt3DRender;

PanoEntity::PanoEntity(QNode * const parent)
    : QEntity{parent}
{
    textureLoader->setGenerateMipMaps(false);

    shader->setVertexShaderCode(QShaderProgram::loadSource(QStringLiteral("qrc:/shaders/pano.vert")));
    shader->setFragmentShaderCode(QShaderProgram::loadSource(QStringLiteral("qrc:/shaders/pano.frag")));

    filterKey->setParent(effect);
    filterKey->setName(QStringLiteral("renderingStyle"));
    filterKey->setValue(QStringLiteral("forward"));

    techinque->addFilterKey(filterKey);

    renderPass->setShaderProgram(shader);

    const auto cullFront = ::new QCullFace;
    cullFront->setMode(QCullFace::Front);
    const auto depthTest = ::new QDepthTest;
    depthTest->setDepthFunction(QDepthTest::LessOrEqual);

    renderPass->addRenderState(cullFront);
    renderPass->addRenderState(depthTest);

    techinque->addRenderPass(renderPass);

    effect->addTechnique(techinque);

    material->setEffect(effect);
    material->addParameter(textureParameter);

    mesh->setXYMeshResolution({2, 2});
    mesh->setXZMeshResolution({2, 2});
    mesh->setYZMeshResolution({2, 2});

    posXImage->setFace(QTextureCubeMap::CubeMapPositiveX);
    posXImage->setMirrored(false);
    posYImage->setFace(QTextureCubeMap::CubeMapPositiveY);
    posYImage->setMirrored(false);
    posZImage->setFace(QTextureCubeMap::CubeMapPositiveZ);
    posZImage->setMirrored(false);
    negXImage->setFace(QTextureCubeMap::CubeMapNegativeX);
    negXImage->setMirrored(false);
    negYImage->setFace(QTextureCubeMap::CubeMapNegativeY);
    negYImage->setMirrored(false);
    negZImage->setFace(QTextureCubeMap::CubeMapNegativeZ);
    negZImage->setMirrored(false);

    transform->setRotationY(90.0f);
    transform->setRotationX(90.0f);

    texture->setMagnificationFilter(QTextureCubeMap::Linear);
    texture->setMinificationFilter(QTextureCubeMap::Linear);
    texture->setGenerateMipMaps(false);
    texture->setWrapMode(QTextureWrapMode{QTextureWrapMode::ClampToEdge});

    texture->addTextureImage(posXImage);
    texture->addTextureImage(posYImage);
    texture->addTextureImage(posZImage);
    texture->addTextureImage(negXImage);
    texture->addTextureImage(negYImage);
    texture->addTextureImage(negZImage);

    addComponent(mesh);
    addComponent(material);
    addComponent(transform);

    connect(this, &PanoEntity::sourceChanged, this, &PanoEntity::reloadTexture);
}

void PanoEntity::reloadTexture(QUrl source)
{
    if (!source.isLocalFile()) {
        return;
    }
    QDir currentCatalog = Configurator::currentCatalogPath();
    QFileInfo fileInfo{currentCatalog, source.toLocalFile()};
    if (fileInfo.suffix() != "360") {
        return;
    }
    if (fileInfo.canonicalPath().startsWith(currentCatalog.canonicalPath())) {
        return;
    }
    QFile panoFile{fileInfo.filePath()};
    if (!panoFile.open(QFile::ReadOnly)) {
        return;
    }
    QDataStream dataStream{&panoFile};
    Pano pano;
    if (!pano.readHeader(dataStream)) {
        return;
    }
    if (!pano.readBody(dataStream)) {
        return;
    }
    dataStream.setDevice(Q_NULLPTR);
    QDir cacheDir{getBaseDirName() + "/var/cache/pano"};
    if (!cacheDir.exists() && !cacheDir.mkpath(cacheDir.path())) {
        return;
    }
    if (!panoFile.reset()) {
        return;
    }
    QCryptographicHash hash{QCryptographicHash::Md5};
    hash.addData(&panoFile);
    const auto baseName = QString::fromUtf8(hash.result().toHex());
    int i = 0;
    for (const auto suffix : {"_posx", "_negx", "_posy", "_negy", "_posz", "_negz"}) {
        const QString fileName = baseName + suffix;
        if (!cacheDir.exists(fileName)) {
            QSaveFile file{cacheDir.filePath(fileName)};
            if (file.open(QFile::WriteOnly | QFile::Truncate)) {
                Q_ASSERT(file.pos() == 0);
                if (file.write(pano.frames[i].buffer())) {
                    if (!file.commit()) {
                        qWarning() << QStringLiteral("Unable to commit %1").arg(file.fileName());
                    } else {
                        qDebug().noquote()
                                << QStringLiteral("QML URL: %1; suffix %2 is cached in file %3")
                                   .arg(source.toString(), QString::fromLatin1(suffix), file.fileName());
                    }
                }
            } else {
                qDebug() << file.errorString();
            }
        } else {
            qDebug() << "file already exist: " << cacheDir.filePath(fileName);
        }
        ++i;
    }
    const auto basePath = cacheDir.filePath(baseName);

    posXImage->setSource(QUrl::fromLocalFile(basePath + "_posx"));
    posYImage->setSource(QUrl::fromLocalFile(basePath + "_negy"));
    posZImage->setSource(QUrl::fromLocalFile(basePath + "_posz"));
    negXImage->setSource(QUrl::fromLocalFile(basePath + "_negx"));
    negYImage->setSource(QUrl::fromLocalFile(basePath + "_posy"));
    negZImage->setSource(QUrl::fromLocalFile(basePath + "_negz"));

    textureParameter->setValue(QVariant::fromValue(texture));

    transform->setRotationZ(transform->rotationZ() + pano.heading());
    transform->setRotationX(transform->rotationX() + pano.tilt());
}

我是否可以通过为每个轴交换posneg纹理并使它们镜像来实现这一目标,或者我可以使用{以某种方式交换两个坐标系轴{1}} CameraLens的东西?或者也许最好只修改着色器以不同的顺序对纹理坐标进行采样?

0 个答案:

没有答案