场景由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);
}
}
通过一些操作可以重现几种情况:例如使用QGLSphere
或QGLCylinder
或手动创建几何体,为材质添加颜色或纹理,更改对象数量,更改颜色/材质的数量等。我注意到的依赖关系是集合中的材料数量+ 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);
}
}
就是这样。