Code Monkey home page Code Monkey logo

parallel101 / opengltutor Goto Github PK

View Code? Open in Web Editor NEW
279.0 5.0 116.0 3.33 MB

零基础入门计算机图形学必不可少的在线网络公开课,手把手教您现代 OpenGL 的点点滴滴,构建爆款游戏引擎。

Home Page: https://space.bilibili.com/263032155/channel/collectiondetail?sid=53025

License: GNU General Public License v3.0

CMake 0.51% C 65.02% SCSS 0.11% HTML 0.02% Objective-C 1.83% C++ 32.47% GLSL 0.04%
3d game-engine glsl graphics opengl opengl-tutorial opengl3 realtime-rendering rendering shaders tutorial webinar

opengltutor's Introduction

现代 OpenGL 保姆级教程

零基础入门计算机图形学必不可少的在线网络公开课,手把手教您现代 OpenGL 的点点滴滴,构建爆款游戏引擎。

本仓库仅仅包含实验源码,课件下载请前往:https://github.com/parallel101/openglslides

国内镜像下载:https://gitee.com/archibate/opengltutor

本分支为最新一课(第三课)的作业项目源码,要做第一课作业的同学请点击这里跳转到 hw01 分支。提交 PR 时,请在标题中写明是第几课的作业,对于第一课的作业,则应该将目标分支设为 hw01。

课程简介

你是否想要掌握计算机图形学的核心原理和技术?你是否想要利用现代OpenGL创建自己的3D游戏引擎?但又苦于没有简单易懂适合入门的中文教程?如果是,那么这门课程就是为你量身定制的! 在这门课程中,你将从基础知识开始,逐步深入探索图形渲染管线的各个阶段,学习如何使用OpenGL和GLSL进行高效的图形编程,实现各种真实感效果,如光照、纹理、阴影等。你还将动手搭建一个完整的3D游戏引擎框架,体验从模型导入、场景管理、相机控制到碰撞检测、动画系统等各个方面的设计和实现。通过这门课程,你将获得丰富的图形学理论和实践知识,为你未来的图形学创作和研究打下坚实的基础。 这门网络公开课每周六2点开始直播,每次约1小时,共15课,错过了也不要紧,每一期的录播都会上传到B站免费观看。

目标:打造一款基于 OpenGL 的 3D 游戏引擎,开发出爆款开源游戏。

面向人群:有一定编程基础,学过 C 语言,想要入门计算机图形学,OpenGL 的初学者。

能学到的东西:现代 OpenGL API 的使用,线性代数与矢量微积分,图形管线的原理,GLSL 着色器语言,迪士尼 BRDF、TAA、IBL、全局光照等现代渲染技术,游戏引擎的 ECS 架构,现代 C++ 设计模式,软件工程最佳实践,软件跨平台,部署与发布,多线程性能优化等。

直播间:https://live.bilibili.com/14248205

课程录播:https://space.bilibili.com/263032155/channel/collectiondetail?sid=53025

课程大纲

  1. 从配置安装到画第一个三角形(BV1Na4y1c7tP)
  2. 重学线性代数矢量与矩阵(BV1ej411U7SW)
  3. 三维模型的加载与相机控制 (录播文件丢失,正在重置中)
  4. GLSL 着色器语言与 PBR 光照模型
  5. UV、法线与材质贴图的加载和使用
  6. 离屏渲染与点选物体的实现
  7. 高质量实时软阴影的实现
  8. 环境光贴图与 IBL 烘培
  9. 色调映射、延迟渲染、Blooming 与 TAA
  10. 屏幕空间反射与 SDF 全局光照
  11. 几何着色器:实例化与曲面细分
  12. 骨骼动画与蒙皮:角色走路动画的实现
  13. 地型的程序化生成与天空体积云的渲染
  14. 用计算着色器做实时物理仿真
  15. 游戏引擎 ECS 架构的设计与实现

课程参考资源

硬件要求

流畅运行所需最低配置:

  • 显卡:Intel 或 AMD 集成显卡,支持 OpenGL 4.3
  • 处理器:2 GHz 以上处理器,64 位
  • 内存:4 GB
  • 硬盘:20 GB 空闲空间

小彭老师同款配置:

  • 显卡:NVIDIA GeForce RTX 2080(或 AMD Radeon RX 5700 XT)独立显卡
  • 处理器:Intel Core i7-9750H(或 AMD Ryzen 7 4800H)
  • 内存:32 GB(DDR4)
  • 硬盘:1 TB

软件要求

编译源码所需软件:

  • 操作系统:Windows >= 10 或 Ubuntu >= 20.04 或 MSYS2 或 WSL2(需要安装 WSLg)
  • 编译器:MSVC >= 19 或 GCC >= 9 或 Clang >= 11(支持 C++17 即可)
  • 编辑器:Visual Studio 2019、2022 或 VS Code 等任意你用得惯的编辑器
  • 构建系统:CMake >= 3.10

小彭老师所用软件:

  • 操作系统:Arch Linux
  • 编译器:GCC 12.2.1
  • 编辑器:NeoVim 0.9.1
  • 构建系统:CMake 3.26

Windows 开发环境搭建

网盘分享链接:https://pan.baidu.com/s/1TZ6nVJC7DZIuUarZrGJYow 提取码:opgl

内含:

  1. VS2022(自带了 CMake 和 Git)
  2. DX 运行时(包含 OpenGL)
  3. OpenGL 软光栅(你没有显卡时才需要下载)
  4. CPU-Z 配置检测工具(可查看显卡和处理器型号)

仅供方便,不一定非用网盘里的文件不可,也可以从网上搜索其他资源下载,也可以选择其他 IDE。

opengltutor's People

Contributors

archibate avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

opengltutor's Issues

问题:计算具有biased的顶点法向量,代码中是不是需要关于顶点做个轮换

@archibate

现代码中,基于顶点a计算出具有biased的顶点法向量后,会依次赋值给a, b, c三个顶点:

opengltutor/src/OBJ.cpp

Lines 77 to 79 in 817754a

for (size_t i = 0; i < 3; i++) {
normals[face[i]] += compute_normal_biased(a, b, c);
}

是不是应该改成,基于顶点a, b, c进行轮换的计算,然后再依次赋值:

normals[face[0]] += compute_normal_biased(a, b, c); 
normals[face[1]] += compute_normal_biased(b, c, a); 
normals[face[2]] += compute_normal_biased(c, a, b);  

请教大佬,为什么运行完189行代码之后,shaderProgram2的值变了

#pragma once

#include <iostream>
#include <glad/glad.h>

static const char *opengl_errno_name(int err) {
    switch (err) {
#define PER_GL_ERROR(x) case GL_##x: return #x;
    PER_GL_ERROR(NO_ERROR)
    PER_GL_ERROR(INVALID_ENUM)
    PER_GL_ERROR(INVALID_VALUE)
    PER_GL_ERROR(INVALID_OPERATION)
    PER_GL_ERROR(STACK_OVERFLOW)
    PER_GL_ERROR(STACK_UNDERFLOW)
    PER_GL_ERROR(OUT_OF_MEMORY)
#undef PER_GL_ERROR
    }
    return "unknown error";
}

static void check_gl_error(const char *filename, int lineno, const char *expr) {
    int err = glGetError();
    if (err != GL_NO_ERROR) {
        std::cerr << filename << ":" << lineno << ": " << expr << " failed: " << opengl_errno_name(err) << '\n';
        std::terminate();
    }
}

#define CHECK_GL(x) do { \
    (x); \
    check_gl_error(__FILE__, __LINE__, #x); \
} while (0)


#include <GLFW/glfw3.h> // must be placed behind glad/glad.h
#include <iostream>

static void framebuffer_size_callback(GLFWwindow* window, int width, int height){
    glViewport(0,0,width,height);
    std::cout<<"resize windows width="<<width<<",height="<<height<<std::endl;
}

static void processInput(GLFWwindow *window)
{
    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS){
        std::cout<<"GLFW_KEY_ESCAPE press"<<std::endl;
        glfwSetWindowShouldClose(window, true);
    }
}

const char *vertexShaderSource = "#version 330 core\n"
    "layout (location = 1) in vec4 aPos;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, aPos.w);\n"
    "}\0";
const char *fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";
const char *fragmentShaderSource2 = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(1.0f, 1.0f, 0.0f, 1.0f);\n"
    "}\n\0";

unsigned int VBO, VAO;
unsigned int shaderProgram;
unsigned int VBO2, VAO2;
unsigned int shaderProgram2;

static void render() {
    // render
    // ------
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    // draw our first triangle
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glUseProgram(shaderProgram2);
    glBindVertexArray(VAO2); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
    glDrawArrays(GL_TRIANGLES, 0, 3);
    // glBindVertexArray(0); // no need to unbind it every time 
}

static void prepareShader(){
    // build and compile our shader program
    // ------------------------------------
    // vertex shader
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    // check for shader compile errors
    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // fragment shader
    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    // check for shader compile errors
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // fragment shader
    unsigned int fragmentShader2 = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader2, 1, &fragmentShaderSource2, NULL);
    glCompileShader(fragmentShader2);
    // check for shader compile errors
    glGetShaderiv(fragmentShader2, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader2, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // link shaders
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    // check for linking errors
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }
    // link shaders
    shaderProgram2 = glCreateProgram();
    unsigned int tmp=shaderProgram2;
    glAttachShader(shaderProgram2, vertexShader);
    glAttachShader(shaderProgram2, fragmentShader2);
    glLinkProgram(shaderProgram2);
    // check for linking errors
    glGetProgramiv(shaderProgram2, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram2, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    glDeleteShader(fragmentShader2);

    // set up vertex data (and buffer(s)) and configure vertex attributes
    // ------------------------------------------------------------------
    float vertices1[] = {
        -0.8f, -0.5f, 0.0f, 1.0f, // left  
        -0.0f, -0.5f, 0.0f, 1.0f, // right 
        -0.4f,  0.5f, 0.0f, 1.0f,  // top     
    }; 
    float vertices2[]={
        0.0f, -0.5f, 0.0f, 1.0f, // left  
        0.8f, -0.5f, 0.0f, 1.0f, // right 
        0.4f,  0.5f, 0.0f, 1.0f,  // top 
    };

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_STATIC_DRAW);

    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);

    // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    glBindVertexArray(0); 

    std::cout<<"shaderProgram2 = "<<shaderProgram2<<std::endl;
    glGenVertexArrays(2, &VAO2);
    std::cout<<"shaderProgram2 = "<<shaderProgram2<<std::endl;
    glGenBuffers(2, &VBO2);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    glBindVertexArray(VAO2);

    glBindBuffer(GL_ARRAY_BUFFER, VBO2);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices2), vertices2, GL_STATIC_DRAW);

    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);

    // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    glBindVertexArray(0);


}

int main(){
    if (!glfwInit()) {
        const char *errmsg;
        glfwGetError(&errmsg);
        if (!errmsg) errmsg = "(no error)";
        std::cerr << "failed to initialize GLFW: " << errmsg << '\n';
        return -1;
    }

    // hint the version required: OpenGL 2.0
    constexpr int version = 20;
    glfwWindowHint(GLFW_OPENGL_API, GLFW_OPENGL_API);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, version / 10);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, version % 10);
    if (version >= 33) {
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
    }

    // Create window
    GLFWwindow *window = glfwCreateWindow(800, 600, "Example", NULL, NULL);
    if (!window) {
        const char *errmsg;
        glfwGetError(&errmsg);
        if (!errmsg) errmsg = "(no error)";
        std::cerr << "GLFW failed to create window: " << errmsg << '\n';
        std::cerr << "==============================================\n";
        if (!strcmp(errmsg, "X11: The DISPLAY environment variable is missing")) {
            std::cerr << "You seems not running with graphic display\n";
        } else if (!strcmp(errmsg, "WGL: The driver does not appear to support OpenGL")) {
            std::cerr << "Please consider install an OpenGL driver, or use the mesa driver\n";
        } else if (!strcmp(errmsg, "WGL: Failed to create OpenGL context")) {
            std::cerr << "Your driver seems not supporting the required OpenGL version\n";
        }
        std::cerr << "- If you have a physical graphic card (e.g. NVIDIA), install it from your graphic card vendor official website: http://www.nvidia.com/Download/index.aspx\n";
        std::cerr << "- If you are using Windows, download opengl32.dll from https://pan.baidu.com/s/1TZ6nVJC7DZIuUarZrGJYow?pwd=opgl and place it into the same directory as this executable file (alternatively you may download opengl32sw.dll from Internet and rename it to opengl32.dll to place into the same directory as this executable file)\n";
        std::cerr << "- If you are using Linux or WSL1, install the mesa driver: https://ubuntuhandbook.org/index.php/2021/07/install-latest-mesa-ubuntu-20-04-21-04/";
        std::cerr << "- If you use WSL2, install WSLg: https://learn.microsoft.com/zh-cn/windows/wsl/tutorials/gui-apps\n";
        std::cerr << "- If you are using SSH remote server, try connect it using ssh -X <ip address>\n";
        std::cerr << "- If you are using MacOS, you probably want to use Windows or Linux instead for better OpenGL support\n";
        std::cerr << "- If you are using a Laptop with dual-cards, make sure you have switch to dedicated card (NVIDIA) instead of the integrated card (Intel)\n";
        std::cerr << "==============================================\n";
#ifdef _WIN32
        std::system("pause");
#endif
        glfwTerminate();
        return -1;
    }

    glfwSetFramebufferSizeCallback(window,framebuffer_size_callback);

    glfwMakeContextCurrent(window);

    // Load glXXX function pointers
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
        glfwTerminate();
        std::cerr << "GLAD failed to load GL functions\n";
        return -1;
    }
    std::cerr << "OpenGL version: " << glGetString(GL_VERSION) << '\n';
    GLint nrAttributes;
    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
    std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;
    
    CHECK_GL(glEnable(GL_POINT_SMOOTH));
    CHECK_GL(glEnable(GL_BLEND));
    CHECK_GL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
    CHECK_GL(glPointSize(64.0f));

    glViewport(0,0,800,600);

    prepareShader();

    // start main game loop
    while (!glfwWindowShouldClose(window)) {
        processInput(window);
        // render graphics

        render();

        // refresh screen
        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(window);
        glfwPollEvents();
    }


    // optional: de-allocate all resources once they've outlived their purpose:
    // ------------------------------------------------------------------------
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteProgram(shaderProgram);
    glDeleteProgram(shaderProgram2);
    glfwTerminate();
    return 0;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.