qt的opengl的使用示例

openglWidget.h


#ifndef OPENGLWIDGET_H
#define OPENGLWIDGET_H

#include <QOpenGLWidget>
#include <QGLWidget>
#include "qevent.h"

class openglWidget : public QOpenGLWidget
{
    Q_OBJECT

public:
    openglWidget(QWidget* parent = nullptr);//parent就是父窗口部件的指针,name就是这个窗口部件的名称,fs就是窗口是否最大化
    ~openglWidget();

protected:
    // 设置渲染环境
    void initializeGL();//用来初始化这个OpenGL窗口部件的,可以在里面设定一些有关选项
    // 响应窗口的大小变化
    void resizeGL(int w, int h);//用来处理窗口大小变化这一事件的,width和height就是新的大小状态下的宽和高了,另外resizeGL()在处理完后会自动刷新屏幕
    // 绘制窗口
    void paintGL();//用来绘制OpenGL的窗口了,只要有更新发生,这个函数就会被调用

private:
    //*********************事件********************
    void mousePressEvent(QMouseEvent* event);
    void mouseMoveEvent(QMouseEvent* event);
    void mouseReleaseEvent(QMouseEvent* event);
    void keyPressEvent(QKeyEvent *event);

    //*********************绘图********************
    // 场景渲染
    void renderScene();
    // 场景渲染-基本图形
    void renderBasicShape();
    // 场景渲染-立方体纹理
    void renderTextureCube();
    // 场景渲染-圆柱体纹理
    void renderTextureCylinder();
    // 绘制立方体
    void drawCube();
    // 绘制圆形
    void drawCircle();
    // 绘制圆柱体
    void drawCylinder();
    // 绘制圆锥体
    void drawCone();
    // 绘制四面体
    void drawTetrahedron();
    // 绘制球体
    void drawSphere(GLfloat xx = 0.0,
                    GLfloat yy = 0.0,
                    GLfloat zz = 0.0,
                    GLfloat radius = 1.0,
                    GLfloat M = 100.0,
                    GLfloat N = 100.0);
    // 绘制圆环
    void DrawTorus(double Radius = 1,
                   double TubeRadius = 0.2,
                   int Sides = 20,
                   int Rings = 30);
    // 加载纹理
    void loadGLTextures();

private:
//    GLfloat rTri= 0.0;//用于三角形的角度
    bool fullscreen = false;//用来保存窗口是否处于全屏状态的变量

    // 旋转角度
    GLfloat  xRot;
    GLfloat  yRot;
    GLfloat  zRot;
    // 存储纹理
    GLuint texture[2];

    //平移
    bool ctrlPress = false;
    QPoint moveStartPos;
    GLfloat translateX = 0;
    GLfloat translateY = 0;
    GLfloat translateZ = -12;
//    bool leftButtonPress = false;
//    bool rightButtonPress = false;

};

#endif // OPENGLWIDGET_H

openglWidget.cpp

#include "openglWidget.h"
#include <gl/GL.h>
#include <gl/GLU.h>
#include <qmath.h>
#include "qdebug.h"
#include <QApplication>

#define PI          3.14
#define ROT_DELTA   0.5f

void qgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
{
    const GLdouble ymax = zNear * tan(qDegreesToRadians(fovy) / 2.0);
    const GLdouble ymin = -ymax;
    const GLdouble xmin = ymin * aspect;
    const GLdouble xmax = ymax * aspect;
    glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
}

openglWidget::openglWidget(QWidget* parent)
    : QOpenGLWidget(parent)
    , xRot(0.0f)
    , yRot(0.0f)
    , zRot(0.0f)
{ 
    // 设置画面的双缓冲和深度缓存
//       setFormat(QGLFormat(QGL::DoubleBuffer | QGL::DepthBuffer));

//    setGeometry(100,100,640,480);
//    setWindowTitle("SQYopengl");

    if(fullscreen)
        showFullScreen();//全屏显示窗口
}

openglWidget::~openglWidget()
{

}

void openglWidget::initializeGL()
{
    glShadeModel(GL_SMOOTH);//GL_SMOOTH和GL_FLAT着色模式,GL_SMOOTH阴影平滑:渐变
    glClearColor(0.0,0.0,0.0,0.0);//设置清除屏幕时所用的颜色。
    //色彩的工作原理:色彩值的范围从0.0到1.0。0.0代表最黑的情况,1.0就是最亮的情况。
    //glClearColor后的第一个参数是红色,第二个是绿色,第三个是蓝色。最大值也是1.0,代表特定颜色分量的最亮情况。
    //最后一个参数是Alpha值。当它用来清除屏幕的时候,我们不用关心第四个数字。现在让它为0.0

    glClearDepth(1.0);//设置深度缓存
    glEnable(GL_DEPTH_TEST);//启用深度测试
    glDepthFunc(GL_LEQUAL);//所作深度测试的类型
    //上面这三行必须做的是关于depth buffer(深度缓存)的。
    //将深度缓存设想为屏幕后面的层。深度缓存不断的对物体进入屏幕内部有多深进行跟踪。
    //我们本节的程序其实没有真正使用深度缓存,但几乎所有在屏幕上显示3D场景OpenGL程序都使用深度缓存。
    //它的排序决定那个物体先画。这样您就不会将一个圆形后面的正方形画到圆形上来。深度缓存是OpenGL十分重要的部分

    glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);//真正精细的透视修正。这一行告诉OpenGL我们希望进行最好的透视修正。这会十分轻微的影响性能。但使得透视图看起来好一点。

    glEnable(GL_TEXTURE_2D);
    loadGLTextures();
}

void openglWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_COLOR_BUFFER_BIT);//清空屏幕和深度缓存
    glLoadIdentity();//重置当前的模型观察矩阵

//    //画三角形
//    glTranslatef( -3, 3, -12);
//    glColor3f( 0.5, 0.5, 1.0 );
//    glRotatef(rTri, 0.0,-1.0,0.0);
//    glBegin(GL_TRIANGLES);
//    glVertex3f(0.0,0.5,0.0);
//    glVertex3f(-0.5,-0.5,0.0);
//    glVertex3f(0.5,-0.5,0.0);
//    glEnd();
//    update();
//    rTri+=0.2;

    glPushMatrix();
    glColor3f(0, 1, 0);
    glTranslatef(translateX, -translateY, translateZ);
//    glRotatef(angle, 1, 1 , 1);
    drawCone();
    glPopMatrix();


//    renderScene();
//    renderTextureCube();
//    renderTextureCylinder();

}

void openglWidget::resizeGL(int w, int h)
{
    if(h == 0)
    {
        h = 1;
    }

    glViewport(this->x(),this->y(),(GLint)w,(GLint)h);//重置当前的视口(Viewport)
    glMatrixMode(GL_PROJECTION);//选择投影矩阵
    glLoadIdentity();//重置投影矩阵
    qgluPerspective(45.0,(GLfloat)w/(GLfloat)h,0.1,100.0);//建立透视投影矩阵
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void openglWidget::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_F2:
        fullscreen = !fullscreen;
        if(fullscreen)
            showFullScreen();
        else
        {
            showNormal();
            setGeometry(100,100,640,480);
        }
        update();
        break;
    case Qt::Key_Escape:
        close();
        break;
    default:
        break;
    }
    if(event->key()==Qt::Key_Up && event->modifiers()==Qt::ControlModifier)
    {

    }
}

void openglWidget::mousePressEvent(QMouseEvent* event)
{
    if(event->button() == Qt::MiddleButton)
    {
        if(QApplication::keyboardModifiers() == Qt::ControlModifier)//ctrl+鼠标中键 = 平移
        {
            ctrlPress = true;
            moveStartPos = event->pos();
        }
    }
}

void openglWidget::mouseMoveEvent(QMouseEvent* event)
{
    if(ctrlPress)//平移
    {
        translateX += (event->pos().x()-moveStartPos.x())*0.01f;
        translateY += (event->pos().y()-moveStartPos.y())*0.01f;
        update();
        moveStartPos = event->pos();
    }
}

void openglWidget::mouseReleaseEvent(QMouseEvent* event)
{
    if(ctrlPress)
    {
        translateX += (event->pos().x() -moveStartPos.x())*0.01f;
        translateY += (event->pos().y() -moveStartPos.y())*0.01f;
        ctrlPress = false;
    }
}

// 绘制立方体
void openglWidget::drawCube()
{
    glBegin(GL_QUAD_STRIP);         //填充凸多边形
    glColor3f(1, 0, 0);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glColor3f(1, 1, 0);
    glVertex3f(0.0f, 1.0f, 0.0f);
    glColor3f(0, 1, 0);
    glVertex3f(1.0f, 0.0f, 0.0f);
    glColor3f(0, 1, 1);
    glVertex3f(1.0f, 1.0f, 0.0f);
    glColor3f(1, 0, 0);
    glVertex3f(1.0f, 0.0f, -1.0f);
    glColor3f(1, 1, 0);
    glVertex3f(1.0f, 1.0f, -1.0f);
    glColor3f(0, 1, 0);
    glVertex3f(0.0f, 0.0f, -1.0f);
    glColor3f(0, 1, 1);
    glVertex3f(0.0f, 1.0f, -1.0f);
    glColor3f(1, 0, 0);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glColor3f(1, 1, 0);
    glVertex3f(0.0f, 1.0f, 0.0f);
    glEnd();
    glBegin(GL_QUAD_STRIP);
    glColor3f(0, 0, 1);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glColor3f(1, 0, 1);
    glVertex3f(1.0f, 0.0f, 0.0f);
    glColor3f(0, 1, 0);
    glVertex3f(0.0f, 0.0f, -1.0f);
    glColor3f(1, 0, 0);
    glVertex3f(1.0f, 0.0f, -1.0f);
    glColor3f(1, 1, 0);
    glVertex3f(0.0f, 1.0f, 0.0f);
    glColor3f(1, 0, 1);
    glVertex3f(1.0f, 1.0f, 0.0f);
    glColor3f(0, 0, 1);
    glVertex3f(0.0f, 1.0f, -1.0f);
    glColor3f(1, 0, 0);
    glVertex3f(1.0f, 1.0f, -1.0f);
    glEnd();
}

// 绘制圆形
void openglWidget::drawCircle()
{
    glBegin(GL_TRIANGLE_FAN);           //扇形连续填充三角形串
    glVertex3f(0.0f, 0.0f, 0.0f);
    int i = 0;
    for (i = 0; i <= 360; i += 15)
    {
        float p = i * 3.14 / 180;
        glColor3f(sin(p), cos(p), tan(p));
        glVertex3f(sin(p), cos(p), 0.0f);
    }
    glEnd();
}

// 绘制圆柱体
void openglWidget::drawCylinder()
{
    // 利用三角形和四边形等基本图元绘制底面圆圆心在坐标原点, 半径为 r,高为 h,方向沿 z 轴方向的圆柱;
    // 侧面用多个四边形,底面用多个三角形来表示
    glBegin(GL_QUAD_STRIP);//连续填充四边形串
    int i = 0;
    for (i = 0; i <= 360; i += 15)
    {
        float p = i * 3.14 / 180;
        glVertex3f(sin(p), cos(p), 1.0f);
        glVertex3f(sin(p), cos(p), 0.0f);
    }
    glEnd();
    //bottom circle
    glColor3f(1, 0, 0);
    drawCircle();
    glTranslatef(0, 0, 1);
    //top circle
    glColor3f(0, 0, 1);
    drawCircle();
    glColor3f(0, 1, 0);
}

// 绘制圆锥体
void openglWidget::drawCone()
{
    glBegin(GL_QUAD_STRIP);//连续填充四边形串
    int i = 0;
    for (i = 0; i <= 360; i += 15)
    {
        float p = i * 3.14 / 180;
        glColor3f(sin(p), cos(p), 1.0f);
        glVertex3f(0, 0, 1.0f);
        glVertex3f(sin(p), cos(p), 0.0f);
    }
    glEnd();
    //bottom circle
    glColor3f(0, 1, 1);
    drawCircle();
}

// 绘制四面体等
void openglWidget::drawTetrahedron()
{
    glBegin(GL_QUADS);
    glNormal3f(0, 0, -1);
    glColor3f(1.0, 0.0, 0.0);
    glVertex3f(-1, -1, 0);
    glColor3f(0.0, 1.0, 0.0);
    glVertex3f(-1, 1, 0);
    glColor3f(0.0, 0.0, 1.0);
    glVertex3f(1, 1, 0);
    glColor3f(1.0, 1.0, 0.0);
    glVertex3f(1, -1, 0);
    glEnd();

    glBegin(GL_TRIANGLES);
    glNormal3f(0, -1, 0.707);
    glColor3f(0.0, 1.0, 1.0);
    glVertex3f(-1, -1, 0);
    glColor3f(1.0, 0.0, 1.0);
    glVertex3f(1, -1, 0);
    glColor3f(1.0, 0.0, 1.0);
    glVertex3f(0, 0, 1.2);
    glEnd();
    glBegin(GL_TRIANGLES);
    glNormal3f(1, 0, 0.707);
    glColor3f(0.0, 1.0, 1.0);
    glVertex3f(1, -1, 0);
    glColor3f(1.0, 0.0, 1.0);
    glVertex3f(1, 1, 0);
    glColor3f(1.0, 0.0, 1.0);
    glVertex3f(0, 0, 1.2);
    glEnd();
    glBegin(GL_TRIANGLES);
    glNormal3f(0, 1, 0.707);
    glColor3f(0.0, 1.0, 1.0);
    glVertex3f(1, 1, 0);
    glColor3f(1.0, 0.0, 1.0);
    glVertex3f(-1, 1, 0);
    glColor3f(1.0, 0.0, 1.0);
    glVertex3f(0, 0, 1.2);
    glEnd();
    glBegin(GL_TRIANGLES);
    glNormal3f(-1, 0, 0.707);
    glColor3f(1.0, 0.0, 1.0);
    glVertex3f(-1, 1, 0);
    glColor3f(0.0, 1.0, 1.0);
    glVertex3f(-1, -1, 0);
    glColor3f(1.0, 0.0, 0.0);
    glVertex3f(0, 0, 1.2);
    glEnd();
}

// 绘制球体
// 球心坐标为(x,y,z),球的半径为radius,M,N分别表示球体的横纵向被分成多少份
void openglWidget::drawSphere(GLfloat xx, GLfloat yy, GLfloat zz,
                          GLfloat radius, GLfloat M, GLfloat N)
{
    // 选择使用的纹理
    glBindTexture(GL_TEXTURE_2D, texture[0]);

    float step_z = PI / M;
    float step_xy = 2 * PI / N;
    float x[4], y[4], z[4];

    float angle_z = 0.0;
    float angle_xy = 0.0;
    int i = 0, j = 0;
    glBegin(GL_QUADS);
    for(i = 0; i < M; i++)
    {
        angle_z = i * step_z;

        for(j = 0; j < N; j++)
        {
            angle_xy = j * step_xy;

            x[0] = radius * sin(angle_z) * cos(angle_xy);
            y[0] = radius * sin(angle_z) * sin(angle_xy);
            z[0] = radius * cos(angle_z);

            x[1] = radius * sin(angle_z + step_z) * cos(angle_xy);
            y[1] = radius * sin(angle_z + step_z) * sin(angle_xy);
            z[1] = radius * cos(angle_z + step_z);

            x[2] = radius * sin(angle_z + step_z) * cos(angle_xy + step_xy);
            y[2] = radius * sin(angle_z + step_z) * sin(angle_xy + step_xy);
            z[2] = radius * cos(angle_z + step_z);

            x[3] = radius * sin(angle_z) * cos(angle_xy + step_xy);
            y[3] = radius * sin(angle_z) * sin(angle_xy + step_xy);
            z[3] = radius * cos(angle_z);
            for(int k = 0; k < 4; k++)
            {
                glColor3f(sin(angle_z), cos(angle_z), tan(angle_z));
                //glTexCoord2f(0.1f, 0.1f);
                glVertex3f(xx + x[k], yy + y[k], zz + z[k]);
            }
        }
    }
    glEnd();
}

// 绘制圆环
// 大半径Radius,小半径TubeRadius,边数Sides, 环数Rings
void openglWidget::DrawTorus(double Radius, double TubeRadius, int Sides, int Rings)
{
    double sideDelta = 2.0 * PI / Sides;
    double ringDelta = 2.0 * PI / Rings;
    double theta = 0;
    double cosTheta = 1.0;
    double sinTheta = 0.0;

    double phi, sinPhi, cosPhi;
    double dist;
    glColor3f(1, 0, 0);
    for (int i = 0; i < Rings; i++)
    {
        double theta1 = theta + ringDelta;
        double cosTheta1 = cos(theta1);
        double sinTheta1 = sin(theta1);

        glBegin(GL_QUAD_STRIP);
        phi = 0;
        for (int j = 0; j <= Sides; j++)
        {
            phi = phi + sideDelta;
            cosPhi = cos(phi);
            sinPhi = sin(phi);
            dist = Radius + (TubeRadius * cosPhi);

            glNormal3f(cosTheta * cosPhi, sinTheta * cosPhi, sinPhi);
            glColor3f(cosTheta, sinTheta, sinPhi);
            glVertex3f(cosTheta * dist, sinTheta * dist, TubeRadius * sinPhi);

            glNormal3f(cosTheta1 * cosPhi, sinTheta1 * cosPhi, sinPhi);
            glColor3f(cosTheta1, sinTheta1, sinPhi);
            glVertex3f(cosTheta1 * dist, sinTheta1 * dist, TubeRadius * sinPhi);
        }
        glEnd();
        theta = theta1;
        cosTheta = cosTheta1;
        sinTheta = sinTheta1;
    }
}

// 加载纹理
void openglWidget::loadGLTextures()
{
    QImage tex1, buf1;
    QImage tex2, buf2;
    if (!buf1.load(":/data/qt-logo.jpg"))
    {
        // 如果载入不成功,自动生成一个128*128的32位色的绿色图片。
        qWarning("Could not read image file!");
        QImage dummy(128, 128, QImage::Format_RGB32);
        dummy.fill(Qt::green);
        buf1 = dummy;
    }

    if (!buf2.load(":/data/qt-wood.jpg"))
    {
        // 如果载入不成功,自动生成一个128*128的32位色的绿色图片。
        qWarning("Could not read image file!");
        QImage dummy(128, 128, QImage::Format_RGB32);
        dummy.fill(Qt::green);
        buf2 = dummy;
    }

    //***********************************************//
    // 纹理0:qt-logo
    //***********************************************//
    //转换成纹理类型
    tex1 = QGLWidget::convertToGLFormat(buf1);
    // 创建纹理
    glGenTextures(1, &texture[0]);
    // 使用来自位图数据生成的典型纹理,将纹理名字texture[0]绑定到纹理目标上
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    // WRAP参数:纹理坐标超出[0,0]到[1,1]的范围该怎么处理呢?
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    // Filter参数:纹理坐标映射到纹素位置(127.34,255.14)该怎么办?
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // 纹理环境
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    // 将纹素数组从CPU传至GPU并且设置为当前纹理。
    // 在处理单一纹理时,你可以用,负责效率非常低。
    // 多纹理时可以参见纹理绑定。
    glTexImage2D(GL_TEXTURE_2D, 0, 3, tex1.width(), tex1.height(), 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, tex1.bits());

    //***********************************************//
    // 纹理0:qt-logo
    //***********************************************//
    tex2 = QGLWidget::convertToGLFormat(buf2);
    glGenTextures(1, &texture[1]);
    glBindTexture(GL_TEXTURE_2D, texture[1]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, tex2.width(), tex2.height(), 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, tex2.bits());
    // 使用纹理
    // 首先调用glEnable( GL_TEXTURE_2D ),来启用2D纹理;
    // 然后绘制图形,并且为每个顶点指定ST坐标;
    // 最后调用glDisable( GL_TEXTURE_2D ).
}

// 场景渲染
void openglWidget::renderScene(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glPushMatrix();
    renderBasicShape();
    glPopMatrix();

    glPushMatrix();
    glTranslatef(-3, 0, 0);
    renderTextureCube();
    glPopMatrix();

    glPushMatrix();
    glTranslatef(3, 0, 0);
    renderTextureCylinder();
    glPopMatrix();
}

// 渲染基本图形
void openglWidget::renderBasicShape()
{
    static float fRotAngle = 0.0f;
    fRotAngle += ROT_DELTA;
    if (fRotAngle > 360)
        fRotAngle = 0;

    glPushMatrix();
    glColor3f(0, 1, 0);
    glTranslatef(-3, 3, -12);
    glRotatef(fRotAngle, 1, 1 , 1);
    drawCylinder();
    glPopMatrix();

    glPushMatrix();
    glColor3f(1, 0, 0);
    glTranslatef(0, 3, -12);
    glRotatef(fRotAngle, 1, 1 , 1);
    drawTetrahedron();
    glPopMatrix();

    glPushMatrix();
    glColor3f(1, 0, 0);
    glTranslatef(3, 3, -12);
    glRotatef(fRotAngle, 1, 1, 1);
    drawCircle();
    glPopMatrix();

    glPushMatrix();
    glColor3f(1, 0, 0);
    glTranslatef(0, 0, -15);
    glRotatef(fRotAngle, 0, 1, 0);
    drawSphere();
    glPopMatrix();

    glPushMatrix();
    glColor3f(0, 1, 1);
    glTranslatef(-3, -3, -12);
    glRotatef(fRotAngle, 1, 1, 1);
    drawCube();
    glPopMatrix();

    glPushMatrix();
    glColor3f(1, 0, 1);
    glTranslatef(0, -3, -12);
    glRotatef(fRotAngle, 1, 1, 1);
    DrawTorus();
    glPopMatrix();

    glPushMatrix();
    glColor3f(1, 1, 0);
    glTranslatef(3, -3, -12);
    glRotatef(fRotAngle, 1, 1, 1);
    drawCone();
    glPopMatrix();
}

// 渲染纹理
void openglWidget::renderTextureCube()
{
    // 纹理映射
    glColor3f(1.0, 1.0, 1.0);
    glTranslatef(0.0f, 0.0f, -12.0f);
    glRotatef(xRot, 1.0, 0.0, 0.0);
    glRotatef(yRot, 0.0, 1.0, 0.0);
    glRotatef(zRot, 0.0, 0.0, 1.0);
    // 使用来自位图数据生成的典型纹理,将纹理名字texture[0]绑定到纹理目标上
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glBegin( GL_QUADS );
    glTexCoord2f( 0.0, 0.0 );
    glVertex3f( -1.0, -1.0,  1.0 );
    glTexCoord2f( 1.0, 0.0 );
    glVertex3f(  1.0, -1.0,  1.0 );
    glTexCoord2f( 1.0, 1.0 );
    glVertex3f(  1.0,  1.0,  1.0 );
    glTexCoord2f( 0.0, 1.0 );
    glVertex3f( -1.0,  1.0,  1.0 );
    glTexCoord2f( 1.0, 0.0 );
    glVertex3f( -1.0, -1.0, -1.0 );
    glTexCoord2f( 1.0, 1.0 );
    glVertex3f( -1.0,  1.0, -1.0 );
    glTexCoord2f( 0.0, 1.0 );
    glVertex3f(  1.0,  1.0, -1.0 );
    glTexCoord2f( 0.0, 0.0 );
    glVertex3f(  1.0, -1.0, -1.0 );
    glTexCoord2f( 0.0, 1.0 );
    glVertex3f( -1.0,  1.0, -1.0 );
    glTexCoord2f( 0.0, 0.0 );
    glVertex3f( -1.0,  1.0,  1.0 );
    glTexCoord2f( 1.0, 0.0 );
    glVertex3f(  1.0,  1.0,  1.0 );
    glTexCoord2f( 1.0, 1.0 );
    glVertex3f(  1.0,  1.0, -1.0 );
    glTexCoord2f( 1.0, 1.0 );
    glVertex3f( -1.0, -1.0, -1.0 );
    glTexCoord2f( 0.0, 1.0 );
    glVertex3f(  1.0, -1.0, -1.0 );
    glTexCoord2f( 0.0, 0.0 );
    glVertex3f(  1.0, -1.0,  1.0 );
    glTexCoord2f( 1.0, 0.0 );
    glVertex3f( -1.0, -1.0,  1.0 );
    glTexCoord2f( 1.0, 0.0 );
    glVertex3f(  1.0, -1.0, -1.0 );
    glTexCoord2f( 1.0, 1.0 );
    glVertex3f(  1.0,  1.0, -1.0 );
    glTexCoord2f( 0.0, 1.0 );
    glVertex3f(  1.0,  1.0,  1.0 );
    glTexCoord2f( 0.0, 0.0 );
    glVertex3f(  1.0, -1.0,  1.0 );
    glTexCoord2f( 0.0, 0.0 );
    glVertex3f( -1.0, -1.0, -1.0 );
    glTexCoord2f( 1.0, 0.0 );
    glVertex3f( -1.0, -1.0,  1.0 );
    glTexCoord2f( 1.0, 1.0 );
    glVertex3f( -1.0,  1.0,  1.0 );
    glTexCoord2f( 0.0, 1.0 );
    glVertex3f( -1.0,  1.0, -1.0 );
    glEnd();
    xRot += ROT_DELTA;
    if (xRot > 360) xRot = 0;
    yRot += ROT_DELTA;
    if (yRot > 360) yRot = 0;
    zRot += ROT_DELTA;
    if (zRot > 360) zRot = 0;
}

void openglWidget::renderTextureCylinder()
{
    // 纹理映射
    glTranslatef(0.0f, 0.0f, -12.0f);
    glRotatef(xRot, 1.0, 0.0, 0.0);
    //glRotatef(yRot, 0.0, 1.0, 0.0);
    //glRotatef(zRot, 0.0, 0.0, 1.0);
    // 选择使用的纹理
    glBindTexture(GL_TEXTURE_2D, texture[1]);
    // 利用三角形和四边形等基本图元绘制底面圆圆心在坐标原点, 半径为 r,高为 h,方向沿 z 轴方向的圆柱;
    // 侧面用多个四边形,底面用多个三角形来表示
    glBegin(GL_QUAD_STRIP);//连续填充四边形串
    int i = 0;
    for (i = 0; i <= 360; i += 15)
    {
        float p = i * 3.14 / 180;
        //p和圆周是相对应的, 这里让纹理的横坐标随圆周扫过的角度一起改变,就能够将纹理图“刷”上去了,
        //而纵坐标设置为图像的高度和纹理高度的对应,这里合适的参数是根据实际测试得到的
        glTexCoord2f(p / 10, 0.1f);
        glVertex3f(sin(p), cos(p), 1.0f);   //这个 1.0f指定的是高度h
        glTexCoord2f(p / 10, 0.0f);
        glVertex3f(sin(p), cos(p), 0.0f);
    }
    glEnd();
    //bottom circle
    glBegin(GL_TRIANGLE_FAN);           //扇形连续填充三角形串
    glTexCoord2f(0.0f, 0.0f);           //将纹理图(0, 0)映射到圆心
    glVertex3f(0.0f, 0.0f, 0.0f);
    for (i = 0; i <= 360; i += 15)
    {
        float p = i * 3.14 / 180;
        glTexCoord2f(1.0f, 0.0f);       //将纹理图(1, 0)映射到圆周
        glVertex3f(sin(p), cos(p), 0.0f);
    }
    glEnd();
    glTranslatef(0, 0, 1);              //设定高度为1,画上底面
    //top circle
    glBegin(GL_TRIANGLE_FAN);           //扇形连续填充三角形串
    glTexCoord2f(0.0f, 0.0f);           //将纹理图(0, 0)映射到圆心
    glVertex3f(0.0f, 0.0f, 0.0f);
    for (i = 0; i <= 360; i += 15)
    {
        float p = i * 3.14 / 180;
        glTexCoord2f(1.0f, 0.0f);       //将纹理图(1, 0)映射到圆周
        glVertex3f(sin(p), cos(p), 0.0f);
    }
    glEnd();

    xRot += ROT_DELTA;
    if (xRot > 360) xRot = 0;
    yRot += ROT_DELTA;
    if (yRot > 360) yRot = 0;
    zRot += ROT_DELTA;
    if (zRot > 360) zRot = 0;
}

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用QtOpenGL和Assimp实现骨骼动画的示例代码: 首先,需要在项目中包含assimp库和QtOpenGL模块。可以使用以下命令将它们添加到.pro文件中: ``` LIBS += -lassimp QT += opengl ``` 然后,需要编写一个用于渲染模型的OpenGL窗口类。以下是一个简单的示例: ```cpp #include <QOpenGLWidget> #include <QOpenGLFunctions> #include <assimp/Importer.hpp> #include <assimp/scene.h> #include <assimp/postprocess.h> class OpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions { public: OpenGLWidget(QWidget *parent = 0); ~OpenGLWidget(); protected: void initializeGL(); void resizeGL(int w, int h); void paintGL(); private: Assimp::Importer m_importer; const aiScene *m_scene; }; ``` 在初始化函数中,需要加载模型并设置OpenGL状态: ```cpp void OpenGLWidget::initializeGL() { initializeOpenGLFunctions(); // Load model m_scene = m_importer.ReadFile("model.dae", aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_LimitBoneWeights); // Set up OpenGL state glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } ``` 在绘制函数中,需要遍历场景中的所有节点和网格,并计算每个节点的变换矩阵。以下是绘制函数的示例代码: ```cpp void OpenGLWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Set up camera glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, (double)width() / (double)height(), 0.1, 100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); // Draw meshes for (unsigned int i = 0; i < m_scene->mNumMeshes; i++) { const aiMesh *mesh = m_scene->mMeshes[i]; // Set up vertex positions and normals glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, mesh->mVertices); glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, 0, mesh->mNormals); // Set up bone weights and indices if (mesh->HasBones()) { glEnableVertexAttribArray(4); glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(VertexBoneData), (const GLvoid*)offsetof(VertexBoneData, weights)); glEnableVertexAttribArray(5); glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(VertexBoneData), (const GLvoid*)offsetof(VertexBoneData, indices)); // Calculate bone matrices std::vector<aiMatrix4x4> boneMatrices(mesh->mNumBones); for (unsigned int j = 0; j < mesh->mNumBones; j++) { const aiBone *bone = mesh->mBones[j]; aiMatrix4x4 boneMatrix = bone->mOffsetMatrix; const aiNode *node = m_scene->mRootNode->FindNode(bone->mName); while (node && node != mesh->mBones[j]->mNode) { boneMatrix = node->mTransformation * boneMatrix; node = node->mParent; } boneMatrices[j] = boneMatrix; } // Set up bone matrices glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram.programId(), "boneMatrices"), mesh->mNumBones, GL_FALSE, (const GLfloat*)&boneMatrices[0]); } // Draw triangles glDrawElements(GL_TRIANGLES, mesh->mNumFaces * 3, GL_UNSIGNED_INT, mesh->mFaces[0].mIndices); // Disable vertex and normal arrays glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); // Disable bone weights and indices if (mesh->HasBones()) { glDisableVertexAttribArray(4); glDisableVertexAttribArray(5); } } // Swap buffers swapBuffers(); } ``` 在这个示例中,假设模型使用了骨骼动画。因此,需要设置每个网格的顶点数据结构,其中包含每个顶点的骨骼权重和索引。以下是这个数据结构的示例代码: ```cpp struct VertexBoneData { float weights[4]; unsigned int indices[4]; }; ``` 在顶点着色器中,需要将顶点位置和法线变换为相机空间,并使用骨骼权重和索引来计算每个顶点的最终位置。以下是顶点着色器的示例代码: ```glsl #version 330 uniform mat4 projectionMatrix; uniform mat4 modelViewMatrix; uniform mat4 boneMatrices[100]; in vec3 vertexPosition; in vec3 vertexNormal; in vec4 vertexWeights; in ivec4 vertexIndices; out vec3 normal; void main() { mat4 boneMatrix = boneMatrices[vertexIndices.x] * vertexWeights.x; boneMatrix += boneMatrices[vertexIndices.y] * vertexWeights.y; boneMatrix += boneMatrices[vertexIndices.z] * vertexWeights.z; boneMatrix += boneMatrices[vertexIndices.w] * vertexWeights.w; gl_Position = projectionMatrix * modelViewMatrix * boneMatrix * vec4(vertexPosition, 1.0); normal = normalize(mat3(modelViewMatrix * boneMatrix) * vertexNormal); } ``` 在片段着色器中,可以使用法线和光照计算每个像素的颜色。以下是片段着色器的示例代码: ```glsl #version 330 uniform vec3 lightPosition; in vec3 normal; out vec4 fragmentColor; void main() { vec3 ambientColor = vec3(0.2, 0.2, 0.2); vec3 diffuseColor = vec3(1.0, 1.0, 1.0); vec3 specularColor = vec3(1.0, 1.0, 1.0); float shininess = 50.0; vec3 lightDirection = normalize(lightPosition - gl_FragCoord.xyz); vec3 normalDirection = normalize(normal); vec3 reflectionDirection = reflect(-lightDirection, normalDirection); float diffuseFactor = max(dot(lightDirection, normalDirection), 0.0); vec3 diffuseComponent = diffuseColor * diffuseFactor; float specularFactor = pow(max(dot(reflectionDirection, normalize(-gl_FragCoord.xyz)), 0.0), shininess); vec3 specularComponent = specularColor * specularFactor; fragmentColor = vec4(ambientColor + diffuseComponent + specularComponent, 1.0); } ``` 最后,需要在Qt应用程序中创建OpenGL窗口并运行事件循环。以下是一个简单的示例: ```cpp #include <QApplication> #include "OpenGLWidget.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); OpenGLWidget w; w.show(); return a.exec(); } ``` 这就是使用QtOpenGL和Assimp实现骨骼动画的基本步骤和代码示例

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值