美文网首页
8-2.纹理-金字塔纹理案例

8-2.纹理-金字塔纹理案例

作者: Pufus | 来源:发表于2020-10-19 16:43 被阅读0次
金字塔绘制及纹理填充

金字塔图形坐标解析:

金字塔底部四边形 = 三角形X + 三角形Y


image
  • 各个顶点坐标
    vBackLeft (-1.0,-1.0,-1.0)
    vBackRight (1.0,-1.0,-1.0)
    vFrontLeft (-1.0,-1.0,1.0)
    vFrontRight(1.0,-1.0,1.0)
    vApex (0,1.0,0)
  • 三⻆形X的坐标如下:
    vBackLeft(-1.0,-1.0,-1.0)
    vBackRight(1.0,-1.0,-1.0)
    vFrontRight(1.0,-1.0,1.0)
  • 三⻆形Y的坐标如下:
    vFrontLeft(-1.0,-1.0,1.0)
    vBackLeft(-1.0,-1.0,-1.0)
    vFrontRight(1.0,-1.0,1.0)
  • 三⻆形X的2D纹理坐标如下(第一个0是纹理,后面的表示坐标(s,t)):
    vBackLeft(0,0.0,0.0)
    vBackRight(0,1.0,0.0)
    vFrontRight(0,1.0,1.0)
  • 三⻆形Y的2D纹理坐标如下:
    vFrontLeft(0,0.0,1.0)
    vBackLeft(0,0.0,0.0)
    vFrontRight(0,1.0,1.0)

金字塔实现并填充纹理思维导图

金字塔实现并填充纹理思维导图(图像转载自简书用户CC老师)

1、主函数中设置环境及注册函数

int main(intargc,char* argv[])

{

    gltSetWorkingDirectory(argv[0]);

    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);

    glutInitWindowSize(800, 600);

    glutCreateWindow("Pyramid");

    glutReshapeFunc(ChangeSize);

    glutSpecialFunc(SpecialKeys);

    glutDisplayFunc(RenderScene);

    GLenum err = glewInit();



    if(GLEW_OK!= err) {

        fprintf(stderr,"GLEW Error: %s\n",glewGetErrorString(err));

        return1;

    }

    SetupRC();

    glutMainLoop();

    ShutdownRC();//重要,纹理绑定后需要进行解绑

    return 0;

}

2、定义全局变量

GLShaderManager shaderManager;//着色器程序

GLMatrixStack modelViewMatrix;//模型视图矩阵

GLMatrixStack projectionMatrix;//投影矩阵

GLFrame cameraFrame;//观察者坐标

GLFrame            objectFrame;//对象坐标

GLFrustum viewFrustum;//

GLBatch            pyramidBatch;//金字塔批次类

GLuint              textureID;//纹理变量,一般使用无符号整型

GLGeometryTransform transformPipeline;

M3DMatrix44f shadowMatrix;

3、开始设置环境

void SetupRC()
{

    //1.初始化着色器,设置清屏颜色
    glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
    shaderManager.InitializeStockShaders();

    //2.开启深度测试
    glEnable(GL_DEPTH_TEST);

    //3.分配纹理对象
    // 参数1:纹理对象个数,金字塔的5个面,共6个三角形,但是用的是同一个纹理,所以纹理对象个数为1。
//参数2:纹理对象指针,之前定义过了纹理对象,直接拿下来取地址就行了
    glGenTextures(1, &textureID);

    //4、绑定纹理状态 
   //参数1:纹理状态2D 参数2:纹理对象
    glBindTexture(GL_TEXTURE_2D, textureID);

    //将TGA文件加载为2D纹理。
    //参数1:纹理文件名称
    //参数2&参数3:需要缩小&放大的过滤器
    //参数4:纹理坐标环绕模式
    LoadTGATexture("stone.tga", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, GL_CLAMP_TO_EDGE);

    //5.创造金字塔pyramidBatch
    MakePyramid(pyramidBatch);

    //6.调整观察者位置
    /**相机frame MoveForward(平移)
    参数1:Z,深度(屏幕到图形的Z轴距离)
     */
    cameraFrame.MoveForward(-10);

}

4、渲染场景

步骤一:设置场景
void RenderScene(void)
{
    //1.颜色值&光源位置
    staticGLfloatvLightPos [] = {1.0f,1.0f,0.0f};
    staticGLfloatvWhite [] = {1.0f,1.0f,1.0f,1.0f};

    //2.清理缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    //3.当前模型视图压栈
    modelViewMatrix.PushMatrix();

    //添加照相机矩阵
    M3DMatrix44fmCamera;

    //从camraFrame中获取一个4*4的矩阵
    cameraFrame.GetCameraMatrix(mCamera);

    //矩阵乘以矩阵堆栈顶部矩阵,相乘结果存储到堆栈的顶部 将照相机矩阵 与 当前模型矩阵相乘 压入栈顶
    modelViewMatrix.MultMatrix(mCamera);

    //创建mObjectFrame矩阵
    M3DMatrix44fmObjectFrame;

    //从objectFrame中获取矩阵,objectFrame保存的是特殊键位的变换矩阵
    objectFrame.GetMatrix(mObjectFrame);

    //矩阵乘以矩阵堆栈顶部矩阵,相乘结果存储到堆栈的顶部 将世界变换矩阵 与 当前模型矩阵相乘 压入栈顶
    modelViewMatrix.MultMatrix(mObjectFrame);

    //4.绑定纹理,因为我们的项目中只有一个纹理。如果有多个纹理。绑定纹理很重要
    glBindTexture(GL_TEXTURE_2D, textureID);

    /*5.点光源着色器
     参数1:GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF(着色器标签)
     参数2:模型视图矩阵
     参数3:投影矩阵
     参数4:视点坐标系中的光源位置
     参数5:基本漫反射颜色
     参数6:图形颜色(用纹理就不需要设置颜色。设置为0)
     */
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                 transformPipeline.GetModelViewMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightPos, vWhite,0);

    //pyramidBatch 绘制
    pyramidBatch.Draw();

    //模型视图出栈,恢复矩阵(push一次就要pop一次,push和pop成对存在)
    modelViewMatrix.PopMatrix();

    //6.交换缓存区
    glutSwapBuffers();
}
步骤二:绘制金字塔
void MakePyramid(GLBatch &pyramidBatch)
{
    /*1、通过pyramidBatch组建三角形批次
      参数1:类型
      参数2:顶点数
      参数3:这个批次中将会应用1个纹理
      注意:如果不写这个参数,默认为0。
     */
    pyramidBatch.Begin(GL_TRIANGLES,18,1);

    /***前情导入
     1)设置法线
     void Normal3f(GLfloat x, GLfloat y, GLfloat z);
     Normal3f:添加一个表面法线(法线坐标 与 Vertex顶点坐标中的Y轴一致)
     表面法线是有方向的向量,代表表面或者顶点面对的方向(相反的方向)。在多数的关照模式下是必须使用。后面的课程会详细来讲法线的应用
     pyramidBatch.Normal3f(X,Y,Z);

     2)设置纹理坐标
     void MultiTexCoord2f(GLuint texture, GLclampf s, GLclampf t);
     参数1:texture,纹理层次,对于使用存储着色器来进行渲染,设置为0
     参数2:s:对应顶点坐标中的x坐标
     参数3:t:对应顶点坐标中的y
     (s,t,r,q对应顶点坐标的x,y,z,w)
     pyramidBatch.MultiTexCoord2f(0,s,t);

     3)void Vertex3f(GLfloat x, GLfloat y, GLfloat z);
      void Vertex3fv(M3DVector3f vVertex);
     向三角形批次类添加顶点数据(x,y,z);
      pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);

     4)获取从三点找到一个法线坐标(三点确定一个面)
     void m3dFindNormal(result,point1, point2,point3);
     参数1:结果
     参数2-4:3个顶点数据
     */

    //塔顶
    M3DVector3fvApex = {0.0f,1.0f,0.0f};
    M3DVector3fvFrontLeft = { -1.0f, -1.0f,1.0f};
    M3DVector3fvFrontRight = {1.0f, -1.0f,1.0f};
    M3DVector3fvBackLeft = { -1.0f,  -1.0f, -1.0f};
    M3DVector3fvBackRight = {1.0f,  -1.0f, -1.0f};
    M3DVector3f n;

    //金字塔底部
    //底部的四边形 = 三角形X + 三角形Y
    //三角形X = (vBackLeft,vBackRight,vFrontRight)
    //1.找到三角形X 法线
    m3dFindNormal(n, vBackLeft, vBackRight, vFrontRight);

    //vBackLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,0.0f,0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);

    //vBackRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,1.0f,0.0f);
    pyramidBatch.Vertex3fv(vBackRight);

    //vFrontRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,1.0f,1.0f);
    pyramidBatch.Vertex3fv(vFrontRight);

    //三角形Y =(vFrontLeft,vBackLeft,vFrontRight)
    //1.找到三角形X 法线
    m3dFindNormal(n, vFrontLeft, vBackLeft, vFrontRight);

    //vFrontLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,0.0f,1.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);

    //vBackLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,0.0f,0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);

    //vFrontRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,1.0f,1.0f);
    pyramidBatch.Vertex3fv(vFrontRight);

    // 金字塔前面
    //三角形:(Apex,vFrontLeft,vFrontRight)
    m3dFindNormal(n, vApex, vFrontLeft, vFrontRight);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,0.5f,1.0f);
    pyramidBatch.Vertex3fv(vApex);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,0.0f,0.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,1.0f,0.0f);
    pyramidBatch.Vertex3fv(vFrontRight);

    //金字塔左边
    //三角形:(vApex, vBackLeft, vFrontLeft)
    m3dFindNormal(n, vApex, vBackLeft, vFrontLeft);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,0.5f,1.0f);
    pyramidBatch.Vertex3fv(vApex);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,1.0f,0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,0.0f,0.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);

    //金字塔右边
    //三角形:(vApex, vFrontRight, vBackRight)
    m3dFindNormal(n, vApex, vFrontRight, vBackRight);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,0.5f,1.0f);
    pyramidBatch.Vertex3fv(vApex);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,1.0f,0.0f);
    pyramidBatch.Vertex3fv(vFrontRight);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,0.0f,0.0f);
    pyramidBatch.Vertex3fv(vBackRight);

    //金字塔后边
    //三角形:(vApex, vBackRight, vBackLeft)
    m3dFindNormal(n, vApex, vBackRight, vBackLeft);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,0.5f,1.0f);
    pyramidBatch.Vertex3fv(vApex);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,0.0f,0.0f);
    pyramidBatch.Vertex3fv(vBackRight);
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0,1.0f,0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);

    //结束批次设置

    pyramidBatch.End();

}
步骤三:自定义函数 ,从TGA文件加载2D纹理。
bool LoadTGATexture(const char *szFileName,GLenum minFilter,GLenum magFilter,GLenum wrapMode)
{
    GLbyte*pBits;
    intnWidth, nHeight, nComponents;
    GLenumeFormat;

    //1、读纹理位,读取像素
    //参数1:纹理文件名称
    //参数2:文件宽度地址
    //参数3:文件高度地址
    //参数4:文件组件地址
    //参数5:文件格式地址
    //返回值:pBits,指向图像数据的指针
    pBits =gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);

    if(pBits ==NULL)
        return false;

    //2、设置纹理参数
    //参数1:纹理维度
    //参数2:为S/T坐标设置模式
    //参数3:wrapMode,环绕模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);

    //参数1:纹理维度
    //参数2:线性过滤
    //参数3:wrapMode,环绕模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);

    //3.载入纹理
    //参数1:纹理维度
    //参数2:mip贴图层次
    //参数3:纹理单元存储的颜色成分(从读取像素图是获得)
    //参数4:加载纹理宽
    //参数5:加载纹理高
    //参数6:加载纹理的深度
    //参数7:像素数据的数据类型(GL_UNSIGNED_BYTE,每个颜色分量都是一个8位无符号整数)
    //参数8:指向纹理图像数据的指针

    glTexImage2D(GL_TEXTURE_2D,0, nComponents, nWidth, nHeight,0,
                 eFormat,GL_UNSIGNED_BYTE, pBits);
    //使用完毕释放pBits
    free(pBits);

    //4.加载Mip,纹理生成所有的Mip层
    //参数:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D

    glGenerateMipmap(GL_TEXTURE_2D);

    return true;
}

5、窗口改变监听

void ChangeSize(int w,int h)
{
    //1.设置视口
    glViewport(0,0, w, h);
    //2.创建投影矩阵
    viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
    //viewFrustum.GetProjectionMatrix()  获取viewFrustum投影矩阵
    //并将其加载到投影矩阵堆栈上
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //3.设置变换管道以使用两个矩阵堆栈(变换矩阵modelViewMatrix ,投影矩阵projectionMatrix)
    //初始化GLGeometryTransform 的实例transformPipeline.通过将它的内部指针设置为模型视图矩阵堆栈 和 投影矩阵堆栈实例,来完成初始化
    //当然这个操作也可以在SetupRC 函数中完成,但是在窗口大小改变时或者窗口创建时设置它们并没有坏处。而且这样可以一次性完成矩阵和管线的设置。
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

6、特殊键位操作

void SpecialKeys(int key,int x,int y)

{

    if(key ==GLUT_KEY_UP)

        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);



    if(key == GLUT_KEY_DOWN)

        objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);



    if(key == GLUT_KEY_LEFT)

        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);



    if(key == GLUT_KEY_RIGHT)

        objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);

    glutPostRedisplay();//视口改变,更新窗口

}

7、最后需要清除绑定的纹理

void ShutdownRC(void)
{
    glDeleteTextures(1, &textureID);
}

运行代码,得到带纹理的金字塔(通过上下左右键操作可选择金字塔)


最终效果图
最终效果图

相关文章

  • 8-2.纹理-金字塔纹理案例

    金字塔图形坐标解析: 金字塔底部四边形 = 三角形X + 三角形Y 各个顶点坐标vBackLeft (-1.0,-...

  • 案例分析3:纹理金字塔

    案例效果如下 对应代码地址纹理金字塔。 常见纹理使用流程

  • OpenGL案例02

    绘制一个带纹理的金字塔模型,通过本案例来加深对纹理的理解,案例执行结果如下效果图: 搭建框架 SetupRC函数 ...

  • 八、OpenGL - 纹理金字塔

    一 初始化数据 生成纹理对象 绑定纹理 读取纹理文件 设置纹理参数 载入纹理 创建金字塔并设置纹理顶点映射 二 渲...

  • OpenGL ES案例- 实现颜色和纹理的混合

    这个案例是在上个案例的基础上,在金字塔上贴上纹理,并实现纹理和颜色的混合。最终效果: 一、使用GLSL实现 结合我...

  • OpenGL纹理使用

    我们先来看个“金字塔”案例,下文将按照此案例进行讲解。 一、加载2D纹理 我们先来看一下如何加载2D纹理 该函数为...

  • 案例07:纹理金字塔

    OpenGL + OpenGL ES +Metal 系列文章汇总 本次案例的目的在于理解纹理的使用 案例整体效果图...

  • 案例分析4:纹理隧道

    本案例主要目的多个纹理如何使用,加深对纹理的使用的理解。案例效果如下 对应代码地址纹理隧道。 下面接着说说隧道的绘...

  • 九、OpenGL - 隧道案例解析

    初始化 在初始化函数生成纹理对象,过程和金字塔类似,纹理的显示过程基本一致,注意纹理坐标和顶点坐标的映射关系 窗体...

  • OpenGL纹理坐标&&隧道案例(二)

    一.隧道案例效果 二.纹理坐标 纹理坐标主要是把图形映射到OpenGL中去,图形中每个顶点关联到对应的纹理坐标下,...

网友评论

      本文标题:8-2.纹理-金字塔纹理案例

      本文链接:https://www.haomeiwen.com/subject/gdruuktx.html