公开课地址:中国大学慕课网——华中科技大学《计算机图形学》
根据老师的课件的代码绘制出来的球只有一面,当把X坐标和Z坐标进行交换就能正常绘制出球。
shader代码参考上一篇博客:Qt+OpenGL——索引绘制四边形
头文件
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_5_Core>
#include <QOpenGLShaderProgram>
class GLWidget : public QOpenGLWidget,public QOpenGLFunctions_4_5_Core
{
Q_OBJECT
public:
explicit GLWidget(QWidget *parent=nullptr);
~GLWidget();
protected:
void iniDatas();
void initializeGL(); //初始化相关的操作全在这个函数中完成
void resizeGL(int w,int h);
void paintGL();
float *getBallVertex(int xSegment,int ySegment);
int *getBallIndices(int xSegment,int ySegment);
private:
QOpenGLShaderProgram *m_pShaderProgram = nullptr;
};
#endif // GLWIDGET_H
源文件
#include "glwidget.h"
#include <QOpenGLBuffer>
#include <QtMath>
#include <QDebug>
#define BUFFER_OFFSET(offset) ((void*)(offset))
#define BALL_X_SEGMENT 50
#define BALL_Y_SEGMENT 50
GLuint VAO = -1;
GLWidget::GLWidget(QWidget *parent):
QOpenGLWidget(parent)
{
}
GLWidget::~GLWidget()
{
}
void GLWidget::iniDatas()
{
float *vertices = getBallVertex(BALL_X_SEGMENT,BALL_Y_SEGMENT);
int *indices = getBallIndices(BALL_X_SEGMENT,BALL_Y_SEGMENT);
glGenVertexArrays(1,&VAO);
glBindVertexArray(VAO);
GLuint VBO;
glGenBuffers(1,&VBO);
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices) * (BALL_X_SEGMENT + 1) * (BALL_Y_SEGMENT + 1) * 3,vertices,GL_STATIC_DRAW);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,sizeof(float) * 3,BUFFER_OFFSET(0));
glEnableVertexAttribArray(0);
GLuint EBO;
glGenBuffers(1,&EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices) * BALL_X_SEGMENT * BALL_Y_SEGMENT * 6,indices,GL_STATIC_DRAW);
glBindVertexArray(0);//解绑
glBindBuffer(GL_ARRAY_BUFFER,0);
// glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);//填充图,,默认
// glPolygonMode(GL_FRONT_AND_BACK,GL_POINT);//散点图
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);//线框图
}
void GLWidget::initializeGL()
{
initializeOpenGLFunctions();
m_pShaderProgram = new QOpenGLShaderProgram(this);
m_pShaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex,":/shaders/vertext.vert");
m_pShaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment,":/shaders/fragment.frag");
m_pShaderProgram->link();
m_pShaderProgram->bind();
iniDatas();
}
void GLWidget::resizeGL(int w, int h)
{
glViewport(0,0,w,h);
}
void GLWidget::paintGL()
{
static const GLfloat color[] = {0.0f,0.0f,0.0f,1.0f};
glClearBufferfv(GL_COLOR,0,color);
if(VAO == -1){
return;
}
glUseProgram(m_pShaderProgram->programId());
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES,(BALL_X_SEGMENT + 1) * (BALL_Y_SEGMENT + 1) * 3 * 6,GL_UNSIGNED_INT,0);
glBindVertexArray(0);
update();
}
float *GLWidget::getBallVertex(int xSegment, int ySegment)
{
float *data = nullptr;
data = new float[(xSegment + 1) * (ySegment + 1) * 3];
int nIndex = 0;
for (int y = 0; y <= ySegment; ++y) {
for (int x = 0; x <= xSegment; ++x) {
float xS = x * 1.0 / xSegment;
float yS = y * 1.0 / ySegment;
float xPos = qSin(xS * 2.0f * M_PI) * qSin(yS * M_PI);
float yPos = qCos(yS * M_PI);
float zPos = qCos(xS * 2.0f * M_PI) * qSin(ySegment * M_PI);
data[nIndex] = xPos;
data[nIndex + 1] = yPos;
data[nIndex + 2] = zPos;
nIndex += 3;
}
}
return data;
}
int *GLWidget::getBallIndices(int xSegment, int ySegment)
{
int *indices = nullptr;
indices = new int[xSegment * ySegment * 6];
int nIndex = 0;
for (int i = 0; i < ySegment; ++i) {
for (int j = 0; j < xSegment; ++j) {
indices[nIndex] = i * (xSegment + 1) + j;
indices[nIndex + 1] = (i + 1) * (xSegment + 1) + j;
indices[nIndex + 2] = (i + 1) * (xSegment + 1) + (j + 1);
indices[nIndex + 3] = i * (xSegment + 1) + j;
indices[nIndex + 4] = (i + 1) * (xSegment + 1) + (j + 1);
indices[nIndex + 5] = i * (xSegment + 1) + (j + 1);
nIndex += 6;
}
}
return indices;
}
最终效果