当前位置:首页 > 芯闻号 > 充电吧
[导读]在这一课里,将学会如何将纹理映射到立方体的六个面。学习texture map纹理映射(贴图)有很多好处。比方说您想让一颗导弹飞过屏幕。根据前几课的知识,我们最可行的办法可能是很多个多边形来构建导弹的轮

在这一课里,将学会如何将纹理映射到立方体的六个面。

学习texture map纹理映射(贴图)有很多好处。比方说您想让一颗导弹飞过屏幕。根据前几课的知识,我们最可行的办法可能是很多个多边形来构建导弹的轮廓并加上有趣的颜色。使用纹理映射,您可以使用真实的导弹图像并让它飞过屏幕。您觉得哪个更好看?照片还是一大堆三角形和四边形?使用纹理映射的好处还不止是更好看,而且您的程序运行会更快。导弹贴图可能只是一个飞过窗口的四边形。一个由多边形构建而来的导弹却很可能包括成百上千的多边形。很显然,贴图极大的节省了CPU时间。

需要注意的是,用作纹理的图像的宽和高必须是2的n次方;宽度和高度最小必须是64象素;并且出于兼容性的原因,图像的宽度和高度不应超过256象素。
如果您的原始素材的宽度和高度不是64,128,256象素的话,使用图像处理软件重新改变图像的大小。
可以肯定有办法能绕过这些限制,但现在我们只需要用标准的纹理尺寸。

关于纹理映射,更详细的讲解可参考:https://blog.csdn.net/caoshangpa/article/details/80318959

这一课的代码较之前有了较大变化,全部贴出来。

lesson5.h

#ifndef LESSON5_H
#define LESSON5_H

#include#includeclass QPainter;
class QOpenGLContext;
class QOpenGLPaintDevice;

class Lesson5 : public QWindow, QOpenGLFunctions_1_1
{
    Q_OBJECT
public:
    explicit Lesson5(QWindow *parent = 0);
    ~Lesson5();

    virtual void render(QPainter *);
    virtual void render();
    virtual void initialize();

public slots:
    void renderNow();

protected:
    void exposeEvent(QExposeEvent *);
    void resizeEvent(QResizeEvent *);

private:
    void myPerspective( GLdouble fov, GLdouble aspectRatio, GLdouble zNear, GLdouble zFar );
    void loadGLTexture();

private:
    QOpenGLContext *m_context;

    GLfloat		xrot;	// X 旋转量
    GLfloat		yrot;	// Y 旋转量
    GLfloat		zrot;	// Z 旋转量

    GLuint		texture[1];	// 存储一个纹理
};

#endif // LESSON5_H

lesson5.cpp

#include "lesson5.h"

#include#include#include#includeLesson5::Lesson5(QWindow *parent) :
    QWindow(parent)
  , m_context(0)
{
    setSurfaceType(QWindow::OpenGLSurface);
    xrot=45.0f;
    yrot=45.0f;
    zrot=45.0f;
}

Lesson5::~Lesson5()
{
    glDeleteTextures(1, &texture[0]);
}

void Lesson5::render(QPainter *painter)
{
    Q_UNUSED(painter);
}

void Lesson5::myPerspective( GLdouble fov, GLdouble aspectRatio, GLdouble zNear, GLdouble zFar )
{
    // 使用glu库函数,需要添加glu.h头文件
    // gluPerspective(fov, aspectRatio, zNear, zFar);
    GLdouble rFov = fov * 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 );
}

void Lesson5::render()
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glViewport(0,0,(GLint)width(),(GLint)height()); // 重置当前视口
    glMatrixMode(GL_PROJECTION);                    // 选择投影矩阵
    glLoadIdentity();                               // 重置投影矩阵为单位矩阵
    // glu库函数Qt不支持,但是glu库函数是对gl库函数的封装,方便使用。因此我们可以自己
    // 写一个类似gluPerspective的函数myPerspective,用于设置透视。
    //gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
    myPerspective(45.0,(GLfloat)width()/(GLfloat)height(),0.1,100.0);

    glMatrixMode(GL_MODELVIEW);// 选择模型视图矩阵
    glLoadIdentity();          // 重置模型视图矩阵为单位矩阵

    glTranslatef(0.0f,0.0f,-6.0f);  // 移入屏幕6.0
    //下面三行使立方体绕X、Y、Z轴旋转。旋转多少依赖于变量 xrot , yrot 和 zrot 的值。
    glRotatef(xrot,1.0f,0.0f,0.0f); // X轴旋转
    glRotatef(yrot,0.0f,1.0f,0.0f); // Y轴旋转
    glRotatef(zrot,0.0f,0.0f,1.0f); // Z轴旋转
    //下一行代码选择我们使用的纹理。
    //如果您在您的场景中使用多个纹理,您应该使用来 glBindTexture(GL_TEXTURE_2D, texture[ 所使用纹理对应的数字 ]) 选择要绑定的
    //纹理。当您想改变纹理时,应该绑定新的纹理。有一点值得指出的是,您不能在 glBegin() 和 glEnd() 之间绑定纹理,必须在 glBegin()
    //之前或 glEnd() 之后绑定。注意我们在后面是如何使用 glBindTexture 来指定和绑定纹理的。
    glBindTexture(GL_TEXTURE_2D, texture[0]); // 选择纹理
    //为了将纹理正确的映射到四边形上,您必须将纹理的右上角映射到四边形的右上角,纹理的左上角映射到四边形的左上角,
    //纹理的右下角映射到四边形的右下角,纹理的左下角映射到四边形的左下角。
    //如果映射错误的话,图像显示时可能上下颠倒,侧向一边或者什么都不是。
    //glTexCoord2f 的第一个参数是X坐标。 0.0f 是纹理的左侧。 0.5f 是纹理的中点, 1.0f 是纹理的右侧。
    //glTexCoord2f 的第二个参数是Y坐标。 0.0f 是纹理的底部。 0.5f 是纹理的中点, 1.0f 是纹理的顶部。
    //所以纹理的左上坐标是 X:0.0f,Y:1.0f ,四边形的左上顶点是 X: -1.0f,Y:1.0f 。其余三点依此类推。
    //试着玩玩 glTexCoord2f X, Y坐标参数。把 1.0f 改为 0.5f 将只显示纹理的左半部分,把 0.0f 改为 0.5f 将只显示纹理的右半部分。
    glBegin(GL_QUADS);
    // 前面
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	// 纹理和四边形的左下
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	// 纹理和四边形的右下
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	// 纹理和四边形的右上
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	// 纹理和四边形的左上
    // 后面
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	// 纹理和四边形的右下
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	// 纹理和四边形的右上
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	// 纹理和四边形的左上
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	// 纹理和四边形的左下
    // 顶面
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	// 纹理和四边形的左上
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	// 纹理和四边形的左下
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	// 纹理和四边形的右下
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	// 纹理和四边形的右上
    // 底面
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	// 纹理和四边形的右上
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	// 纹理和四边形的左上
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	// 纹理和四边形的左下
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	// 纹理和四边形的右下

    // 右面
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	// 纹理和四边形的右下
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	// 纹理和四边形的右上
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	// 纹理和四边形的左上
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	// 纹理和四边形的左下

    // 左面
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	// 纹理和四边形的左下
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	// 纹理和四边形的右下
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	// 纹理和四边形的右上
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	// 纹理和四边形的左上
    glEnd();
}

void Lesson5::initialize()
{
    loadGLTexture();                      // 加载纹理
    glEnable(GL_TEXTURE_2D);              // 启用纹理映射
    glShadeModel(GL_SMOOTH);              // 启用平滑着色
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 黑色背景
    glClearDepth(1.0f);                   // 设置深度缓存
    glEnable(GL_DEPTH_TEST);              // 启用深度测试
    glDepthFunc(GL_LEQUAL);               // 深度测试类型
    // 接着告诉OpenGL我们希望进行最好的透视修正。这会十分轻微的影响性能。但使得透视图看起来好一点。
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}

void Lesson5::renderNow()
{
    if (!isExposed())
        return;

    bool needsInitialize = false;

    if (!m_context) {
        m_context = new QOpenGLContext(this);
        m_context->setFormat(requestedFormat());
        m_context->create();

        needsInitialize = true;
    }

    m_context->makeCurrent(this);

    if (needsInitialize) {
        initializeOpenGLFunctions();
        initialize();
    }

    render();

    m_context->swapBuffers(this);
}

void Lesson5::loadGLTexture()
{
    // 现在载入图像,并将其转换为纹理。
    QImage image(":/image/NeHe.bmp");
    image = image.convertToFormat(QImage::Format_RGB888);
    image = image.mirrored();
    // 创建纹理
    glGenTextures(1, &texture[0]);
    // 使用来自位图数据生成的典型纹理
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    // 下来我们创建真正的纹理。下面一行告诉OpenGL此纹理是一个2D纹理 ( GL_TEXTURE_2D )。
    // 参数“0”代表图像的详细程度,通常设置为0。参数三是数据的成分数。
    // 因为图像是由红色数据,绿色数据,蓝色数据三种组分组成。 TextureImage[0]->sizeX 是纹理的宽度。
    // 如果您知道宽度,您可以在这里填入,但计算机可以很容易的为您指出此值。
    // TextureImage[0]->sizey 是纹理的高度。参数零是边框的值,一般就是“0”。
    // GL_RGB 告诉OpenGL图像数据由红、绿、蓝三色数据组成。
    // GL_UNSIGNED_BYTE 意味着组成图像的数据是无符号字节类型的。
    // 最后TextureImage[0]->data 告诉OpenGL纹理数据的来源。此例中指向存放在 TextureImage[0] 记录中的数据。
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
                 image.width(), image.height(), 0, GL_RGB, GL_UNSIGNED_BYTE,
                 image.bits());
    // 下面的两行告诉OpenGL在显示图像时,
    // 当它比放大得原始的纹理大 ( GL_TEXTURE_MAG_FILTER )或缩小得比原始得纹理小( GL_TEXTURE_MIN_FILTER )时
    // OpenGL采用的滤波方式。通常这两种情况下我都采用 GL_LINEAR 。
    // 这使得纹理从很远处到离屏幕很近时都平滑显示。使用 GL_LINEAR 需要CPU和显卡做更多的运算。
    // 如果您的机器很慢,您也许应该采用 GL_NEAREST 。过滤的纹理在放大的时候,看起来斑驳的很『译者注:马赛克啦』。
    // 您也可以结合这两种滤波方式。在近处时使用 GL_LINEAR ,远处时 GL_NEAREST 。
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);	// 线形滤波
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);	// 线形滤波
}

void Lesson5::exposeEvent(QExposeEvent *event)
{
    Q_UNUSED(event);

    if (isExposed())
        renderNow();
}

void Lesson5::resizeEvent(QResizeEvent *event)
{
    Q_UNUSED(event);

    if (isExposed())
        renderNow();
}

main.cpp

#include#includeint main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QSurfaceFormat format;
    format.setSamples(16);

    Lesson5 window;
    window.setFormat(format);
    window.resize(640, 480);
    window.show();

    return app.exec();
}

运行效果




本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭