Qt3d:QGLMaterial / QGLMaterialCollection:大量的QGLMaterial可用于1000 QGLScenenodes

时间:2012-10-24 20:27:29

标签: opengl colors textures qt3d

场景由1500个球体和1000个圆柱体组成。必须为每个球体和圆柱体设置不同的颜色。我使用QGLCollectionMaterial,创建n QGLMaterial-Object并将材料添加到Collection。对于每个QGLSceneNode(球体或圆柱体),我设置一个调色板 - MaterialCollection,然后调用setMaterialIndex(i),其中i是相应的索引。使用n = 25(材质计数)和2000 QGLSceneNodes,渲染场景,但响应鼠标操作(旋转,缩放)有点慢。颜色数量的进一步增加使得场景更具交互性,而n = 100它看起来像幻灯片。在我的例子中,代替颜色QGLMaterial包括纹理,但这并不重要。如果设置了颜色,也会发生同样的情况。我修改了qt3d/src/examples/qt3d/builder的示例。以下是源代码:

标题文件:

#ifndef BUILDER_H
#define BUILDER_H
#include "qglview.h"
QT_BEGIN_NAMESPACE
class QGLSceneNode;
class QGLBuilder;
QT_END_NAMESPACE
class BuilderView : public QGLView

{
    Q_OBJECT

public:
    BuilderView(const QGLFormat &f, QWidget *parent = 0);
    ~BuilderView();
protected:
    void initializeGL(QGLPainter *painter);
    void paintGL(QGLPainter *painter);
private:
    QGLSceneNode *buildGeometry();
    QGLSceneNode *buildGeometry2(qreal radius = 1.0,
                                 int divisions = 5);
    QGLSceneNode *canScene;
    int mCount;
    int mColorCount;
    QGLMaterialCollection *mPalette;
    void initializePalette();
};
#endif

CPP-文件:

#include "builder.h"
#include "qglbuilder.h"
#include "qglmaterialcollection.h"
#include "qgltexture2d.h"
#include "qglmaterial.h"
#include "qglscenenode.h"
#include "qgllightmodel.h"
#include "qglsphere.h"
#include "qglcylinder.h"
#include <QtGui/qmatrix4x4.h>
#include <QtCore/qmath.h>

static inline qreal rval()
{
    return qreal((qreal(qrand()) / qreal(RAND_MAX)) * 200.0);
}

static inline int ival()
{
    return (qreal(qrand()) / qreal(RAND_MAX)) * 255;
}

BuilderView::BuilderView(const QGLFormat &f, QWidget *parent)
    : QGLView(f, parent)
    , canScene(new QGLSceneNode(this))
{
    QGLSceneNode *can = buildGeometry();
    //QGLSceneNode *sphere = buildGeometry2();
    mPalette = new QGLMaterialCollection(canScene);
    mCount = 1000;
    mColorCount = 100;
    initializePalette();
    can->setObjectName("SceneNode Can");
    canScene->setObjectName("Root - canScene");
    for(int i = 1; i < mCount; i++)
    {
        QGLSceneNode *node = new QGLSceneNode(canScene);
        node->setObjectName("Sphere_r_" + QString::number(i));
        node->setPalette(mPalette);
        node->setMaterialIndex(i % mColorCount);;
        node->setEffect(QGL::LitModulateTexture2D);
        node->addNode(can);
        {
            QMatrix4x4 mat;
            mat.translate(1.0f * rval(), 1.0f * rval(), -1.0f * rval());
            node->setLocalTransform(mat);
        }
        node = new QGLSceneNode(canScene);
        node->setObjectName("Sphere_b_" + QString::number(i));
        node->setPalette(mPalette);
        node->setMaterialIndex(i % mColorCount);
        node->setEffect(QGL::LitModulateTexture2D);
        node->addNode(can);
        {
            QMatrix4x4 mat;
            mat.translate(-1.0f * rval(), -1.0f * rval(), -1.0f * rval());
            node->setLocalTransform(mat);
        }
    }
}

BuilderView::~BuilderView()
{
    delete canScene;
}

void BuilderView::initializeGL(QGLPainter *painter)
{
    glEnable(GL_CULL_FACE);
    camera()->setFieldOfView(45);
    camera()->setNearPlane(0.1);
    camera()->setFarPlane(5000);
    camera()->setEye(QVector3D(0.0, 0.0, 100.0));

}

void BuilderView::paintGL(QGLPainter *painter)
{
    canScene->draw(painter);
}

QGLSceneNode *BuilderView::buildGeometry()
{
    QGLBuilder builder;
////    QGLSceneNode *root = builder.sceneNode();

////    QGLMaterial *mat = new QGLMaterial;
////    mat->setColor(Qt::blue);
////    mat->setAmbientColor(Qt::blue);
////    mat->setDiffuseColor(Qt::blue);
////    QUrl url;
////    url.setPath(QLatin1String(":/images/qt-soup.png"));
////    url.setScheme(QLatin1String("file"));
////    mat->setTextureUrl(url);
////    int canMat = root->palette()->addMaterial(mat);
////    root->setMaterialIndex(canMat);
////    root->setEffect(QGL::LitMaterial);

//    // size data for can
//    const qreal canRadius = 1.0f;
//    const qreal canHeight = 5.0f;
//    const int numSlices = 32;

//    QGeometryData canRim;
//    QVector3D canExtrudeVec(0.0f, 0.0f, -canHeight);

//    // do the math for the defining points
//    for (int i = 0; i < numSlices; ++i)
//    {
//        qreal angle = (qreal(i) * 2.0 * M_PI) / numSlices;
//        canRim.appendVertex(QVector3D(canRadius * qCos(angle),
//                                      canRadius * qSin(angle),
//                                      canHeight / 2.0f));
//    }
//    // create the flat top lid of the can
//    builder.newSection();
//    //builder.currentNode()->setMaterialIndex(canMat);
//    builder.currentNode()->setObjectName(QLatin1String("CanTop"));
//    QGeometryData top;
//    top.appendVertex(canRim.center());
//    top.appendVertexArray(canRim.vertices());
//    builder.addTriangulatedFace(top);

//    // create the sides of the can
//    builder.newSection();
//    builder.currentNode()->setObjectName(QLatin1String("CanSides"));
//    //builder.currentNode()->setMaterialIndex(canMat);
//    //builder.currentNode()->setEffect(QGL::LitMaterial);
//    QGeometryData canTop = canRim;
//    canTop.detach();
//    canTop.appendVertex(canTop.vertex(0));       // doubled vert for texture seam
////    canTop.generateTextureCoordinates();            // generate x texture coords
//    QGeometryData canBase = canTop.translated(canExtrudeVec);  // base has tex.y == 0
///*    for (int i = 0; i < canTop.count(); ++i)
//        canTop.texCoord(i).setY(1.0); */                     // top has tex.y == 1
//    builder.addQuadsInterleaved(canTop, canBase);

//    // create the flat bottom lid of the can
//    builder.newSection();
//    builder.currentNode()->setObjectName(QLatin1String("CanBottom"));
//    //builder.currentNode()->setMaterialIndex(canMat);
//    //builder.currentNode()->setEffect(QGL::LitMaterial);
//    QGeometryData rimReversed = canRim.translated(canExtrudeVec).reversed();
//    QGeometryData canBottom;
//    canBottom.appendVertex(rimReversed.center());
//    canBottom.appendVertexArray(rimReversed.vertices());
//    builder.addTriangulatedFace(canBottom);

    builder << QGLCylinder(1.0f, 1.0f, 5.0f, 32);
    return builder.finalizedSceneNode();
    //! [3]
}


QGLSceneNode *BuilderView::buildGeometry2(qreal radius, int divisions)
{
    QGLBuilder builder;
    // Determine the number of slices and stacks to generate.
    static int const slicesAndStacks[] = {
        8, 4,
        8, 8,
        16, 8,
        16, 16,
        32, 16,
        32, 32,
        64, 32,
        64, 64,
        128, 64,
        128, 128
    };

    if (divisions < 1)
        divisions = 1;
    else if (divisions > 10)
        divisions = 10;
    int stacks = slicesAndStacks[divisions * 2 - 1];
    int slices = slicesAndStacks[divisions * 2 - 2];

    // Precompute sin/cos values for the slices and stacks.
    const int maxSlices = 128 + 1;
    const int maxStacks = 128 + 1;
    qreal sliceSin[maxSlices];
    qreal sliceCos[maxSlices];
    qreal stackSin[maxStacks];
    qreal stackCos[maxStacks];
    for (int slice = 0; slice < slices; ++slice) {
        qreal angle = 2 * M_PI * slice / slices;
        sliceSin[slice] = qFastSin(angle);
        sliceCos[slice] = qFastCos(angle);
    }
    sliceSin[slices] = sliceSin[0]; // Join first and last slice.
    sliceCos[slices] = sliceCos[0];
    for (int stack = 0; stack <= stacks; ++stack) {
        qreal angle = M_PI * stack / stacks;
        stackSin[stack] = qFastSin(angle);
        stackCos[stack] = qFastCos(angle);
    }
    stackSin[0] = 0.0f;             // Come to a point at the poles.
    stackSin[stacks] = 0.0f;

    // Create the stacks.
    for (int stack = 0; stack < stacks; ++stack) {
        QGeometryData prim;
        qreal z = radius * stackCos[stack];
        qreal nextz = radius * stackCos[stack + 1];
        qreal s = stackSin[stack];
        qreal nexts = stackSin[stack + 1];
        qreal c = stackCos[stack];
        qreal nextc = stackCos[stack + 1];
        qreal r = radius * s;
        qreal nextr = radius * nexts;
        for (int slice = 0; slice <= slices; ++slice) {
            prim.appendVertex
                (QVector3D(nextr * sliceSin[slice],
                           nextr * sliceCos[slice], nextz));
            prim.appendNormal
                (QVector3D(sliceSin[slice] * nexts,
                           sliceCos[slice] * nexts, nextc));
            prim.appendTexCoord
                (QVector2D(1.0f - qreal(slice) / slices,
                           1.0f - qreal(stack + 1) / stacks));

            prim.appendVertex
                (QVector3D(r * sliceSin[slice],
                           r * sliceCos[slice], z));
            prim.appendNormal
                (QVector3D(sliceSin[slice] * s,
                           sliceCos[slice] * s, c));
            prim.appendTexCoord
                (QVector2D(1.0f - qreal(slice) / slices,
                           1.0f - qreal(stack) / stacks));
        }
        builder.addQuadStrip(prim);
    }
//    builder << QGLSphere();
//    builder.currentNode()->setObjectName("Geometry of Sphere");
    return builder.finalizedSceneNode();
}

void BuilderView::initializePalette()
{
    for(int i = 0; i < mColorCount; i++)
    {
        QImage image(QSize(1, 6), QImage::Format_ARGB32_Premultiplied);
        QPainter painter(&image);
        QColor c(ival(), ival(), ival());
        QColor c2(ival(), ival(), ival());
        QLinearGradient linearGrad(QPointF(0.5, 0), QPointF(0.5, 6));
        linearGrad.setColorAt(0, c);
        linearGrad.setColorAt(1, c2);
        painter.fillRect(image.rect(), linearGrad);
        painter.end();
        QGLMaterial *m = new QGLMaterial;
        //m->setColor(c);
        QGLTexture2D *tex = new QGLTexture2D(m);
        tex->setImage(image);
        m->setTexture(tex);
        mPalette->addMaterial(m);
    }
}

通过一些操作可以重现几种情况:例如使用QGLSphereQGLCylinder或手动创建几何体,为材质添加颜色或纹理,更改对象数量,更改颜色/材质的数量等。我注意到的依赖关系是集合中的材料数量+ QGLScenenodes的数量。

摘要:是Qt3D中的一个错误,或者任何人都有一个想法,如何放置或管理多个QGLScenenodes的大量颜色/材料。在“几个QGLScenenodes”下,我理解了超过2000个对象。

如果可以为场景中的多个对象使用/设置多种颜色,那么我可以在运行时轻松更改颜色吗?

以下两个重要部分是所有魔法发生的地方。

在initializePalette()中填充调色板。生成的材料有mColorCount(= 25),并将它们添加到调色板中。对于每种材质,都是使用渐变生成的简单纹理((无关紧要,您也可以设置颜色)。

  //create palette QGLMaterialCollection
void BuilderView::initializePalette()
    {
        for(int i = 0; i < mColorCount; i++)
        {
            //create a texture with gradient
            // from random color c to color c2
            QImage image(QSize(1, 6), QImage::Format_ARGB32_Premultiplied);
            QPainter painter(&image);
            QColor c(ival(), ival(), ival());
            QColor c2(ival(), ival(), ival());
            QLinearGradient linearGrad(QPointF(0.5, 0), QPointF(0.5, 6));
            linearGrad.setColorAt(0, c);
            linearGrad.setColorAt(1, c2);
            // write to image
            painter.fillRect(image.rect(), linearGrad);
            painter.end();
            // create material
            QGLMaterial *m = new QGLMaterial;
            //m->setColor(c);
            QGLTexture2D *tex = new QGLTexture2D(m);
            // set image to texture
            tex->setImage(image);
            // set texture to material
            m->setTexture(tex);
            // add material to palette
            mPalette->addMaterial(m);
        }
    }

以下是生成的2000(mcount * 2)QGLScenNodes。然后从调色板中将材质放置为索引为0到mColorCount。

//mCount = 1000;
  //mColorCount = 25; for example
  for(int i = 1; i < mCount; i++)
        {
            QGLSceneNode *node = new QGLSceneNode(canScene);
            node->setObjectName("Sphere_r_" + QString::number(i));
            //set palette with mColorCount of materials
            node->setPalette(mPalette);
            //set index from 0 to mColorCount
            node->setMaterialIndex(i % mColorCount);;
            // effect is a lighting model: LitModulateTexture2D 
            // combine a lighting with object color
            node->setEffect(QGL::LitModulateTexture2D);
            // add geomtry
            node->addNode(can);
            // simple random translate 
            {
                QMatrix4x4 mat;
                mat.translate(1.0f * rval(), 1.0f * rval(), -1.0f * rval());
                node->setLocalTransform(mat);
            }
            //second node do the same
            node = new QGLSceneNode(canScene);
            node->setObjectName("Sphere_b_" + QString::number(i));
            node->setPalette(mPalette);
            node->setMaterialIndex(i % mColorCount);
            node->setEffect(QGL::LitModulateTexture2D);
            node->addNode(can);
            {
                QMatrix4x4 mat;
                mat.translate(-1.0f * rval(), -1.0f * rval(), -1.0f * rval());
                node->setLocalTransform(mat);
            }
        }

就是这样。

0 个答案:

没有答案