大作业要做这个,边学边做笔记

学习链接

遇到的问题:
显示的纹理变成了黑白色,且存在纹理错位的情况,用wps裁剪了一下就好了,不知道为啥

代码解读:
顶点着色器

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

uniform mat4 transform;

void main()
{
	gl_Position = transform * vec4(aPos, 1.0);
	TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}

片段着色器

#version 330 core
out vec4 FragColor;

in vec2 TexCoord;

// texture samplers
uniform sampler2D texture1;
uniform sampler2D texture2;

void main()
{
	// linearly interpolate between both textures (80% container, 20% awesomeface)
	FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
}

旋转矩形

#define STB_IMAGE_IMPLEMENTATION
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>

#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <gtc/type_ptr.hpp>

#include <shader_s.h>

#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height)//回调函数,窗口改变的时候也应该调整视口
{
    glViewport(0, 0, width, height);//设置OpenGL渲染窗口的尺寸大小
}
void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

int main()
{
    /*初始化*/
    if(!glfwInit())return -1;
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	/*定义窗口尺寸和名称*/
    GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);//设置为当前上下文

	
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//调整窗口大小的时候要调用调整视口的函数

	//glad是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们都需要初始化GLAD
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    Shader ourShader("5.1.transform.vs", "5.1.transform.fs");//生成顶点着色器 片段着色器

    float vertices[] = //每一行是图形顶点坐标+纹理坐标
	{
         0.5f,  0.5f, 0.0f,   1.0f, 1.0f, //右上角
         0.5f, -0.5f, 0.0f,   1.0f, 0.0f, //右下角
        -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, //左下角
        -0.5f,  0.5f, 0.0f,   0.0f, 1.0f  //左上角 
    };
    unsigned int indices[] = //每一行是画的三角形用到了vertices哪些点
	{
        0, 1, 3,//第一个
        1, 2, 3 //第二个
    };
    unsigned int VBO, VAO, EBO;
    glGenVertexArrays(1, &VAO);//生成顶点数组对象
    glGenBuffers(1, &VBO);//生成顶点缓冲对象
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);//绑定顶点数组对象

    glBindBuffer(GL_ARRAY_BUFFER, VBO);//绑定顶点缓冲对象
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//把用户定义的数据复制到当前绑定缓冲的函数。
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);//GL_ELEMENT_ARRAY_BUFFER用于处理索引
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);//解释顶点数据 图形顶点坐标
    glEnableVertexAttribArray(0);//开启了0这个通道

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));//解释顶点数据 纹理坐标
    glEnableVertexAttribArray(1);

	/*下面用于加载纹理1*/
    unsigned int texture1, texture2;
    glGenTextures(1, &texture1);//生成纹理1
    glBindTexture(GL_TEXTURE_2D, texture1);//绑定纹理1
    // 为当前绑定的纹理对象设置环绕、过滤方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(true); //这句用来翻转图片y轴,因为图片y轴正方向的定义往往和opengl的相反,所以在加载图片前加上这一句
    unsigned char *data = stbi_load("myTexturePic.jpg", &width, &height, &nrChannels, 0);
	std::cout<<nrChannels<<std::endl;
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);

	/*下面用于加载纹理2*/
    glGenTextures(1, &texture2);
    glBindTexture(GL_TEXTURE_2D, texture2);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    data = stbi_load("awesomeface.png", &width, &height, &nrChannels, 0);
	std::cout<<nrChannels<<std::endl;
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);
	/*-------------------------------上面是加载纹理-----------------------------------*/


    ourShader.use(); //使用着色器
    ourShader.setInt("texture1", 0);//设置纹理
    ourShader.setInt("texture2", 1);


    while (!glfwWindowShouldClose(window))//循环渲染
    {

        processInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//设置清空屏幕(就是运行glClear)用啥颜色
        glClear(GL_COLOR_BUFFER_BIT);//清空屏幕

        glActiveTexture(GL_TEXTURE0);//设置纹理单元
        glBindTexture(GL_TEXTURE_2D, texture1);//绑定纹理目标
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);


        glm::mat4 transform = glm::mat4(1.0f); // 单位矩阵
        transform = glm::translate(transform, glm::vec3(0.5f, -0.5f, 0.0f));//移动
        transform = glm::rotate(transform, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));//旋转

        ourShader.use();
        unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");//获取着色器内某个参数的位置
        glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));//写入参数值

        glBindVertexArray(VAO);//绑定顶点数组对象
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);//用索引画,有6个点

        glfwSwapBuffers(window);//交换缓冲(是一个储存所有颜色的大缓冲)
        glfwPollEvents();//检查有没有键盘鼠标输入,有就调用回调函数
    }

    /*删除操作*/
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);

    glfwTerminate();//释放之前分配的所有资源
    return 0;
}

旋转立方体

#define STB_IMAGE_IMPLEMENTATION
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>

#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <gtc/type_ptr.hpp>

#include <shader_m.h>

#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height)//回调函数,窗口改变的时候也应该调整视口
{
    glViewport(0, 0, width, height);//设置OpenGL渲染窗口的尺寸大小
}
void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

int main()
{
     /*初始化*/
    if(!glfwInit())return -1;
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    /*定义窗口尺寸和名称*/
    GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);//设置为当前上下文
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//调整窗口大小的时候要调用调整视口的函数

    //glad是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们都需要初始化GLAD
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }
    glEnable(GL_DEPTH_TEST);//开启更新深度缓冲区的功能,启动它,OpenGL就可以跟踪再Z轴上的像素
    Shader ourShader("6.2.coordinate_systems.vs", "6.2.coordinate_systems.fs");//生成顶点着色器 片段着色器

    float vertices[] = {//每一行是图形顶点坐标+纹理坐标
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,//前
         0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
         0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
         0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
         0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
         0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f
    };
    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);//生成顶点数组对象
    glGenBuffers(1, &VBO);//生成顶点缓冲对象

    glBindVertexArray(VAO);//绑定顶点数组对象

    glBindBuffer(GL_ARRAY_BUFFER, VBO);//绑定顶点缓冲对象
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//把用户定义的数据复制到当前绑定缓冲的函数

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);//解释顶点数据 图形顶点坐标
    glEnableVertexAttribArray(0);//开启了0这个通道

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));//解释顶点数据 纹理坐标
    glEnableVertexAttribArray(1);


    /*下面用于加载纹理1*/
    unsigned int texture1, texture2;
    glGenTextures(1, &texture1);//生成纹理1
    glBindTexture(GL_TEXTURE_2D, texture1);//绑定纹理1
    // 为当前绑定的纹理对象设置环绕、过滤方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(true); //这句用来翻转图片y轴,因为图片y轴正方向的定义往往和opengl的相反,所以在加载图片前加上这一句
    unsigned char *data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
	std::cout<<nrChannels<<std::endl;
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);

	/*下面用于加载纹理2*/
    glGenTextures(1, &texture2);
    glBindTexture(GL_TEXTURE_2D, texture2);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    data = stbi_load("awesomeface.png", &width, &height, &nrChannels, 0);
	std::cout<<nrChannels<<std::endl;
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);
	/*-------------------------------上面是加载纹理-----------------------------------*/

    ourShader.use();//使用着色器
    ourShader.setInt("texture1", 0);//设置纹理
    ourShader.setInt("texture2", 1);


    while (!glfwWindowShouldClose(window))//循环渲染
    {
        processInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//设置清空屏幕(就是运行glClear)用啥颜色
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清空屏幕+深度缓冲

        glActiveTexture(GL_TEXTURE0);//设置纹理单元
        glBindTexture(GL_TEXTURE_2D, texture1);//绑定纹理目标
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);

        ourShader.use();

        glm::mat4 model         = glm::mat4(1.0f);//局部 -> 世界
        glm::mat4 view          = glm::mat4(1.0f);//世界 -> 观察 
        glm::mat4 projection    = glm::mat4(1.0f);//观察 -> 裁剪
        model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(0.5f, 1.0f, 0.0f));
        view  = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
        projection = glm::perspective(glm::radians(45.0f)/*视野*/, (float)SCR_WIDTH / (float)SCR_HEIGHT/*宽高比*/, 0.1f/****面*/, 100.0f/*远平面*/);
        
        unsigned int modelLoc = glGetUniformLocation(ourShader.ID, "model");//获取着色器内某个参数的位置
        unsigned int viewLoc  = glGetUniformLocation(ourShader.ID, "view");
        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));//写入参数值
        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]);
        ourShader.setMat4("projection", projection);//更改矩阵

        glBindVertexArray(VAO);//绑定顶点数组对象
        glDrawArrays(GL_TRIANGLES, 0, 36);//用数组来画,36个点


		glfwSwapBuffers(window);//交换缓冲(是一个储存所有颜色的大缓冲)
        glfwPollEvents();//检查有没有键盘鼠标输入,有就调用回调函数
    }
	/*删除操作*/
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);

    glfwTerminate();//释放之前分配的所有资源
    return 0;
}

有了移动功能

#define STB_IMAGE_IMPLEMENTATION
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>

#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <gtc/type_ptr.hpp>

#include <shader_m.h>

#include <iostream>

const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

glm::vec3 cameraPos   = glm::vec3(0.0f, 0.0f, 3.0f);//位置
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);//朝向
glm::vec3 cameraUp    = glm::vec3(0.0f, 1.0f, 0.0f);//UP方向

bool firstMouse = true;
float yaw   = -90.0f;	// yaw is initialized to -90.0 degrees since a yaw of 0.0 results in a direction vector pointing to the right so we initially rotate a bit to the left.
float pitch =  0.0f;
float lastX =  800.0f / 2.0;
float lastY =  600.0 / 2.0;
float fov   =  45.0f;

float deltaTime = 0.0f;	//计算两帧之间的时间差
float lastFrame = 0.0f;

void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)//检查是否按住了esc
        glfwSetWindowShouldClose(window, true);//按住了就关闭

    float cameraSpeed = static_cast<float>(2.5 * deltaTime);//移动距离和每秒帧数有关,防止不同设备体验不一样
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        cameraPos += cameraSpeed * cameraFront;
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        cameraPos -= cameraSpeed * cameraFront;
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)//回调函数,窗口改变的时候也应该调整视口
{
    glViewport(0, 0, width, height);//设置OpenGL渲染窗口的尺寸大小
}

void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)//鼠标移动
{
    float xpos = static_cast<float>(xposIn);
    float ypos = static_cast<float>(yposIn);

    if (firstMouse)//首次进入
    {
        lastX = xpos;
        lastY = ypos;
        firstMouse = false;
    }

    float xoffset = xpos - lastX;
    float yoffset = lastY - ypos; // 这里是相反的,因为俯仰角的0是竖直向上
    lastX = xpos;
    lastY = ypos;

    float sensitivity = 0.1f; // 灵敏度
    xoffset *= sensitivity;
    yoffset *= sensitivity;

    yaw += xoffset;//偏航角
    pitch += yoffset;//俯仰角

    if (pitch > 89.0f)//仰角要有范围
        pitch = 89.0f;
    if (pitch < -89.0f)
        pitch = -89.0f;

    glm::vec3 front;
    front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));//计算向量
    front.y = sin(glm::radians(pitch));
    front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
    cameraFront = glm::normalize(front);
}

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)//视野回调函数
{
    fov -= (float)yoffset;
    if (fov < 1.0f)//fov越小,视野越小,看见的越大
        fov = 1.0f;
    if (fov > 45.0f)
        fov = 45.0f;
}
int main()
{
    /*初始化*/
    if(!glfwInit())return -1;
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    /*定义窗口尺寸和名称*/
    GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);//设置为当前上下文
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//调整窗口大小的时候要调用调整视口的函数
    glfwSetCursorPosCallback(window, mouse_callback);//鼠标移动的时候调用回调函数
    glfwSetScrollCallback(window, scroll_callback);//鼠标滚轮的回调函数

    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);//隐藏光标,并控制其不离开窗口

    //glad是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们都需要初始化GLAD
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    glEnable(GL_DEPTH_TEST);//开启更新深度缓冲区的功能,启动它,OpenGL就可以跟踪再Z轴上的像素
    Shader ourShader("6.2.coordinate_systems.vs", "6.2.coordinate_systems.fs");//生成顶点着色器 片段着色器

    float vertices[] = {//每一行是图形顶点坐标+纹理坐标
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,//前
         0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
         0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
         0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
         0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
         0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f
    };
    // world space positions of our cubes
    glm::vec3 cubePositions[] = {
        glm::vec3( 0.0f,  0.0f,  0.0f),
        glm::vec3( 2.0f,  5.0f, -15.0f),
        glm::vec3(-1.5f, -2.2f, -2.5f),
        glm::vec3(-3.8f, -2.0f, -12.3f),
        glm::vec3( 2.4f, -0.4f, -3.5f),
        glm::vec3(-1.7f,  3.0f, -7.5f),
        glm::vec3( 1.3f, -2.0f, -2.5f),
        glm::vec3( 1.5f,  2.0f, -2.5f),
        glm::vec3( 1.5f,  0.2f, -1.5f),
        glm::vec3(-1.3f,  1.0f, -1.5f)
    };
    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);//生成顶点数组对象
    glGenBuffers(1, &VBO);//生成顶点缓冲对象

    glBindVertexArray(VAO);//绑定顶点数组对象

    glBindBuffer(GL_ARRAY_BUFFER, VBO);//绑定顶点缓冲对象
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//把用户定义的数据复制到当前绑定缓冲的函数

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);//解释顶点数据 图形顶点坐标
    glEnableVertexAttribArray(0);//开启了0这个通道

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));//解释顶点数据 纹理坐标
    glEnableVertexAttribArray(1);


    /*下面用于加载纹理1*/
    unsigned int texture1, texture2;
    glGenTextures(1, &texture1);//生成纹理1
    glBindTexture(GL_TEXTURE_2D, texture1);//绑定纹理1
    // 为当前绑定的纹理对象设置环绕、过滤方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(true); //这句用来翻转图片y轴,因为图片y轴正方向的定义往往和opengl的相反,所以在加载图片前加上这一句
    unsigned char *data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
	std::cout<<nrChannels<<std::endl;
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);

	/*下面用于加载纹理2*/
    glGenTextures(1, &texture2);
    glBindTexture(GL_TEXTURE_2D, texture2);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    data = stbi_load("awesomeface.png", &width, &height, &nrChannels, 0);
	std::cout<<nrChannels<<std::endl;
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture" << std::endl;
    }
    stbi_image_free(data);
	/*-------------------------------上面是加载纹理-----------------------------------*/
    
	ourShader.use();//使用着色器
    ourShader.setInt("texture1", 0);//设置纹理
    ourShader.setInt("texture2", 1);


    while (!glfwWindowShouldClose(window))//循环渲染
    {
        float currentFrame = static_cast<float>(glfwGetTime());//当前运行的时间
        deltaTime = currentFrame - lastFrame;//获得两帧间隔的时间
        lastFrame = currentFrame;

        processInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//设置清空屏幕(就是运行glClear)用啥颜色
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清空屏幕+深度缓冲

        glActiveTexture(GL_TEXTURE0);//设置纹理单元
        glBindTexture(GL_TEXTURE_2D, texture1);//绑定纹理目标
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);

        ourShader.use();

        glm::mat4 projection = glm::perspective(glm::radians(fov)/*视野*/, (float)SCR_WIDTH / (float)SCR_HEIGHT/*宽高比*/, 0.1f/****面*/, 100.0f/*远平面*/);
        ourShader.setMat4("projection", projection);//更改projection矩阵

        glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);//设置look矩阵
        ourShader.setMat4("view", view);

        glBindVertexArray(VAO);//绑定顶点数组对象
        for (unsigned int i = 0; i < 10; i++)
        {
            glm::mat4 model = glm::mat4(1.0f); // 初始化为单位矩阵
            model = glm::translate(model, cubePositions[i]);//移动
            float angle = 20.0f * i;//确定旋转角度
            model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)/*旋转轴*/);//旋转
            ourShader.setMat4("model", model);//更改model矩阵

            glDrawArrays(GL_TRIANGLES, 0, 36);//用数组来画,36个点
        }

        glfwSwapBuffers(window);//交换缓冲(是一个储存所有颜色的大缓冲)
        glfwPollEvents();//检查有没有键盘鼠标输入,有就调用回调函数
    }
	/*删除操作*/
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);

    glfwTerminate();//释放之前分配的所有资源
    return 0;
}

最终版本

/*
功能介绍
0随机纹理 1~5统一纹理 P显示全部 Q仅显示立方体 C清屏 R旋转 T放缩 
esc退出 w a s d 移动 
*/
#define STB_IMAGE_IMPLEMENTATION
#pragma comment(lib,"glew32.lib")
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>
#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <gtc/type_ptr.hpp>
#include <iostream>
#include <fstream>
#include <sstream>

const unsigned int SCR_WIDTH = 1200;
const unsigned int SCR_HEIGHT = 900;
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f),cameraFront = glm::vec3(0.0f, 0.0f, -1.0f),cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);//位置 朝向 UP方向

bool firstMouse = true;
float pitch =  0.0f,yaw   = -90.0f/*0是朝向右,-90是向后*/,lastX =  800.0f / 2.0,lastY =  600.0 / 2.0,fov   =  45.0f,deltaTime = 0.0f,lastFrame = 0.0f;//俯仰角 偏航角 上一帧的鼠标位置 视野 计算两帧之间的时间差
int draw[6],revolve=0,amplify=0;//是否画图形 是否旋转 是否放大缩小
float angle=0.0f,times=0.0f;//用来计算旋转角度 放缩倍数
unsigned int texture[10],wenliHua[10];//加载纹理用 画纹理的时候用

class Shader//着色器用class包装一下
{
public:
    unsigned int ID,vertex, fragment;//着色器程序(=顶点着色器+片段着色器)编号 顶点着色器编号 片段着色器编号
	GLint success;
    GLchar infoLog[1024];
    void init()
    {
		const char* vertexShaderSource = "#version 330 core\n"//顶点着色器程序
				"layout (location = 0) in vec3 aPos;\n"
				"layout (location = 1) in vec2 aTexCoord;\n"
				"out vec2 TexCoord;\n"
				"uniform mat4 projection,view,model;\n"
				"void main()\n"
				"{\n"
				"	gl_Position = projection * view * model * vec4(aPos, 1.0f);\n"//最终坐标要记得吧变化算上
				"	TexCoord = vec2(aTexCoord.x, aTexCoord.y);\n"
				"}\0";
    const char* fragmentShaderSource = "#version 330 core\n"//片段着色器程序
				"out vec4 FragColor;\n"
				"in vec2 TexCoord;\n"
				"uniform sampler2D texture1;\n"
				"void main()\n"
				"{\n"
				"	FragColor =texture(texture1, TexCoord);\n"
				"}\0";

        vertex = glCreateShader(GL_VERTEX_SHADER);//创建顶点着色器 CreateShader返回类型为unsigned int ,返回的是创建出的着色器的id
        glShaderSource(vertex, 1, &vertexShaderSource, NULL);//将前面写的着色器源码(vertexShaderSource)附加给着色器对象(vertexShader)
        glCompileShader(vertex);//编译这个着色器对象
		glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);//检查顶点着色器对象是否编译成功
        if (!success)
        {
            glGetShaderInfoLog(vertex, 1024, NULL, infoLog);
            std::cout << "glGetShaderiv ERROR!" <<infoLog <<std::endl;
        }
        fragment = glCreateShader(GL_FRAGMENT_SHADER);//创建片段着色器
        glShaderSource(fragment, 1, &fragmentShaderSource, NULL);//将前面写的着色器源码(vertexShaderSource)附加给着色器对象(vertexShader)
        glCompileShader(fragment);//编译这个着色器对象
        glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);//检查顶点着色器对象是否编译成功
        if (!success)
        {
            glGetShaderInfoLog(fragment, 1024, NULL, infoLog);
            std::cout << "glGetShaderiv ERROR!" <<infoLog <<std::endl;
		}
        ID = glCreateProgram();//创建着色器程序对象,着色器程序对象(Shader Program Object)是多个着色器合并之后并最终链接完成的版本。
        glAttachShader(ID, vertex);//将前面创建的顶点着色器对象附加到着色器程序对象上
        glAttachShader(ID, fragment);//将前面创建的片段着色器对象附加到着色器程序对象上
        glLinkProgram(ID);//链接程序
		glGetProgramiv(ID, GL_LINK_STATUS, &success);//检查链接过程中是否有错误
        if (!success)
        {
            glGetProgramInfoLog(ID, 1024, NULL, infoLog);
            std::cout << "glGetShaderiv ERROR!" <<infoLog <<std::endl;
        }
        glDeleteShader(vertex);//删除着色器对象,已经链接完了,不需要它们了
        glDeleteShader(fragment);
    }
    void setInt(char name[], int value)
    { 
        glUniform1i(glGetUniformLocation(ID, name)/*获取uniform变量tansform的地址 ,shaderProgram为前面定义的着色器程序*/, value); 
    }
    void setMat4(char name[],glm::mat4 mat) 
    {
        glUniformMatrix4fv(glGetUniformLocation(ID, name)/*变量的位置值*/, 1, GL_FALSE, &mat[0][0]);//通过glUniform4f函数设置uniform值
    }

}myShader;
void processInput(GLFWwindow *window)//检查键盘情况
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)//检查是否按住了esc
        glfwSetWindowShouldClose(window, true);//按住了就关闭

    float cameraSpeed = static_cast<float>(2.5 * deltaTime);//移动距离和每秒帧数有关,防止不同设备体验不一样 static_cast是强制类型转化
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)cameraPos += cameraFront * cameraSpeed  ;//前后左右移动
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)cameraPos -= cameraFront * cameraSpeed  ;
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;

	if (glfwGetKey(window, GLFW_KEY_P) == GLFW_PRESS)draw[1]=draw[2]=draw[3]=draw[4]=draw[5]=1;//按住P 全画
	if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)draw[1]=1,draw[2]=draw[3]=draw[4]=draw[5]=0;//Q仅立方体
	if (glfwGetKey(window, GLFW_KEY_C) == GLFW_PRESS)draw[1]=draw[2]=draw[3]=draw[4]=draw[5]=0;//C清屏
	static float lastPressR=0;
	if (glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS&&(float)glfwGetTime()-lastPressR>0.5)revolve^=1,lastPressR=(float)glfwGetTime();//R 旋转
	static float lastPressT=0;
	if (glfwGetKey(window, GLFW_KEY_T) == GLFW_PRESS&&(float)glfwGetTime()-lastPressT>0.5)amplify^=1,lastPressT=(float)glfwGetTime();//T 收缩

	static float lastPress0=0;//用随机纹理
	if (glfwGetKey(window, GLFW_KEY_0) == GLFW_PRESS&&(float)glfwGetTime()-lastPress0>0.5)for(int i=1;i<=5;++i)wenliHua[i]=texture[rand()*3%5],lastPress0=(float)glfwGetTime();
	static float lastPress1=0;//用统一的几种纹理
	if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS&&(float)glfwGetTime()-lastPress1>0.5)for(int i=1;i<=5;++i)wenliHua[i]=texture[0],lastPress1=(float)glfwGetTime();
	static float lastPress2=0;
	if (glfwGetKey(window, GLFW_KEY_2) == GLFW_PRESS&&(float)glfwGetTime()-lastPress2>0.5)for(int i=1;i<=5;++i)wenliHua[i]=texture[1],lastPress2=(float)glfwGetTime();
	static float lastPress3=0;
	if (glfwGetKey(window, GLFW_KEY_3) == GLFW_PRESS&&(float)glfwGetTime()-lastPress3>0.5)for(int i=1;i<=5;++i)wenliHua[i]=texture[2],lastPress3=(float)glfwGetTime();
	static float lastPress4=0;
	if (glfwGetKey(window, GLFW_KEY_4) == GLFW_PRESS&&(float)glfwGetTime()-lastPress4>0.5)for(int i=1;i<=5;++i)wenliHua[i]=texture[3],lastPress4=(float)glfwGetTime();
	static float lastPress5=0;
	if (glfwGetKey(window, GLFW_KEY_5) == GLFW_PRESS&&(float)glfwGetTime()-lastPress5>0.5)for(int i=1;i<=5;++i)wenliHua[i]=texture[4],lastPress5=(float)glfwGetTime();
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)//回调函数,窗口改变的时候也应该调整视口
{
    glViewport(0, 0, width, height);//设置OpenGL渲染窗口的尺寸大小
}

void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)//鼠标移动
{
    float xpos = static_cast<float>(xposIn),ypos = static_cast<float>(yposIn);
    if (firstMouse)lastX = xpos,lastY = ypos,firstMouse = false;//首次进入

    float xoffset = (xpos - lastX)*0.1f,yoffset = (lastY - ypos)*0.1f; // yoffset是相反的,因为俯仰角的0是竖直向上 这里的0.1是灵敏度
    yaw += xoffset,pitch += yoffset;pitch=std::max(pitch,-89.0f);pitch=std::min(pitch,89.0f);//偏航角 俯仰角 俯仰角要有范围
	lastX = xpos;lastY = ypos;//计算完记得更新
	
    glm::vec3 front;
    front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));//计算向量
    front.y = sin(glm::radians(pitch));
    front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
    cameraFront = glm::normalize(front);
}

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)//视野回调函数
{
    fov -= (float)yoffset;
	fov=std::max(fov,1.0f);fov=std::min(fov,45.0f);//fov越小,视野越小,看见的越大
}

void wenli(char name[],unsigned int &texture)//用来加载纹理
{
	glGenTextures(1, &texture);//生成纹理
    glBindTexture(GL_TEXTURE_2D, texture);//绑定纹理
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);// 为当前绑定的纹理对象设置环绕、过滤方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(true); //这句用来翻转图片y轴,因为图片y轴正方向的定义往往和opengl的相反,所以在加载图片前加上这一句
    unsigned char *data = stbi_load(name, &width, &height, &nrChannels, 0);//
    if (data)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, nrChannels==3?GL_RGB:GL_RGBA/*注意一下看看是几通道*/, GL_UNSIGNED_BYTE, data);
		glGenerateMipmap(GL_TEXTURE_2D);//生成多级渐远纹理
    }
    else std::cout << "纹理加载失败!" << std::endl;
    stbi_image_free(data);//释放空间
}
void myDraw(int id,float posX,float posY,float posZ,float revolveX,float revolveY,float revolveZ,float revolveTimes,float scaleTimes,int beginPos,int num)
{
	glm::mat4 model = glm::mat4(1.0f);
	if(!draw[id])return;
	glActiveTexture(GL_TEXTURE1);//设置纹理单元
	glBindTexture(GL_TEXTURE_2D, wenliHua[id]);//绑定纹理目标
	model = glm::translate(model, glm::vec3(posX, posY, posZ));//移动
	model = glm::rotate(model, angle*revolveTimes, glm::vec3(revolveX, revolveY, revolveZ)/*旋转轴*/);//旋转
	model = glm::scale(model,  glm::vec3(1.0f+sin(times)*scaleTimes, 1.0f+sin(times)*scaleTimes, 1.0f+sin(times)*scaleTimes));//放缩
	model = glm::translate(model, glm::vec3(-posX, -posY, -posZ));//移动
	myShader.setMat4("model", model);//更改model矩阵
	glDrawArrays(GL_TRIANGLES, beginPos,num);//用数组来画
}

int main()
{
    /*初始化*/
    if(!glfwInit())return -1;
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//确定版本为3.3
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//使用核心模式

    /*定义窗口尺寸和名称*/
    GLFWwindow* window = glfwCreateWindow(1200, 900, "TuXing", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "glfwCreateWindow ERROR!" << std::endl;
        glfwTerminate();//销毁窗口并释放资源
        return -1;
    }
    glfwMakeContextCurrent(window);//设置为当前上下文
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//调整窗口大小的时候要调用调整视口的函数
    glfwSetCursorPosCallback(window, mouse_callback);//鼠标移动的时候调用回调函数
    glfwSetScrollCallback(window, scroll_callback);//鼠标滚轮的回调函数
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);//隐藏光标,并控制其不离开窗口
	if (glewInit() != 0)std::cout<<"glewInit() ERROR!"<<std::endl;
    glEnable(GL_DEPTH_TEST);//开启更新深度缓冲区的功能,启动它,OpenGL就可以跟踪再Z轴上的像素
    myShader.init();//生成顶点着色器 片段着色器

    float vertices[] = {//每一行是图形顶点坐标+纹理坐标
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,//后
         0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,//前
         0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,//左
        -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,//右
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
         0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,//下
         0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
         0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
         0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,//上
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,

		-2.5f, -0.5f,  0.5f,  0.0f, 0.0f,//长方形
        -1.0f, -0.5f,  0.5f,  1.0f, 0.0f,
        -1.0f,  0.5f,  0.5f,  1.0f, 1.0f,
        -1.0f,  0.5f,  0.5f,  1.0f, 1.0f,
        -2.5f,  0.5f,  0.5f,  0.0f, 1.0f,
        -2.5f, -0.5f,  0.5f,  0.0f, 0.0f,

		-2.5f, -0.5f, -0.5f,  0.0f, 0.0f,//长方形
        -1.0f, -0.5f, -0.5f,  1.0f, 0.0f,
        -1.0f,  0.5f, -0.5f,  1.0f, 1.0f,
        -1.0f,  0.5f, -0.5f,  1.0f, 1.0f,
        -2.5f,  0.5f, -0.5f,  0.0f, 1.0f,
        -2.5f, -0.5f, -0.5f,  0.0f, 0.0f,

		 1.0f, 0.65f,  -0.5f,  0.0f,0.65f,//五角星1
		 1.7f, 0.65f,  -0.5f,  0.7f,0.65f,
         1.9f,  0.0f,  -0.5f,  0.9f, 0.0f,

		 2.0f, 0.65f,  -0.5f,  1.0f,0.65f,//五角星2
		 1.3f, 0.65f,  -0.5f,  0.3f,0.65f,
         1.1f,  0.0f,  -0.5f,  0.1f, 0.0f,

		1.25f,  0.4f,  -0.5f, 0.25f, 0.4f,//五角星3
		1.75f,  0.4f,  -0.5f, 0.75f, 0.4f,
         1.5f,  1.2f,  -0.5f,  0.5f, 1.2f,

		2.25f,  0.0f,  -0.5f, 0.25f, 0.0f,//五边形1
		 2.5f,  1.0f,  -0.5f,  0.5f, 1.0f,
         2.0f, 0.55f,  -0.5f,  0.0f,0.55f,

		2.75f,  0.0f,  -0.5f, 0.75f, 0.0f,//五边形2
		 2.5f,  1.0f,  -0.5f,  0.5f, 1.0f,
         3.0f, 0.55f,  -0.5f,  1.0f,0.55f,

		2.25f,  0.0f,  -0.5f, 0.25f, 0.0f,//五边形3
		2.75f,  0.0f,  -0.5f, 0.75f, 0.0f,
         2.5f,  1.0f,  -0.5f,  0.5f, 1.0f
    };
	draw[1]=draw[2]=draw[3]=draw[4]=draw[5]=1;
    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);//生成顶点数组对象
    glGenBuffers(1, &VBO);//生成顶点缓冲对象
    glBindVertexArray(VAO);//绑定顶点数组对象
    glBindBuffer(GL_ARRAY_BUFFER, VBO);//绑定顶点缓冲对象
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//把用户定义的数据复制到当前绑定缓冲的函数
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);//解释顶点数据 图形顶点坐标
    glEnableVertexAttribArray(0);//开启了0这个通道
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));//解释顶点数据 纹理坐标
    glEnableVertexAttribArray(1);
    
	wenli("tom.png",texture[0]);wenli("jerry.png",texture[1]);wenli("sunrise.png",texture[2]);wenli("sunflower.png",texture[3]);wenli("starry sky.png",texture[4]);//给纹理编号
	glUseProgram(myShader.ID);//使用着色器
    myShader.setInt("texture1", 1);//给着色器里的变量编号
	wenliHua[0]=wenliHua[1]=wenliHua[2]=wenliHua[3]=wenliHua[4]=wenliHua[5]=texture[4];

    while (!glfwWindowShouldClose(window))//循环渲染
    {
        float currentFrame = static_cast<float>(glfwGetTime());//当前运行的时间
        deltaTime = currentFrame - lastFrame;//获得两帧间隔的时间
        lastFrame = currentFrame;
        processInput(window);//检查键盘情况

        glClearColor(0.5f, 0.6f, 0.7f, 1.0f);//设置清空屏幕(就是运行glClear)用啥颜色
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清空屏幕+深度缓冲 
		glUseProgram(myShader.ID);//使用myShader着色器程序

        glm::mat4 projection = glm::perspective(glm::radians(fov)/*视野*/, (float)SCR_WIDTH / (float)SCR_HEIGHT/*宽高比*/, 0.1f/****面*/, 100.0f/*远平面*/);
        myShader.setMat4("projection", projection);//更改projection矩阵
        glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);//设置look矩阵
        myShader.setMat4("view", view);

        glBindVertexArray(VAO);//绑定顶点数组对象

		if(revolve == 1)angle+=deltaTime;//angle 旋转角度
		if(amplify == 1)times+=deltaTime;//times 收缩倍数

		myDraw(1, 0.0f, 0.0f, 0.0f,  1.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0, 36);
		myDraw(2, 0.0f, 0.0f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 36, 6);
		myDraw(3, 0.0f, 0.0f, -0.5f,-1.0f, 0.0f, 0.0f, 0.5f, 0.5f, 42, 6);
		myDraw(4, 1.5f, 0.0f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.5f, 48, 9);
		myDraw(5, 2.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.5f, 57, 9);

        glfwSwapBuffers(window);//交换缓冲(是一个储存所有颜色的大缓冲)
        glfwPollEvents();//检查有没有键盘鼠标输入,有就调用回调函数
    }
	/*删除操作*/
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glfwTerminate();//释放之前分配的所有资源
    return 0;
}