画圆环体的方法为,用一个小圆绕y轴一定半径转一周,这样就能形成一个圆环,其生成顶点的公式如下
其纹理坐标可以使用上一节圆柱的方法,将圆环体剪开,再水平剪开,就能还原为一个矩形。所以纹理坐标计算方式为,当大圆周每转过一定角度时,用这个角度除以360就能得到纹理x坐标,将小圆周角度除以360就能得到纹理y坐标。
我实现的圆环体效果如下
其渲染器实现如下
#ifndef TORUSRENDER_H
#define TORUSRENDER_H
#include
#include
#include
#include
#define PI 3.14159265f
class TorusRender
{
public:
TorusRender() = default;
void initsize(float rBig,float rSmall,int nCol,int nRow,QImage &img);
void initsize(float rBig,float rSmall,int nCol,int nRow);
void render(QOpenGLExtraFunctions *f,QMatrix4x4 &pMatrix,QMatrix4x4 &vMatrix,QMatrix4x4 &mMatrix);
private:
QOpenGLShaderProgram program_;
QOpenGLBuffer vbo_;
QVector vertPoints_,textPoints_;
QOpenGLTexture *texture_{nullptr};
bool userTexture_ = false;
};
#endif // TORUSRENDER_H
#include
#include "torusrender.h"
void TorusRender::initsize(float rBig, float rSmall, int nCol, int nRow, QImage &img)
{
userTexture_ = true;
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"vsrc.vert");
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"fsrc.frag");
program_.link();
float angdegColSpan = 360.0/nCol;
float angdegRowSpan = 360.0/nRow;
float A = (rBig - rSmall)/2;
float D = rSmall + A;
QVector originVertPoints,originTextPoints;
for(float angdegCol=0;::ceil(angdegCol)<360+angdegColSpan;angdegCol+=angdegColSpan) {//对小圆按照等角度间距循环
double a=angdegCol * PI / 180;//当前小圆弧度
float t=angdegCol/360;//当前角度对应的t坐标
for(float angdegRow=0;::ceil(angdegRow)<360+angdegRowSpan;angdegRow+=angdegRowSpan)
{//对大圆按照等角度间距循环
double u=angdegRow * PI / 180;//当前大圆弧度
float y=(float) (A*::cos(a));//按照公式计算当前顶点
float x=(float) ((D+A*::sin(a))*::sin(u)); //的X、Y、Z坐标
float z=(float) ((D+A*::sin(a))*::cos(u));
//将计算出来的X、Y、Z坐标放入原始顶点列表
originVertPoints << x << y << z;
float s=angdegRow/360;//当前角度对应的s坐标
originTextPoints << s << t;
}
}
for(int i=0;i vboVec;
vboVec << vertPoints_ << textPoints_;
vbo_.create();
vbo_.bind();
vbo_.allocate(vboVec.data(),vboVec.count() * sizeof(GLfloat));
texture_ = new QOpenGLTexture(img);
texture_->setWrapMode(QOpenGLTexture::ClampToEdge);
texture_->setMinMagFilters(QOpenGLTexture::NearestMipMapNearest,QOpenGLTexture::LinearMipMapNearest);
}
void TorusRender::initsize(float rBig, float rSmall, int nCol, int nRow)
{
userTexture_ = false;
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"lvsrc.vert");
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"lfsrc.frag");
program_.link();
float angdegColSpan = 360.0/nCol;
float angdegRowSpan = 360.0/nRow;
float A = (rBig - rSmall)/2;
float D = rSmall + A;
QVector originVertPoints,originColorPoints;
for(float angdegCol=0;::ceil(angdegCol)<360+angdegColSpan;angdegCol+=angdegColSpan) {//对小圆按照等角度间距循环
double a=angdegCol * PI / 180;//当前小圆弧度
for(float angdegRow=0;::ceil(angdegRow)<360+angdegRowSpan;angdegRow+=angdegRowSpan)
{//对大圆按照等角度间距循环
double u=angdegRow * PI / 180;//当前大圆弧度
float y=(float) (A*::cos(a));//按照公式计算当前顶点
float x=(float) ((D+A*::sin(a))*::sin(u)); //的X、Y、Z坐标
float z=(float) ((D+A*::sin(a))*::cos(u));
//将计算出来的X、Y、Z坐标放入原始顶点列表
originVertPoints << x << y << z;
originColorPoints << 1.0 << 1.0 << 1.0 << 1.0;
}
}
for(int i=0;i vboVec;
vboVec << vertPoints_ << textPoints_;
vbo_.create();
vbo_.bind();
vbo_.allocate(vboVec.data(),vboVec.count() * sizeof(GLfloat));
}
void TorusRender::render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix, QMatrix4x4 &vMatrix, QMatrix4x4 &mMatrix)
{
f->glEnable(GL_DEPTH_TEST);
f->glEnable(GL_CULL_FACE);
program_.bind();
vbo_.bind();
if(userTexture_){
f->glActiveTexture(GL_TEXTURE0);
program_.setUniformValue("uPMatrix",pMatrix);
program_.setUniformValue("uVMatrix",vMatrix);
program_.setUniformValue("uMMatrix",mMatrix);
program_.setUniformValue("sTexture",0);
program_.enableAttributeArray(0);
program_.enableAttributeArray(1);
program_.setAttributeBuffer(0,GL_FLOAT,0,3,3*sizeof(GLfloat));
program_.setAttributeBuffer(1,GL_FLOAT,vertPoints_.count() * sizeof(GLfloat),2,2*sizeof(GLfloat));
texture_->bind();
f->glDrawArrays(GL_TRIANGLES,0,vertPoints_.count() / 3);
program_.disableAttributeArray(0);
program_.disableAttributeArray(1);
texture_->release();
}else{
program_.setUniformValue("uPMatrix",pMatrix);
program_.setUniformValue("uVMatrix",vMatrix);
program_.setUniformValue("uMMatrix",mMatrix);
program_.enableAttributeArray(0);
program_.enableAttributeArray(1);
program_.setAttributeBuffer(0,GL_FLOAT,0,3,3*sizeof(GLfloat));
program_.setAttributeBuffer(1,GL_FLOAT,vertPoints_.count() * sizeof(GLfloat),4,4*sizeof(GLfloat));
f->glDrawArrays(GL_LINE_STRIP,0,vertPoints_.count() / 3);
program_.disableAttributeArray(0);
program_.disableAttributeArray(1);
}
vbo_.release();
program_.release();
f->glDisable(GL_CULL_FACE);
f->glDisable(GL_DEPTH_TEST);
}
shader实现如下,带纹理图片
#version 330
uniform mat4 uPMatrix,uVMatrix,uMMatrix;
layout (location = 0)in vec3 aPosition;
layout (location = 1)in vec2 aTexture;
smooth out vec2 vTexture;
void main(void)
{
gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aPosition,1);
vTexture = aTexture;
}
#version 330
uniform sampler2D sTexture;
in vec2 vTexture;
out vec4 fragColor;
void main(void)
{
fragColor = texture2D(sTexture,vTexture);
}
shader不带纹理图片
#version 330
uniform mat4 uPMatrix,uVMatrix,uMMatrix;
layout (location = 0)in vec3 aPosition;
layout (location = 1)in vec4 aColor;
smooth out vec4 vColor;
void main(void)
{
gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aPosition,1);
vColor = aColor;
}
#version 330
in vec4 vColor;
out vec4 fragColor;
void main(void)
{
fragColor = vColor;
}
其实现方法和前面一样
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include "torusrender.h"
class Widget : public QOpenGLWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
protected:
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
private:
QTimer tm_;
TorusRender render_;
QMatrix4x4 pMatrix_;
QVector3D camera_;
qreal angleX_ = 0,angleY_ = 0,angleZ_ = 0;
private slots:
void slotTimeout();
};
#endif // WIDGET_H
#include "widget.h"
Widget::Widget(QWidget *parent)
: QOpenGLWidget(parent)
{
connect(&tm_,SIGNAL(timeout()),this,SLOT(slotTimeout()));
tm_.start(60);
}
Widget::~Widget()
{
}
void Widget::initializeGL()
{
// render_.initsize(0.9,0.7,13,30,QImage("texture.png"));
render_.initsize(0.9,0.7,13,30);
camera_.setX(0);
camera_.setY(0);
camera_.setZ(3);
}
void Widget::resizeGL(int w, int h)
{
pMatrix_.setToIdentity();
pMatrix_.perspective(45,float(w)/h,0.01f,100.0f);
}
void Widget::paintGL()
{
QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
f->glClearColor(0.0f,0.0f,0.0f,0.0f);
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 vMatrix;
vMatrix.lookAt(camera_,QVector3D(0.0,0.0,0.0),QVector3D(0.0,1.0,0.0));
QMatrix4x4 mMatrix;
mMatrix.rotate(angleX_,1,0,0);
mMatrix.rotate(angleY_,0,1,0);
mMatrix.rotate(angleZ_,0,0,1);
render_.render(f,pMatrix_,vMatrix,mMatrix);
}
void Widget::slotTimeout()
{
angleX_ += 5;
angleY_ += 5;
angleZ_ += 5;
update();
}
到此结束。