我拿qt-opengl做一个体数据的三维可视化,先创建QOpenGLBuffer模型,然后把数据填入QImage并应用在QOpenGLTexture,最后在显示时把纹理贴在对应模型面上。
现在问题是显示出来结果中间没问题,但边缘颜色是对称边的颜色,如图左边缘颜色是右边缘的,上边缘是下边缘的,(因为其他需求,现在这个面分成了4个部分,这不重要,合在一起就是中间那两条线没了,但整体还是边缘颜色对称的)。
部分实现
void Widgets3D::initializeGL()
{
initializeOpenGLFunctions();
makeObject();
#define PROGRAM_VERTEX_ATTRIBUTE 0
#define PROGRAM_TEXCOORD_ATTRIBUTE 1
vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
const char* vsrc =
"attribute highp vec4 vertex;\n"
"attribute mediump vec4 texCoord;\n"
"varying mediump vec4 texc;\n"
"uniform mediump mat4 matrix;\n"
"void main(void)\n"
"{\n"
" gl_Position = matrix * vertex;\n"
" texc = texCoord;\n"
"}\n";
vshader->compileSourceCode(vsrc);
fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
const char* fsrc =
"uniform sampler2D texture;\n"
"varying mediump vec4 texc;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(texture, texc.st);\n"
"}\n";
fshader->compileSourceCode(fsrc);
program = new QOpenGLShaderProgram;
program->addShader(vshader);
program->addShader(fshader);
program->link();
}
void Widgets3D::paintGL()
{
glClearColor(0.95, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
program->bind();
QMatrix4x4 m;
if (height() > width())
m.ortho(-0.5f, +0.5f, +0.5f * height() / width(), -0.5f * height() / width(), 4.0f, 15.0f);
else
m.ortho(-0.5f * width() / height(), +0.5f * width() / height(), +0.5f, -0.5f, 4.0f, 15.0f);
m.translate(0.0f, 0.0f, -10.0f);
m.rotate(xRot / 16.0f, 1.0f, 0.0f, 0.0f);
m.rotate(yRot / 16.0f, 0.0f, 1.0f, 0.0f);
m.rotate(zRot / 16.0f, 0.0f, 0.0f, 1.0f);
program->setUniformValue("matrix", m);
program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
program->setAttributeBuffer(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, 0, 3, 5 * sizeof(GLfloat));
program->setAttributeBuffer(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat));
if ((xRot % 5760 >= 0 && xRot % 5760 < (360 * 4) && yRot % 5760 >= (360 * 12) && yRot % 5760 < (360 * 16)) ||
(xRot % 5760 >= (360 * 4) && xRot % 5760 < (360 * 8) && yRot % 5760 >= (360 * 4) && yRot % 5760 < (360 * 8)))
{
if (showX) { SideTexture[0]->bind(); glDrawArrays(GL_TRIANGLE_FAN, 0 * 4, 4); }
//...其他纹理
}
//...其他情况
program->release();
}
void Widgets3D::makeObject(void)
{
if (_type == 0) DrawXSide<int>(xPos, mapX);
else if (_type == 1) DrawXSide<float>(xPos, mapX);
else if (_type == 2) DrawXSide<double>(xPos, mapX);
QImage mapX1 = mapX->copy(0, 0, yPos + 1, zPos + 1);
QImage mapX2 = mapX->copy(0, zPos, yPos + 1, _sizeZ - zPos);
QImage mapX3 = mapX->copy(yPos, 0, _sizeY - yPos, zPos + 1);
QImage mapX4 = mapX->copy(yPos, zPos, _sizeY - yPos, _sizeZ - zPos);
SideTexture[0] = new QOpenGLTexture(mapX1.mirrored());
SideTexture[1] = new QOpenGLTexture(mapX2.mirrored());
SideTexture[2] = new QOpenGLTexture(mapX3.mirrored());
SideTexture[3] = new QOpenGLTexture(mapX4.mirrored());
//...其他面
creatVbo();
}
void Widgets3D::creatVbo(void)
{
double coords[7][4][3] = {/*...各面位置*/};
QList<GLfloat> vertData;
for (int i = 0; i < 4; ++i)//X
for (int j = 0; j < 4; ++j) {
vertData.append(0.35 * coords[i][j][0]);
vertData.append(0.35 * coords[i][j][1]);
vertData.append(0.35 * coords[i][j][2]);
vertData.append(j == 0 || j == 3);
vertData.append(j == 0 || j == 1);
}
//...其他面
m_vbo.release();
m_vbo.destroy();
m_vbo.create();
m_vbo.bind();
m_vbo.allocate(vertData.constData(), vertData.count() * sizeof(GLfloat));
}