acetmac 发表于 2022-9-27 12:09:02

OpenGL学习笔记(十二)学习OpenGL超级宝典(第五版)

本文为学习OpenGL的学习笔记,如有书写和理解错误还请大佬扶正;
为后续学习资料与版本特性更好的支持,选择参考<OpenGL超级宝典>来继续学习OpenGL;
配置环境参考:
文章末尾有相关学习资料下载;
效果预览:


代码参考(书籍第六章LitTexture代码,代码中使用的图片可以在文章末尾源码参考中下载得到):
#include <glew/glew.h>                           //GLEW库引入(一定要在GLUT引入之前引入,否则会编译错误),如果要引入其他OpenGL头文件,必须要注意将这个头文件放在前面

#include <gltools/GLTools.h>
#include <gltools/GLShaderManager.h>         
#include <gltools/GLMatrixStack.h>            
#include <gltools/GLFrame.h>               
#include <gltools/GLFrustum.h>            
#include <gltools/GLBatch.h>            
#include <gltools/GLGeometryTransform.h>
#include <gltools/StopWatch.h>         
#include <freeglut/freeglut.h>

#include <math.h>                     
#include <iostream>
using namespace std;

//GTools封装的类
GLFrame             viewFrame;      //模型视图矩阵         
GLFrustum         viewFrustum;    //投影矩阵   
GLTriangleBatch   sphereBatch;    //顶点批次   
GLMatrixStack       modelViewMatrix;   //模型视图矩阵堆栈
GLMatrixStack       projectionMatrix;//投影矩阵堆栈   
GLGeometryTransform transformPipeline;//矩阵管理器

GLShaderManager shaderManager;   //材质管理器

//声明着色器 与变量
GLuint       diffuseLightShader;          // 灯光材质ID
GLint    locAmbient;                 //环境光颜色
GLint       locDiffuse;                // 默认灯光颜色
GLint       locLight;             // 灯光位置
GLint    locSpecular;         //高光颜色
GLint       locMVP;             // 模型视图投影矩阵
GLint       locMV;                  // 模型视图矩阵
GLint       locNM;            //法线矩阵
GLint   locTexture;       //着色器里贴图地址
GLuinttexture;         //为贴图创建ID



// 导入TGA图片 并初始化相关设置
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
        GLbyte *pBits;   //文件指针
        int nWidth, nHeight, nComponents;   //宽度高度格式
        GLenum eFormat;

        // 读取贴图数据
        pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
        if (pBits == NULL)
                return false;
      //纹理环绕   
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
      //纹理过滤
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);

        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
      //载入
        glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
                eFormat, GL_UNSIGNED_BYTE, pBits);
      //释放数据
        free(pBits);

        if (minFilter == GL_LINEAR_MIPMAP_LINEAR ||
                minFilter == GL_LINEAR_MIPMAP_NEAREST ||
                minFilter == GL_NEAREST_MIPMAP_LINEAR ||
                minFilter == GL_NEAREST_MIPMAP_NEAREST)
                glGenerateMipmap(GL_TEXTURE_2D);

        return true;
}



void ChangeSize(int w, int h)
{
        // 高度不为0
        if (h == 0)
                h = 1;

        // 设置渲染窗口的大小为窗口大小
        glViewport(0, 0, w, h);
        //设置投影矩阵FOV 35近截面1.0远截面距离100
        viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 100.0f);

        //创建投影矩阵,并将它载入到投影矩阵堆栈中
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
        //设置管线以使用两个矩阵堆栈   
        transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

void SetupRC()
{
        glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

        glEnable(GL_DEPTH_TEST);    //开启深度测试
        glEnable(GL_CULL_FACE);   //开启背面剔除
        //初始化 GLTOOLs 里的储存着色器初始化着色器对象
        shaderManager.InitializeStockShaders();
        viewFrame.MoveForward(4.0f);   //向后移动模型 模拟摄像机   

        gltMakeSphere(sphereBatch, 1.0f, 26, 13);   //创建一个球体将顶点存在sphereBatch中

        //指定着色器路径,以及顶点属性个数和ID
        diffuseLightShader = shaderManager.LoadShaderPairWithAttributes("SimpleShaderTest01.vs", "SimpleShaderTest01.fs", 3, GLT_ATTRIBUTE_VERTEX, "vVertex",
                GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexture0");

        //获取材质里的变量ID 地址
        locAmbient = glGetUniformLocation(diffuseLightShader, "ambientColor");
        locDiffuse = glGetUniformLocation(diffuseLightShader, "diffuseColor");
        locSpecular = glGetUniformLocation(diffuseLightShader, "specularColor");
        locLight = glGetUniformLocation(diffuseLightShader, "vLightPosition");
        locMVP = glGetUniformLocation(diffuseLightShader, "mvpMatrix");
        locMV = glGetUniformLocation(diffuseLightShader, "mvMatrix");
        locNM = glGetUniformLocation(diffuseLightShader, "normalMatrix");
        locTexture = glGetUniformLocation(diffuseLightShader, "colorMap");

        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);
        LoadTGATexture("CoolTexture.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);

}

//清除材质信息
void ShutdownRC()
{
        glDeleteProgram(diffuseLightShader);
        glDeleteTextures(1, &texture);

}

void RenderScene(void)
{
        static CStopWatch rotTimer;

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);


        modelViewMatrix.PushMatrix(viewFrame);
        modelViewMatrix.Rotate(rotTimer.GetElapsedSeconds() * 10.0f, 0.0f, 1.0f, 0.0f);

        GLfloat vEyeLight[] = { -100.0f, 100.0f, 100.0f };
        GLfloat vAmbientColor[] = { 0.1f, 0.1f, 0.1f, 1.0f };
        GLfloat vDiffuseColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
        GLfloat vSpecularColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };

        //使用材质 同时为材质变量 赋值
        glBindTexture(GL_TEXTURE_2D, texture);
        glUseProgram(diffuseLightShader);
        glUniform4fv(locAmbient, 1, vAmbientColor);
        glUniform4fv(locDiffuse, 1, vDiffuseColor);
        glUniform4fv(locSpecular, 1, vSpecularColor);
        glUniform3fv(locLight, 1, vEyeLight);
        glUniformMatrix4fv(locMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
        glUniformMatrix4fv(locMV, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());
        glUniformMatrix3fv(locNM, 1, GL_FALSE, transformPipeline.GetNormalMatrix());
        glUniform1i(locTexture, 0);
        sphereBatch.Draw();
        modelViewMatrix.PopMatrix();

        //双缓冲
        glutSwapBuffers();
        glutPostRedisplay();
}

int main(int argc, char*argv[])
{
        gltSetWorkingDirectory(argv);
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
        glutInitWindowSize(1024, 720);
        glutCreateWindow("Render");
        glutReshapeFunc(ChangeSize);
        glutDisplayFunc(RenderScene);

        //检测初始化过程是否有问题
        GLenum err = glewInit();
        if (GLEW_OK != err)
        {
                cout << "Error: '%s'\n" << glewGetErrorString(err) << endl;
                return 1;
        }

        //初始化渲染环境 预加载纹理 建立几何图形 渲染器等
        SetupRC();
        glutMainLoop();
        ShutdownRC();
        return 0;

}顶点着色器代码参考 SimpleShaderTest01.vs:
#version 330   //声明版本

// 输入顶点位置 和 法线 属性
in vec4 vVertex;
in vec3 vNormal;
in vec4 vTexture0;

// 声明 着色器变量
uniform vec3 vLightPosition; //灯光位置
uniform mat4 mvpMatrix; //模型视图透视矩阵
uniform mat4 mvMatrix; //模型视图矩阵   
uniform mat3 normalMatrix; //法线矩阵

// 输出灯光方向 与法线向量
smooth out vec3 vVaryingLightDir;
smooth out vec3 vVaryingNormal;
smooth out vec2 vTexCoords;

void main(void)
{
    // 获取表面法线的视觉空间下坐标
    vVaryingNormal = normalMatrix * vNormal;

    // 获取顶点位置在视觉空间下的坐标
    vec4 vPosition4 = mvMatrix * vVertex;
    vec3 vPosition3 = vPosition4.xyz / vPosition4.w;

    // 获取灯光方向
    vVaryingLightDir = normalize(vLightPosition - vPosition3);

    vTexCoords = vTexture0.st;

    // 坐标转换到裁剪坐标系下
    gl_Position = mvpMatrix * vVertex;
}片段着色器代码参考 SimpleShaderTest01.fs:
#version 330      //声明版本

out vec4 vFragColor;

uniform vec4 ambientColor; //环境光颜色
uniform vec4 diffuseColor; //默认灯光颜色
uniform vec4 specularColor; //高光颜色
uniform sampler2D colorMap;

smooth in vec3 vVaryingNormal; //输入平滑过后的法线
smooth in vec3 vVaryingLightDir; //输入平滑过后的灯光方向
smooth in vec2 vTexCoords;

void main(void)
{
//漫反射计算
    float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
    vFragColor = diff * diffuseColor;
//环境光
    vFragColor += ambientColor;

    vFragColor *= texture(colorMap, vTexCoords);

//反射光线计算高光计算
    vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));
    float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));
    if (diff != 0)
    {
      float fSpec = pow(spec, 128.0);
      vFragColor.rgb += vec3(fSpec, fSpec, fSpec);
    }
   
}如果遇到报错如下:


在图中位置 加上#define WIN32即可 WIN64平台time函数路径和相关实现与WIN32有所不同;
相关代码解释参考:
GLTools里包含用于操作矩阵和向量的3D数学库,并依靠GLEW获得OpenGL用来生产和渲染一些简单的3D对象的函数,以及对视觉平截头体,相机类和变换矩阵进行管理的函数的充分支持。
GLShaderManager.h移入了GLTool着色器管理器(ShaderManager)类,不仅可以创建着色器类,还提供一组“储存着色器”(StockShader),能够进行一些初步和基本的渲染操作。
ShaderManager在使用前必须进行初始化,ShaderManager.InitializeStockShaders();
UseStockShader 储存着色器类型及调用:
单位着色器,使用默认的笛卡尔坐标系【-1,1】所有片段都应用同一种颜色,几何图形为实心和未渲染的,着色器只使用一个属性 GLT_ATTRIBUTE_VERTEX,vColor参数包含了要求的颜色;
GLShaderManager::UseStockShader(GLT_SHADER_IDENTITY,GLfloat vColor);
平面着色器对单位着色器进行了扩展,允许为几何图形变化指定一个4*4变换矩阵,典型情况下是一种左乘模型视图矩阵和投影矩阵,被叫做“模型视图投影矩阵”,这种着色器也只使用一个属性GLT_ATTRIBUTE_VERTEX;
GLShaderManager::UseStockShader(GLT_SHADER_IDENTITY,GLfloat mvp,GLfloat vColor);
默认的储存着色器还包括 上色着色器默认光源着色器 点光源着色器 纹理替换矩阵 纹理调整着色器 纹理光源着色器...(文章的第三章 基础渲染中有详细介绍,本文使用自定书写着色器就不一一记录)
shaderManager.LoadShaderPairWithAttributes()函数,加载一对着色器,进行编译并链接在一起,可以参考;
前两个参数为 着色器的名称(文件路径),后面数字是顶点属性数量,其后是具体顶点属性以及对应的着色器参数名称;(参考文章第六章6.1);
GLFrame类         是拿来做变化用的。可以用来产生模型视图矩阵。来产生顶点位置的移动 GetCameraMatrix是GLFrame的一个函数,通常会用这个来进行设置,可以通过此函数来获取一个观察者变换过后的矩阵,可以把顶点坐标从模型空间变换到摄像机空间下;
GLFrustum类         可以创建一个透视投影的矩阵;
GLTriangleBatch类GLTriangleBatch类是专门作为三角形的批次容器的,每个顶点都可以有一个表面法线,以进行光照计算和纹理坐标;
GLMatrixStack类     矩阵堆栈类GLMatrixStack, 这个矩阵堆栈在初始化时候包含了单位矩阵;
GLGeometryTransform类   矩阵管理器;
矩阵存储在堆区,而地址是存储在栈区,在大量进行变换的应用的场景中,就需要顶点与大量的变换矩阵进行相乘,这时候就需要大量的构造矩阵,这时候有一个便利的矩阵构造函数可以进行构造矩阵操作矩阵乘法会方便很多,在math3d的这个类被称为GLMatrixsStack。
使用矩阵堆栈进行矩阵的创建和操作矩阵乘法很方便,但是我们还要方便的管理这些堆栈,就是说我们可以随时方便取到堆栈矩阵的地址,GLGeometryTransform可以设置指针指向我们创建好的堆栈矩阵。

OpenGL超级宝典(第五版)中文PDF
链接:https://pan.baidu.com/s/1FH-z6_nRHDoL0ZLvkOgd6A
提取码:gzfh
OpenGL超级宝典(第五版)源码
链接:https://pan.baidu.com/s/1wWtvS7sGKRhpB-dp7l2KrQ
提取码:2met
OpenGL超级宝典(第五版)环境配置相关.h .dll .lib文件
链接:https://pan.baidu.com/s/1v3zjS5IGpOW35jAuxxS4kQ
提取码:3zeq
页: [1]
查看完整版本: OpenGL学习笔记(十二)学习OpenGL超级宝典(第五版)