概要
上一节,我们已经实现了立体图形每个面填充颜色,这样就显得很单调, 而如果用图片替换这种单调的颜色,这样就会让立体图形显得更为深动。
效果图展示
以y轴为中心旋转图1
以y轴为中心旋转图2
以x轴为中心旋转图1
以x轴为中心旋转图2
以x轴为中心旋转图1
部分代码
#include "openglwidget.h"
OpenglWidget::OpenglWidget(QWidget* parent)
:QGLWidget(parent),
m_rotateTriangle(0),
m_rotateRectangle(0),
m_x(0),
m_y(0),
m_z(0)
{
initWidget();
}
void OpenglWidget::initializeGL()
{
loadGLTextures();
glEnable( GL_TEXTURE_2D );
glShadeModel( GL_SMOOTH );
glClearColor( 0.0, 0.0, 0.0, 0.5 );
glClearDepth( 1.0 );
glEnable( GL_DEPTH_TEST );
glDepthFunc( GL_LEQUAL );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
}
void OpenglWidget::initWidget()
{
setGeometry( 400, 200, 640, 480 );
setWindowTitle(tr("opengl demo"));
}
void OpenglWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef( -1.5, 0.0, -6.0 );
glRotatef( m_x, 1.0, 0.0, 0.0 );
glRotatef( m_y, 0.0, 1.0, 0.0 );
glRotatef( m_z, 0.0, 0.0, 1.0 );
glBindTexture( GL_TEXTURE_2D, textur[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();
glLoadIdentity();
glTranslatef( 1.5, 0.0, -6.0 );
glRotatef( m_x, 1.0, 0.0, 0.0 );
glRotatef( m_y, 0.0, 1.0, 0.0 );
glRotatef( m_z, 0.0, 0.0, 1.0 );
glBegin(GL_TRIANGLES);
//三棱柱四面贴图
glTexCoord2f( 1, 1 ); glVertex3f( 0, 1, 0 );
glTexCoord2f( 0, 0 ); glVertex3f( 1, -1, 1 );
glTexCoord2f( 1, 0 ); glVertex3f( -1, -1, 1 );
glTexCoord2f( 1, 1 ); glVertex3f( 0, 1, 0 );
glTexCoord2f( 0, 0 ); glVertex3f( -1.0, -1.0, 1.0 );
glTexCoord2f( 1, 0 ); glVertex3f( -1.0, -1.0, -1.0 );
glTexCoord2f( 1, 1 ); glVertex3f( 0, 1, 0 );
glTexCoord2f( 0, 0 ); glVertex3f( -1.0, -1.0, -1.0 );
glTexCoord2f( 1, 0 ); glVertex3f( 1.0, -1.0, -1.0 );
glTexCoord2f( 1, 1 ); glVertex3f( 0, 1, 0 );
glTexCoord2f( 0, 0 ); glVertex3f( 1.0, -1.0, -1.0 );
glTexCoord2f( 1, 0 ); glVertex3f( 1.0, -1.0, 1.0 );
//三棱柱底面贴图
glTexCoord2f( 0, 0 ); glVertex3f( -1.0, -1.0, -1.0 );
glTexCoord2f( 1, 0 ); glVertex3f( 1.0, -1.0, -1.0 );
glTexCoord2f( 1, 1 ); glVertex3f( 1.0, -1.0, 1.0 );
glTexCoord2f( 1, 0 ); glVertex3f( 1.0, -1.0, -1.0 );
glTexCoord2f( 1, 1 ); glVertex3f( 1.0, -1.0, 1.0 );
glTexCoord2f( 0, 1 ); glVertex3f( -1.0, -1.0, 1.0 );
glTexCoord2f( 1, 1 ); glVertex3f( 1.0, -1.0, 1.0 );
glTexCoord2f( 0, 1 ); glVertex3f( -1.0, -1.0, 1.0 );
glTexCoord2f( 0, 0 ); glVertex3f( -1.0, -1.0, -1.0 );
glEnd();
m_x += 20;
m_y += 0;
m_z += 0;
}
void OpenglWidget::resizeGL(int width, int height)
{
if(0 == height) {
height = 1;
}
glViewport(0, 0, (GLint)width, (GLint)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// gluPerspective(45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0);
GLdouble aspectRatio = (GLfloat)width/(GLfloat)height;
GLdouble zNear = 0.1;
GLdouble zFar = 100.0;
GLdouble rFov = 45.0 * 3.14159265 / 180.0;
glFrustum( -zNear * tan( rFov / 2.0 ) * aspectRatio,
zNear * tan( rFov / 2.0 ) * aspectRatio,
-zNear * tan( rFov / 2.0 ),
zNear * tan( rFov / 2.0 ),
zNear, zFar );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void OpenglWidget::loadGLTextures()
{
QImage tex;
QImage buf;
if ( !buf.load(":/images/dog.png"))
{
qWarning( "load image failed!" );
QImage dummy( 128, 128, QImage::Format_RGB32 );
dummy.fill( Qt::red);
buf = dummy;
}
tex = QGLWidget::convertToGLFormat( buf );
glGenTextures( 1, &textur[0] );
glBindTexture( GL_TEXTURE_2D, textur[0] );
glTexImage2D( GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, tex.bits() );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
}
主要内容解析
1.相对于立体图形的直接绘图即单一的色彩, 添加了的代码:
添加了用于把图片保存在缓存中的函数
void OpenglWidget::loadGLTextures()
{
QImage tex;
QImage buf;
if ( !buf.load(":/images/dog.png"))
{
qWarning( "load image failed!" );
QImage dummy( 128, 128, QImage::Format_RGB32 );
dummy.fill( Qt::red);
buf = dummy;
}
tex = QGLWidget::convertToGLFormat( buf );
glGenTextures( 1, &textur[0] );
glBindTexture( GL_TEXTURE_2D, textur[0] );
glTexImage2D( GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, tex.bits() );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
}
这里值得一提的是, buf.load(“:/images/dog.png”) 这里,图片load在有些电脑上,竟然不成功,目前也不知道是啥原因。不知道是跟QT版本有关,还是电脑硬件有关。
添加了代码
void OpenglWidget::initializeGL()
{
loadGLTextures();
glEnable( GL_TEXTURE_2D );
glEnable( GL_TEXTURE_2D );这个用于启用纹理, 不然,所显示的全为白色。
convertToGLFormat 这个函数是一个图形转换函数, 也是一个静态函数。转换后的内容,在后面获得纹理时用得上。
glGenTextures( 1, &texture[0] ); 这里第几张图片纹理的定义。
glBindTexture( GL_TEXTURE_2D, texture[0] ); 进行纹理绑定
glTexImage2D( GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, tex.bits() );
这里是纹理的创建。
2.立体图形贴图坐标的计算和转换。
这里有两个接口函数:
glTexCoord2f( x, y );
glVertex3f( x, y, z );
glTexCoord2f这个用于表示原图片的坐标,这样更容易理解,就是以 在x,y 轴的平面里面, (0,0)表示图片的左下角, (0,1) 表示左上角, (1,1)表示右上角, (1,0)表示右下角。
而对应的glVertex3f则对应为 (-1, -1) , (-1, 1) , (1, 1), (1, -1)
我们怎么来理解这种对应关系呢??
- 需要贴图的坐标必须一一对应,就是我们如果顺时针写, 对应的坐都要顺时针,如果逆时针写,对应的坐标都要逆时针,一一对应。
2.我们的贴图是一张图片,所以它一定是一个平面。 所以坐标从(0,0)开始,这个容易使用。而我们需要贴图的立体图形,虽然每个面是平面图形,但它在坐标系中,始终以立体图形的中心为坐标原点,所以,它是一个三维坐标,三维坐标与二维的对应,就只有以相同的平面顶点旋转顺序来对应了。