学习记录 LearnOpenGl文档 -- hello shader(变色三角形)

待补充:

做一个变色三角形:

在hello triangles的代码基础上只要做稍微的变动就可以了

在片段着色中声明uniform全局变量ourColor,然后叠加或者赋值给片段颜色FragColor

const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"uniform vec4 ourColor;\n"
"void main()\n"
"{\n"
"   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f) + ourColor;\n"
"}\n\0";

在渲染循环中添加改变这个全局变量ourColor值的代码

 // 更新uniform颜色
        //glfwGetTime()获取运行的秒数
        float timeValue = glfwGetTime();
        float greenValue = sin(timeValue) / 2.0f + 0.5f;
        //glGetUniformLocation查询uniform ourColor的位置值。我们为查询函数提供着色器程序和uniform的名字(这是我们希望获得的位置值的来源)。
        //如果glGetUniformLocation返回 -1 就代表没有找到这个位置值
        //注意,查询uniform地址不要求你之前使用过着色器程序,但是更新一个uniform之前你必须先使用程序(调用glUseProgram),因为它是在当前激活的着色器程序中设置uniform的
        int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
        //glUniform4f函数设置uniform值
        glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

完整代码:

#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glad.c>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);

#pragma region 渲染三角形

//顶点着色器
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";

//片段着色器
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"uniform vec4 ourColor;\n"
"void main()\n"
"{\n"
"   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f) + ourColor;\n"
"}\n\0";

#pragma endregion


int main()
{
    glfwInit();
    //第一个参数代表选项的名称,第二个参数接受一个整型,用来设置这个选项的值
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    //如果使用的是Mac OS X系统,你还需要加下面这行代码到你的初始化代码中这些配置才能起作用
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

    //创建一个窗口对象,这个窗口对象存放了所有和窗口相关的数据
    //宽和高作为它的前两个参数。第三个参数表示这个窗口的名称
    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);

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

    //告诉OpenGL渲染窗口的尺寸大小
    //前两个参数控制窗口左下角的位置。第三个和第四个参数控制渲染窗口的宽度和高度(像素)
    glViewport(0, 0, 800, 600);

    //告诉GLFW我们希望每当窗口调整大小的时候调用这个函数
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

#pragma region 渲染三角形

    //构建和编译着色器

    //创建顶点着色器
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    //glShaderSource函数把要编译的着色器对象作为第一个参数。第二参数指定了传递的源码字符串数量,这里只有一个。第三个参数是顶点着色器真正的源码,第四个参数我们先设置为NULL。
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    //编译顶点着色器
    glCompileShader(vertexShader);

    //检测编译是否成功
    int success;
    char infoLog[512];
    //glGetShaderiv检查是否编译成功
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);

    if (!success)
    {
        //glGetShaderInfoLog获取错误消息
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    //创建片段着色器
    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);

    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    //链接(Link)shader
    //glCreateProgram函数创建一个程序,并返回新创建程序对象的ID引用
    unsigned int shaderProgram = glCreateProgram();
    //将编译的着色器附加到程序上
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);

    //glLinkProgram链接
    glLinkProgram(shaderProgram);

    //glGetProgramiv检查是否链接成功
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);

    if (!success)
    {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\N" << infoLog << std::endl;
    }

    //把着色器对象链接到程序对象以后,记得删除着色器对象,我们不再需要它们了
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);


    //设置顶点数据(和缓冲)和配置顶点属性
    //顶点
    float vertices[] = {
         0.5f,  0.5f, 0.0f,  // top right
         0.5f, -0.5f, 0.0f,  // bottom right
        -0.5f, -0.5f, 0.0f,  // bottom left
        -0.5f,  0.5f, 0.0f   // top left 
    };
    //顶点索引
    unsigned int indices[] = {
        // 注意索引从0开始! 
        // 此例的索引(0,1,2,3)就是顶点数组vertices的下标,
        // 这样可以由下标代表顶点组合成矩形
       0, 1, 3, // 第一个三角形
       //1, 2, 3  // 第二个三角形
    };

    //顶点数组对象:Vertex Array Object,VAO
    //顶点缓冲对象:Vertex Buffer Object,VBO
    //元素缓冲对象:Element Buffer Object,EBO 或 索引缓冲对象 Index Buffer Object,IBO
    unsigned int VBO, VAO, EBO;
    //生成顶点数组对象名称
    glGenVertexArrays(1, &VAO);

    //使用glGenBuffers函数和一个缓冲ID生成一个VBO对象
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    //绑定VAO,首先查找顶点数组对象,然后绑定和设置顶点缓冲区,然后配置顶点属性。
    glBindVertexArray(VAO);

    //复制顶点数组到缓冲中供OpenGL使用
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    //调用glVertexAttribPointer注册VBO作为顶点属性的绑定顶点缓冲区对象,因此之后我们可以安全地解除绑定
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    //不要在VAO激活时解除EBO的绑定,因为绑定的元素缓冲对象存储在VAO中;保持EBO限制。
    //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    //你可以在之后解除绑定VAO,这样其他VAO调用就不会意外地修改这个VAO,但这种情况很少发生。修改其他
    // VAOs无论如何都需要调用glBindVertexArray,所以我们通常不会在非直接必要的情况下解绑定VAOs(或VBOs)。
    glBindVertexArray(0);

    //绘制多边形的模式,用于绘制线框多边形的调用
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#pragma endregion


    // 渲染循环
    //glfwWindowShouldClose函数在我们每次循环的开始前检查一次GLFW是否被要求退出,
    //如果是的话该函数返回true然后渲染循环便结束了,之后为我们就可以关闭应用程序了
    while (!glfwWindowShouldClose(window))
    {
        // 输入
        processInput(window);

        // 渲染指令
        //设置清空屏幕所用的颜色
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        //清空屏幕的颜色缓冲
        glClear(GL_COLOR_BUFFER_BIT);

#pragma region 渲染三角形
        //绘制第一个三角形
        //调用glUseProgram函数,用刚创建的程序对象作为它的参数,以激活这个程序对象:
        glUseProgram(shaderProgram);
        //因为我们只有一个VAO,所以没有必要每次都绑定它,但我们这样做是为了让事情更有条理
        glBindVertexArray(VAO);
        //绘制三角形
        //glDrawArrays(GL_TRIANGLES, 0, 6);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        //不需要每次解绑
        // glBindVertexArray(0);
#pragma endregion

#pragma region 更新uniform颜色
        //glfwGetTime()获取运行的秒数
        float timeValue = glfwGetTime();
        float greenValue = sin(timeValue) / 2.0f + 0.5f;
        //glGetUniformLocation查询uniform ourColor的位置值。我们为查询函数提供着色器程序和uniform的名字(这是我们希望获得的位置值的来源)。
        //如果glGetUniformLocation返回 -1 就代表没有找到这个位置值
        //注意,查询uniform地址不要求你之前使用过着色器程序,但是更新一个uniform之前你必须先使用程序(调用glUseProgram),因为它是在当前激活的着色器程序中设置uniform的
        int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
        //glUniform4f函数设置uniform值
        glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
#pragma endregion

        // 检查并调用事件,交换缓冲
        glfwSwapBuffers(window);
        //检查有没有触发什么事件(比如键盘输入、鼠标移动等)、
        //更新窗口状态,并调用对应的回调函数(可以通过回调方法手动设置)
        glfwPollEvents();
    }

#pragma region  渲染三角形
    //可选: 一旦资源超过了使用期限,就取消分配资源:
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    glDeleteProgram(shaderProgram);
#pragma endregion

    //渲染循环结束后我们需要正确释放/删除之前的分配的所有资源
    glfwTerminate();
    return 0;
}

/// <summary>
/// 当用户改变窗口的大小的时候,视口也应该被调整。
/// 我们可以对窗口注册一个回调函数(Callback Function),
/// 它会在每次窗口大小被调整的时候被调用
/// </summary>
/// <param name="window"></param>
/// <param name="width"></param>
/// <param name="height"></param>
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

/// <summary>
/// 输入控制
/// </summary>
/// <param name="window"></param>
void processInput(GLFWwindow* window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值