Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用OpenGL绘制彩色网格?_Opengl - Fatal编程技术网

用OpenGL绘制彩色网格?

用OpenGL绘制彩色网格?,opengl,Opengl,我的目标是能够创建所谓的占用网格,它类似于瓷砖/网格游戏,看起来像附加的图像。这是一个小机器人项目,我正在工作。所有这些都是在C/C++中完成的 因此,我希望能够: 更改每个栅格单元的分辨率或大小。例如1x1cm或5x5cm等 根据某些条件更改每个单元格的颜色。障碍==黑色,自由==白色,等等。可能会添加用户单击单元格并更改颜色。例如,如果机器人在0x0启动,单元格为红色,则下一个实例移动到1x1。现在0x0应该是白色,1x1应该是红色 添加某种形式的滚动或跟随(可能通过MVP摄像头完成) 我应

我的目标是能够创建所谓的占用网格,它类似于瓷砖/网格游戏,看起来像附加的图像。这是一个小机器人项目,我正在工作。所有这些都是在C/C++中完成的

因此,我希望能够:

  • 更改每个栅格单元的分辨率或大小。例如1x1cm或5x5cm等
  • 根据某些条件更改每个单元格的颜色。障碍==黑色,自由==白色,等等。可能会添加用户单击单元格并更改颜色。例如,如果机器人在0x0启动,单元格为红色,则下一个实例移动到1x1。现在0x0应该是白色,1x1应该是红色
  • 添加某种形式的滚动或跟随(可能通过MVP摄像头完成)
  • 我应该采用什么OpenGL方法/方法?我目前正在考虑:

  • 具有带有颜色属性的方形着色器(两个三角形顶点和索引缓冲区)。然后有一个包含所有标记和颜色的顶点数组对象/缓冲区,但不知道如何在运行时处理更改的颜色

  • 为每个栅格提供所有真实世界的中心或角点坐标(0x0、0x1、…1x1等),并让着色器绘制各个正方形(如果可能)

  • 使用NxN的纹理/图像并更新纹理像素颜色

  • 我只是不确定什么是最好的可扩展或性能方法。如果我想画一个10000x1000网格单元(例如,缩小到很远),或者如果颜色变化很大,该怎么办

    栅格最具动态性的方面是填充颜色。例如,我可能有一个100x100的网格。有一次,所有的细胞都是白色的,当机器人移动时,我会改变相应细胞的颜色。或者,如果检测到单元中有障碍物,请更改该单元的颜色


    我想出了一些你应该在项目中使用的东西。它是一个可缩放的网格,可以调整大小到您需要的任何尺寸。它应该相对较快,行被批处理,四边形被实例化。它与左键和右键单击以及滚轮单击和滚动进行基本交互,但是您应该能够根据需要调整此界面。API应该非常易于使用
    createCell
    removeCell
    ,等等

    有几件事:

    • 该应用程序不会渲染不在视锥体中的单元格,因此放大时性能更好,尽管也有一些黑客可以让它在缩小时以相当快的速度工作
    • 我只能测试1000x1000个正方形(~10-12fps完全缩小),我没有足够的内存来存储10000x1000个正方形(使用~3GB)
    这是有趣的,我希望你能利用它,如果你有任何问题让我知道

    编辑: 是的,
    flatte
    部分有点无结构。这种展平方法最初只是将2D模型向量展平为1D向量,然后发送到GPU(内部
    \U模型
    数据)。三元操作确定该列表的2D切片(想想主栅格中的方框部分),这就是平截头体剔除的发生方式。 bottomLeft和topRight用于计算相机平截头体的边界框,该边界框与整个网格相交,以获得模型和颜色(有序)向量的索引,该向量发送到GPU,虽然有一定的技巧,但它确保与网格交互的操作(添加、删除、更改颜色等)为O(1)。 有一个小错误导致某些单元格冻结,这是由于在QuadRenderer的
    remove()
    方法中将单元格重置为未初始化而导致的,该方法忽略了将其发送到GPU(一种节省性能的优化),并导致内存偏移错误,导致渲染取消同步。因此,有两种方法可以解决这个问题:取消检查,只向GPU发送初始化的单元格(速度较慢),或者将方块设置为白色(hackier)。所以我选择将移除的细胞设置为白色,这意味着它们仍然被渲染(即使它们是用清晰的颜色伪装的)。您可能可以进行更改,使白色单元格也不会被渲染,但考虑到您保持单元格未初始化以开始(看在上帝的份上,不要将其初始化为白色!),性能不会损失太多

    可以将remove()函数更改为:

    void remove(vec2 pos) { 
    
        //change color to white 
        colors[(int)pos.x][(int)pos.y] = vec3(1); 
    
    }
    

    代码如下:

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    #include <glad/glad.h>
    #include <GLFW/glfw3.h>
    #define GLM_ENABLE_EXPERIMENTAL
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtx/string_cast.hpp>
    
    using std::vector;
    using std::cout;
    using std::endl;
    using glm::mat4;
    using glm::vec2;
    using glm::vec3;
    using glm::vec4;
    using glm::perspective;
    using glm::radians;
    using glm::normalize;
    
    void processInput(GLFWwindow *window);
    void mouse_callback(GLFWwindow* window, double xpos, double ypos);
    void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
    void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
    
    // settings
    const unsigned int SCR_WIDTH = 800;
    const unsigned int SCR_HEIGHT = 600;
    
    // grid dimensions
    const unsigned int GRID_WIDTH = 1000;
    const unsigned int GRID_HEIGHT = 1000;
    
    float lastX = SCR_WIDTH / 2.0f;
    float lastY = SCR_HEIGHT / 2.0f;
    bool firstMouse = true;
    bool realTimeUpdating = true;
    
    // timing
    float deltaTime = 0.0f;
    float lastFrame = 0.0f;
    
    // TO DO a simple camera class
    vec3 cameraPos = vec3(0.0f, 0.0f, 0.0f);
    vec3 cameraFront = vec3(0,0,-1);
    vec3 cameraRight = vec3(1,0,0);
    vec3 cameraUp = vec3(0,1,0);
    mat4 model = mat4(1.0);
    mat4 view;
    mat4 projection;
    float scrollSpeed = 2.0f;
    float fov = 90.0f;
    float nearDist = 0.1f;
    float farDist = 1000.0f;
    float ar = (float)SCR_WIDTH / (float)SCR_HEIGHT;
    
    class LineRenderer {
        int shaderProgram;
        unsigned int VBO, VAO;
        mat4 viewProjection;
    
        vector<float> vertices;
    public:
        LineRenderer() {
    
            const char *vertexShaderSource = "#version 330 core\n"
                "layout (location = 0) in vec3 aPos;\n"
                "uniform mat4 viewProjection;\n"
                "void main()\n"
                "{\n"
                "   gl_Position = viewProjection * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
                "}\0";
            const char *fragmentShaderSource = "#version 330 core\n"
                "out vec4 FragColor;\n"
                "void main()\n"
                "{\n"
                "   FragColor = vec4(0,0,0,1);\n"
                "}\n\0";
    
            // vertex shader
            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);
                cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl;
            }
            // fragment shader
            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);
                cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << 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);
                cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << endl;
            }
            glDeleteShader(vertexShader);
            glDeleteShader(fragmentShader);
    
            vector<float> placeHolderVertices = {
            };
    
            vertices.insert( vertices.end(), placeHolderVertices.begin(), placeHolderVertices.end() );
            glGenVertexArrays(1, &VAO);
            glGenBuffers(1, &VBO);
            glBindVertexArray(VAO);
    
            glBindBuffer(GL_ARRAY_BUFFER, VBO);
            glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
    
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
            glEnableVertexAttribArray(0);
    
            glBindBuffer(GL_ARRAY_BUFFER, 0); 
            glBindVertexArray(0); 
    
        }
    
        void setCamera(mat4 cameraMatrix) {
            viewProjection = cameraMatrix;
        }
    
        void addLine(vec3 start, vec3 end) {
            vector<float> lineVertices = {
                 start.x, start.y, start.z,
                 end.x, end.y, end.z,
    
            };
    
            vertices.insert( vertices.end(), lineVertices.begin(), lineVertices.end() );
            glBindVertexArray(VAO);
            glBindBuffer(GL_ARRAY_BUFFER, VBO);
            glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
        }
    
        int draw() {
            glUseProgram(shaderProgram);
            glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "viewProjection"), 1, GL_FALSE, &viewProjection[0][0]);
    
            glBindVertexArray(VAO);
            glDrawArrays(GL_LINES, 0, vertices.size() / 3);
            return 0;
        }
    };
    
    // maths functions to pick which grid (not necessary, just for demonstration purposes)
    
    vec3 rayCast(double xpos, double ypos, mat4 projection, mat4 view) {
        // converts a position from the 2d xpos, ypos to a normalized 3d direction
        float x = (2.0f * xpos) / SCR_WIDTH - 1.0f;
        float y = 1.0f - (2.0f * ypos) / SCR_HEIGHT;
        float z = 1.0f;
        vec3 ray_nds = vec3(x, y, z);
        vec4 ray_clip = vec4(ray_nds.x, ray_nds.y, -1.0f, 1.0f);
        // eye space to clip we would multiply by projection so
        // clip space to eye space is the inverse projection
        vec4 ray_eye = inverse(projection) * ray_clip;
        // convert point to forwards
        ray_eye = vec4(ray_eye.x, ray_eye.y, -1.0f, 0.0f);
        // world space to eye space is usually multiply by view so
        // eye space to world space is inverse view
        vec4 inv_ray_wor = (inverse(view) * ray_eye);
        vec3 ray_wor = vec3(inv_ray_wor.x, inv_ray_wor.y, inv_ray_wor.z);
        ray_wor = normalize(ray_wor);
        return ray_wor;
    }
    
    vec3 rayPlaneIntersection(vec3 ray_position, vec3 ray_direction, vec3 plane_normal, vec3 plane_position) {
        float d = dot(plane_normal, plane_position - ray_position) / (0.001+dot(ray_direction, plane_normal));
        return ray_position + ray_direction * d;
    }
    
    template<typename T>
    vector<T> flatten(const vector<vector<T>> &orig, vec2 bottomLeft=vec2(0,0), vec2 topRight=vec2(GRID_WIDTH, GRID_HEIGHT))
    {   
        vector<T> ret;
        // for(const auto &v: orig)
        //     ret.insert(ret.end(), v.begin(), v.end());
        float rx = (topRight.x >= GRID_WIDTH ? GRID_WIDTH : topRight.x+1);
        float ry = (topRight.y >= GRID_HEIGHT ? GRID_HEIGHT : topRight.y+1);
    
        float lx = (bottomLeft.x <= 0 ? 0 : bottomLeft.x);
        float ly = (bottomLeft.y <= 0 ? 0 : bottomLeft.y);
    
        for(int i = lx; i < rx; i++) {
            vector<T> v = orig[i];
            ret.insert(ret.end(), v.begin()+ly, v.begin() + ry);                                                                                          
        }
        return ret;
    }   
    
    class QuadRenderer {
    
    public:
    
        unsigned int shaderProgram;
        unsigned int VBO, VAO, EBO;
    
        unsigned int matrixBuffer;
        unsigned int colorBuffer;
    
        vector<vector<vec3>> colors;
        vector<vector<vec3>> frustumCulledColors;   
        vector<vec3> _colors;
    
        vector<vector<mat4>> models;
        vector<vector<mat4>> frustumCulledModels;
        vector<mat4> _models;
    
        mat4 viewProjection;
    
        vec2 bottomLeft=vec2(0,0);
        vec2 topRight=vec2(GRID_WIDTH, GRID_HEIGHT);
    
        QuadRenderer() {
    
            // create an empty grid
            colors.resize(GRID_WIDTH);
            for (int j = 0; j < GRID_WIDTH; j++) {
                colors[j].resize(GRID_HEIGHT);
                std::fill(colors[j].begin(),colors[j].end(),vec3(0));
            }
    
            models.resize(GRID_WIDTH);
            for (int j = 0; j < GRID_WIDTH; j++) {
                models[j].resize(GRID_HEIGHT);
                std::fill(models[j].begin(),models[j].end(),mat4(0));
            }
    
            const char *vertexShaderSource = "#version 330 core\n"
            "layout (location = 0) in vec3 aPos;\n"
            "layout (location = 1) in mat4 aInstanceMatrix;\n"
            "layout (location = 5) in vec3 aCol\n;"
            "uniform mat4 viewProjection;\n"
            "out vec3 color;\n"
            "void main()\n"
            "{\n"
            "   gl_Position = viewProjection * aInstanceMatrix * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
            "   color = aCol;\n"
            "}\0";
        const char *fragmentShaderSource = "#version 330 core\n"
            "out vec4 FragColor;\n"
            "in vec3 color;\n"
            "void main()\n"
            "{\n"
            "   FragColor = vec4(color,1);\n"
            "}\n\0";
    
            // 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);
                cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << 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);
                cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << 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);
                cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << endl;
            }
            glDeleteShader(vertexShader);
            glDeleteShader(fragmentShader);
    
            float vertices[] = {
                 1.0f,  1.0f, 0.0f,  // top right
                 1.0f,  0.0f, 0.0f,  // bottom right
                 0.0f,  0.0f, 0.0f,  // bottom left
                 0.0f,  1.0f, 0.0f   // top left 
            };
    
            unsigned int indices[] = {  // note that we start from 0!
                0, 1, 3,  // first Triangle
                1, 2, 3   // second Triangle
            };
    
            _models = flatten(models);
            _colors = flatten(colors);
    
            glGenVertexArrays(1, &VAO);
            glGenBuffers(1, &VBO);
            glGenBuffers(1, &EBO);
            glGenBuffers(1, &matrixBuffer);
            glGenBuffers(1, &colorBuffer);
    
            // 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(vertices), vertices, GL_STATIC_DRAW);
    
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
            glEnableVertexAttribArray(0);
    
            glBindBuffer(GL_ARRAY_BUFFER, 0); 
    
    
            glBindBuffer(GL_ARRAY_BUFFER, matrixBuffer);
            glBufferData(GL_ARRAY_BUFFER, _models.size() * sizeof(mat4), &_models.front(), GL_STATIC_DRAW);
    
            // set attribute pointers for matrix (4 times vec4)
    
            glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(mat4), (void*)0);
            glEnableVertexAttribArray(1);
    
            glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(mat4), (void*)(sizeof(vec4)));
            glEnableVertexAttribArray(2);
    
    
            glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(mat4), (void*)(2 * sizeof(vec4)));
            glEnableVertexAttribArray(3);
    
            glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(mat4), (void*)(3 * sizeof(vec4)));
            glEnableVertexAttribArray(4);
    
            glVertexAttribDivisor(1, 1);
            glVertexAttribDivisor(2, 1);
            glVertexAttribDivisor(3, 1);
            glVertexAttribDivisor(4, 1);
    
            glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
    
            glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
            glBufferData(GL_ARRAY_BUFFER, _colors.size() * sizeof(vec3), &_colors.front(), GL_STATIC_DRAW);
    
            glVertexAttribPointer(5, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
            glEnableVertexAttribArray(5);
            glVertexAttribDivisor(5, 1);
    
            glBindBuffer(GL_ARRAY_BUFFER, 0); 
            glBindVertexArray(0); 
        }
    
        void calculateFrustum() {
            vec3 rayWorld = rayCast(0, SCR_HEIGHT, projection, view);
            vec3 worldPos = rayPlaneIntersection(cameraPos, rayWorld, vec3(0,0,1), vec3(0,0,0));
            bottomLeft = vec2((int)worldPos.x, (int)worldPos.y);
    
            rayWorld = rayCast(SCR_WIDTH, 0, projection, view);
            worldPos = rayPlaneIntersection(cameraPos, rayWorld, vec3(0,0,1), vec3(0,0,0));
            topRight = vec2((int)worldPos.x, (int)worldPos.y);
        }
    
        // send updated data to GPU
        void update() {
            _models = flatten(models, bottomLeft, topRight);
            _colors = flatten(colors, bottomLeft, topRight);
    
            vector<mat4> shadedCellModels = {};
            vector<vec3> shadedCellColors = {};
    
            for (int i = 0; i < _models.size(); i++) {
                // only send initialized cells to the GPU
                if (_models[i] != mat4(0) && _colors[i] != vec3(0)) {
                    shadedCellModels.push_back(_models[i]);
                    shadedCellColors.push_back(_colors[i]);
                }
            }
    
    
            glBindBuffer(GL_ARRAY_BUFFER, matrixBuffer);
            glBufferSubData(GL_ARRAY_BUFFER, 0, shadedCellModels.size() * sizeof(mat4), &shadedCellModels.front());
    
            glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
            glBufferSubData(GL_ARRAY_BUFFER, 0, shadedCellColors.size() * sizeof(vec3), &shadedCellColors.front());
        }
    
        void addQuad(vec2 pos, vec3 col) {
    
            mat4 model = translate(mat4(1.0), vec3(pos, 0.0));
            models[(int)pos.x][(int)pos.y] = model;
            colors[(int)pos.x][(int)pos.y] = col;
        }
    
        void remove(vec2 pos) {
            //change color to white
            colors[(int)pos.x][(int)pos.y] = vec3(1);
        }
    
        void setCamera(mat4 cameraMatrix) {
            viewProjection = cameraMatrix;
        }
    
        void draw() {
    
            glUseProgram(shaderProgram);
            glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "viewProjection"), 1, GL_FALSE, &viewProjection[0][0]);
    
            // render quad
            glBindVertexArray(VAO);
            glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0, _models.size()); 
            glBindVertexArray(0);
    
        }
    
    };
    
    vec3 selectedColor = vec3(0,1,0);
    bool leftMouseButtonPressed = false;
    bool rightMouseButtonPressed = false;
    
    class Grid {
    public:
    
        LineRenderer lines;
        QuadRenderer cells;
    
        Grid() {
    
            //glLineWidth(2);
    
            // draw horizontal lines of grid
            for (int j = 0; j <= GRID_HEIGHT; j++) {
                lines.addLine(vec3(0, j, 0), vec3(GRID_WIDTH, j, 0));
            }
            // draw vertical lines of grid
            for (int i = 0; i <= GRID_WIDTH; i++) {
                lines.addLine(vec3(i, 0, 0), vec3(i,GRID_HEIGHT, 0));
            };
    
        }
    
        void addCell(vec2 gridPos, vec3 color, bool updateImmediately=true) {
    
            // ignore mouse clicks outside the grid
            if (gridPos.x < 0 || gridPos.x > (GRID_WIDTH -1) || gridPos.y < 0 || gridPos.y > (GRID_HEIGHT -1)) {
                return;
            }
            cells.addQuad(gridPos, color);  
            if (updateImmediately) {
                cells.update();
            }
        }
    
        void removeCell(vec2 gridPos, bool updateImmediately=true) {
    
            // ignore mouse clicks outside the grid
            if (gridPos.x < 0 || gridPos.x > (GRID_WIDTH -1) || gridPos.y < 0 || gridPos.y > (GRID_HEIGHT -1)) {
                return;
            }
            cells.remove(gridPos);
            if (updateImmediately) {
                cells.update();
            }
        }
    
        void draw() {
    
            cells.draw();
            lines.draw(); 
        }
    };
    
    Grid *grid;
    
    int main()
    {
    
        glfwInit();
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    
    #ifdef __APPLE__
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    #endif
    
        GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "grid", NULL, NULL);
        if (window == NULL)
        {
            cout << "Failed to create GLFW window" << endl;
            glfwTerminate();
            return -1;
        }
        glfwMakeContextCurrent(window);
        glfwSetCursorPosCallback(window, mouse_callback);
        glfwSetMouseButtonCallback(window, mouse_button_callback);
        glfwSetScrollCallback(window, scroll_callback);
    
        if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
        {
            cout << "Failed to initialize GLAD" << endl;
            return -1;
        }
    
        grid = new Grid();
        for (int i = 0; i < GRID_WIDTH; i++) {
            for (int j = 0; j < GRID_HEIGHT; j++) {
                // when setting up grid have updateImmediately=false
                // and batch update once at the end
                grid->addCell(vec2(i,j), vec3(1,0,0), false);
            }
        }
        // batch update
        grid->cells.update();
    
    
        // point camera at center of the grid, 15 units back from the grid
        cameraPos = vec3(GRID_WIDTH/2, GRID_HEIGHT/2, 15.0f);
    
        projection = perspective(radians(fov), ar, nearDist, farDist);
        glClearColor(1.0, 1.0, 1.0, 1.0);
    
        // set camera
        view = lookAt(cameraPos,  cameraPos + cameraFront, vec3(0,1,0));
        grid->cells.setCamera(projection * view);
        grid->lines.setCamera(projection * view);
    
        while (!glfwWindowShouldClose(window))
        {
    
            // float currentFrame = glfwGetTime();
            // deltaTime = currentFrame - lastFrame;
            // lastFrame = currentFrame;
    
            // std::cout << "FPS: " << 1.0/(0.00000001+deltaTime) << std::endl;
            processInput(window);
    
            glClear(GL_COLOR_BUFFER_BIT);
    
            grid->draw();
    
            glfwSwapBuffers(window);
            glfwPollEvents();
        }
    
        glfwTerminate();
    
        delete grid;
    
        return 0;
    }
    
    void processInput(GLFWwindow *window)
    {
        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
            glfwSetWindowShouldClose(window, true);
    
        // ray cast to find quad underneath mouse cursor
    
        if (leftMouseButtonPressed) {
            // cast from camera through mouse position
            vec3 rayWorld = rayCast(lastX, lastY, projection, view);
            // check for intersection with grid
            vec3 worldPos = rayPlaneIntersection(cameraPos, rayWorld, vec3(0,0,1), vec3(0,0,0));
    
            vec2 gridPos = vec2((int)worldPos.x, (int)worldPos.y);
    
            grid->addCell(gridPos, selectedColor);
        } 
        if (rightMouseButtonPressed) {
    
            // cast from camera through mouse position
            vec3 rayWorld = rayCast(lastX, lastY, projection, view);
            // check for intersection with grid
            vec3 worldPos = rayPlaneIntersection(cameraPos, rayWorld, vec3(0,0,1), vec3(0,0,0));
    
            vec2 gridPos = vec2((int)worldPos.x, (int)worldPos.y);
    
            grid->removeCell(gridPos);
        }
    
        if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS)
            selectedColor = vec3(1,0,0);
        if (glfwGetKey(window, GLFW_KEY_2) == GLFW_PRESS)
            selectedColor = vec3(0,1,0);    
        if (glfwGetKey(window, GLFW_KEY_3) == GLFW_PRESS)
            selectedColor = vec3(0,0,1);    
        if (glfwGetKey(window, GLFW_KEY_4) == GLFW_PRESS)
            selectedColor = vec3(1,1,0);  
        if (glfwGetKey(window, GLFW_KEY_5) == GLFW_PRESS)
            selectedColor = vec3(1,0,1);
        if (glfwGetKey(window, GLFW_KEY_6) == GLFW_PRESS)
            selectedColor = vec3(1,1,0);       
    }
    
    
    void mouse_callback(GLFWwindow* window, double xpos, double ypos)
    {
    
        if (firstMouse)
        {
            lastX = xpos;
            lastY = ypos;
            firstMouse = false;
        }
    
        float xoffset = xpos - lastX;
        float yoffset = lastY - ypos; 
    
        lastX = xpos;
        lastY = ypos;
    
        // switch to update less frequently when many squares on the screen
        if (cameraPos.z > 15.0f) {
            realTimeUpdating=false;
        } else {
            realTimeUpdating=true;
        }
    
        // scrolling moves camera closer and further from the grid
        int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_MIDDLE);
        if (state == GLFW_PRESS)
        {
            glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
            cameraPos -= scrollSpeed * vec3(xoffset/(float)SCR_WIDTH, yoffset/(float)SCR_WIDTH, 0);
            // update camera
            view = lookAt(cameraPos,  cameraPos + cameraFront, vec3(0,1,0));
            grid->cells.setCamera(projection * view);
            grid->lines.setCamera(projection * view);
            grid->cells.calculateFrustum();
    
            if (realTimeUpdating) {
                grid->cells.update();
            }
        } else {
            glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
            firstMouse = true;
        }
    }
    
    void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
    {
        scrollSpeed = cameraPos.z * 0.1;
        cameraPos += (float)yoffset * scrollSpeed * rayCast(lastX, lastY, projection, view);
        // update camera
        view = lookAt(cameraPos,  cameraPos + cameraFront, vec3(0,1,0));
        grid->cells.setCamera(projection * view);
        grid->lines.setCamera(projection * view);
        grid->cells.calculateFrustum();
        grid->cells.update();
    }
    
    void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
    {
    
        if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
            leftMouseButtonPressed = true;
        } else {
            leftMouseButtonPressed = false;
        }
    
        if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) {
            rightMouseButtonPressed = true;
        } else {
            rightMouseButtonPressed = false;
        }
    
        if (button == GLFW_MOUSE_BUTTON_MIDDLE && action == GLFW_RELEASE) {
            if (!realTimeUpdating) {
                grid->cells.update();
            }
        }
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #定义GLM_启用_
    #包括
    #包括
    #包括
    使用std::vector;
    使用std::cout;
    使用std::endl;
    使用glm::mat4;
    使用glm::vec2;
    使用glm::vec3;
    使用glm::vec4;
    使用glm::透视图;
    使用glm::弧度;
    使用glm::normalize;
    无效处理输入(GLFWwindow*窗口);
    无效鼠标回调(GLFWwindow*窗口,双XPO,双YPO);
    无效鼠标按钮回调(GLFWwindow*窗口、int按钮、int操作、int mods);
    void scroll_回调(GLFWwindow*窗口,双xoffset,双yoffset);
    //背景
    常量无符号整数SCR_WIDTH=800;
    常数无符号整数SCR_高度=600;
    //网格尺寸
    常量无符号整数网格宽度=1000;
    常量无符号整数网格高度=1000;
    浮动lastX=SCR\U宽度/2.0f;
    浮动弹性=SCR_高度/2.0f;
    bool firstMouse=true;
    bool realTimeUpdating=true;
    //时机
    浮动增量时间=0.0f;
    浮动lastFrame=0.0f;
    //做一个简单的相机类
    vec3-cameraPos=vec3(0.0f,0.0f,0.0f);
    vec3-cameraFront=vec3(0,0,-1);
    vec3 cameraRight=vec3(1,0,0);
    vec3-cameraUp=vec3(0,1,0);
    mat4模型=mat4(1.0);
    mat4视图;
    mat4投影;
    浮动滚动速度=2.0f;
    浮动视野=90.0f;
    浮动近距离=0.1f;
    浮动远距=1000.0f;
    浮动ar=(浮动)SCR_宽度/(浮动)SCR_高度;
    类线条渲染器{
    int着色器程序;
    无符号整数VBO,VAO;
    mat4视图投影;
    向量顶点;
    公众:
    LineRenderer(){
    const char*vertexShaderSource=“#版本330核心\n”
    “vec3 aPos中的布局(位置=0);\n”
    “统一mat4视图投影;\n”
    “void main()\n”
    “{\n