Code Fragment-删掉那些认为有用而注释掉的code。

本文讨论了代码管理中注释与删除的选择问题,通过一个具体的Android源码示例,阐述了为何应直接删除无用代码而非注释掉,并分析了这种做法背后的原因。

本文思想参考自《Clean Code》

在android的源码里,有这样一段code。

    // This is to replace p.setStyle(Style.STROKE); canvas.drawRect() since it
    // doesn't work well with hardware acceleration
//    private void drawEmptyRect(Canvas canvas, Rect r, int color) {
//        int linesIndex = 0;
//        mLines[linesIndex++] = r.left;
//        mLines[linesIndex++] = r.top;
//        mLines[linesIndex++] = r.right;
//        mLines[linesIndex++] = r.top;
//
//        mLines[linesIndex++] = r.left;
//        mLines[linesIndex++] = r.bottom;
//        mLines[linesIndex++] = r.right;
//        mLines[linesIndex++] = r.bottom;
//
//        mLines[linesIndex++] = r.left;
//        mLines[linesIndex++] = r.top;
//        mLines[linesIndex++] = r.left;
//        mLines[linesIndex++] = r.bottom;
//
//        mLines[linesIndex++] = r.right;
//        mLines[linesIndex++] = r.top;
//        mLines[linesIndex++] = r.right;
//        mLines[linesIndex++] = r.bottom;
//        mPaint.setColor(color);
//        canvas.drawLines(mLines, 0, linesIndex, mPaint);
//    }

之前我也有过类似的行为,注释而不是删掉,常常有下面的原因:

  1. 这些code将来可能会用到。
而实际上:
  1. 这些code将来也不会用到。
  2. 这些code将来不能直接用,因为在注释掉的一段时间里,它本来的场景已经不合适。
  3. 这些code需要用到的时候,别人也不敢用,别人不知道你为什么注释掉,不清楚这些code现在有没有问题。
  4. 这些code常常没有用,但是非作者一般不会去删掉,这就会使注释掉的code越来越不适用。
  5. 即便这些code有用,完全可以通过代码控制工具恢复。
所以:对于一些代码直接删掉,而不是注释掉!





#ifndef COLORHEXAGON_H #define COLORHEXAGON_H #include <glad/glad.h> #include <glm/glm.hpp> // 顶点结构:位置 + 颜色 struct HexVertex2 { glm::vec3 position; glm::vec3 color; }; class ColorHexagon { public: ColorHexagon(); ~ColorHexagon(); void initData(); // 初始化顶点数据和 VAO/VBO void renderObject(); // 渲染六边形,绑定调用 private: GLuint VAO, VBO; }; #endif // COLORHEXAGON_H #ifndef COLORTRIANGLE_H #define COLORTRIANGLE_H #include <glad/glad.h> class ColorTriangle { public: ColorTriangle(); ~ColorTriangle(); void render(); private: GLuint VAO; GLuint VBO; GLuint shaderProgram; void initShader(); void initBuffers(); }; #endif // COLORTRIANGLE_H #ifndef DEMO_H_ #define DEMO_H_ #include <glad/glad.h> class Demo { public: Demo(); ~Demo(); private: bool enableCullFace; //是否启用面剔除功能(即不渲染背对摄像机的面) GLenum cullMode; //指定要剔除的面类型:GL_BACK(背面)、GL_FRONT(前面)或 GL_FRONT_AND_BACK(双面) GLenum frontFace; //定义三角形的“正面”方向:GL_CCW(逆时针为正,默认),GL_CW(顺时针为正) protected: const char* vertexShaderSource; //顶点着色器的 GLSL 源代码字符串 const char* fragmentShaderSource; //默认片段着色器的 GLSL 源代码字符串 const char* fragmentShader1Source; //可选的第二种片段着色器源码(例如不同光照模型) const char* fragmentShader2Source; //可选的第三种片段着色器源码(例如边缘检测、颜色变换等) public: virtual void setRenderParameter(bool enableCullFace = false, GLenum cullMode = GL_FRONT, GLenum frontFace = GL_CCW); //补注释 virtual void beginRender(); // 开始渲染前调用,用于应用当前设置的渲染状态(如启用/禁用面剔除) virtual void render() = 0; // 纯虚函数:子类必须实现具体的渲染逻辑(如绘制几何体、使用着色器等) }; #endif #pragma once #include "Rectangle.h" #include "Demo.h" class Demo3_2:public Demo { public: Demo3_2(); ~Demo3_2(); private: Rectangle rect; //表示一个具体的矩形对象实例 // 注释:该成员变量封装了顶点数据、缓冲区(VBO/VAO)、着色器以及绘制逻辑在 render() 中会被调用来实际绘制矩形 public: void render(); //重写基类的纯虚函数,实现本 demo 的具体渲染逻辑 // 注释:在此函数中会调用 beginRender() 设置 OpenGL 状态,然后调用 rect.render() 执行矩形的绘制操作 }; #pragma once #include "FivePointedStar.h" #include "Demo.h" class Demo3_3 :public Demo { public: Demo3_3(); ~Demo3_3(); private: FivePointedStar fivePointedStar; //表示一个五角星对象实例 // 注释:该成员封装了五角星的顶点数据、缓冲对象(VBO/VAO)以及渲染逻辑。在 render() 中将调用其自身的 render 方法进行绘制 public: void render(); //重写基类的纯虚函数,实现本 demo 的具体渲染行为 // 注释:在此函数中首先调用 beginRender() 设置 OpenGL 状态(如面剔除)然后调用 fivePointedStar.render() 来实际绘制五角星 }; #pragma once #include "Object.h" #include <GLFW/glfw3.h> #include <glm/glm.hpp> class FivePointedStar : public Object { public: FivePointedStar(); ~FivePointedStar(); private: float x; //五角星中心点的 X 坐标 float y; //五角星中心点的 Y 坐标 double t; //当前时间(或累计动画时间),用于控制动画状态(如旋转角度随时间变化) float rotateSpeed; //旋转速度,决定五角星绕自身中心旋转的快慢 ColorVertex fivePointedStar[12]; //存储构成五角星的 12 个顶点数据 // 注释:每个顶点包含位置 (x, y) 和颜色 (r, g, b)使用三角扇(GL_TRIANGLE_FAN)方式连接,形成封闭五角星 public: virtual void initData(); //初始化顶点数据:设置五角星的几何形状、初始颜色、中心位置等 // 在 OpenGL 中通常也负责创建并绑定 VAO/VBO,上传初始顶点数据到 GPU virtual void update(float dt) {} //更新动画状态:根据时间增量 dt 更新内部参数 virtual void renderObject(); //执行实际绘制操作:绑定着色器、VAO,并调用 glDrawArrays(GL_TRIANGLE_FAN, 0, 12)实现五角星在屏幕上的渲染 void updateDataBuffer(); //将更新后的顶点数据(如旋转后的新坐标)重新上传到 GPU 的 VBO 缓冲区用于支持动态变形或动画效果(如持续旋转) void calcData(); //根据当前状态(x, y, t, rotateSpeed 等)重新计算五角星各个顶点的坐标和颜色是生成五角星几何结构的核心函数,通常被 initData() 和 update() 调用 }; // Hexagon.h #pragma once #include "Object.h" #include <glm/glm.hpp> struct HexVertex { glm::vec3 position; glm::vec3 color; }; class Hexagon { private: unsigned int VAO, VBO; public: Hexagon(); ~Hexagon(); void initData(); // 用于初始化六边形的顶点数据并上传至 GPU。 void renderObject(); // 用于执行绘制命令。 void updateDataBuffer(); //声明一个更新缓冲区数据的函数。 }; // Hexagon2.h #pragma once #include "Object.h" #include <glm/glm.hpp> struct Hex2Vertex { glm::vec3 position; glm::vec3 color; }; class Hexagon2 { private: unsigned int VAO, VBO; public: Hexagon2(); ~Hexagon2(); void initData(); // 用于初始化六边形的顶点数据并上传至 GPU。 void renderObject(); // 用于执行绘制命令。 void updateDataBuffer(); //声明一个更新缓冲区数据的函数。 }; #pragma once #include "Demo.h" #include "Triangle.h" class Lab3_2:public Demo { public: Lab3_2(); ~Lab3_2(); private: Triangle leftTriangle; //左侧三角形对象实例 // 注释:封装了左侧三角形的顶点数据、颜色、VBO/VAO 及其渲染逻辑在 render() 中会被调用以绘制位于屏幕左侧的三角形 Triangle rightTriangle; //右侧三角形对象实例 // 注释:与 leftTriangle 类似,但可能具有不同的顶点位置或颜色用于对比测试面剔除(Culling)对不同朝向三角形的影响 bool enableCullFace; //是否启用背面剔除功能的开关标志 // 注释:若为 true,则调用 glEnable(GL_CULL_FACE);否则调用 glDisable(GL_CULL_FACE)控制是否剔除不可见面(提升性能并观察渲染效果变化) GLenum cullMode; //指定要剔除的面(正面或背面) //可取值:GL_BACK -> 剔除背面 // GL_FRONT -> 剔除正面 // GL_FRONT_AND_BACK -> 正反面都剔除(整个物体不可见) // 该值将传递给 glCullFace(cullMode) GLenum frontFace; // 定义哪一侧为“正面”(顺时针或逆时针) //可取值:GL_CCW -> 逆时针方向的多边形被视为正面(默认) // GL_CW -> 顺时针方向的多边形被视为正面 // 该值将传递给 glFrontFace(frontFace),影响面剔除判断结果 public: void render(); //重写基类的纯虚函数,执行本实验的具体渲染流程 // 注释:在此函数中: // 1. 调用 beginRender() 设置全局渲染状态 // 2. 根据 enableCullFace 决定是否启用面剔除 // 3. 设置 cullMode 和 frontFace // 4. 分别调用 leftTriangle.render() 和 rightTriangle.render() 绘制两个三角形 }; #pragma once #include <string> #include <glad/glad.h> #include <glm/glm.hpp> #include "Shader.h" using namespace std; typedef struct { float x; float y; float z; }Vertex; //表示三维空间中的一个点,仅包含位置坐标 (x, y, z) typedef struct { glm::vec3 coordinate; glm::vec4 color; } ColorVertex; //包含位置和颜色数据的顶点,用于支持逐顶点着色 class Object { public: Object(); Object(const char* vs, const char* fs);//构造函数重载:传入顶点着色器和片段着色器路径来创建着色器 virtual ~Object(); public: void createShader(const char* vs, const char* fs); // 创建并编译着色器程序,输入为顶点和片段着色器文件路径 protected: GLvoid* vertices; //指向顶点数据的指针(可以是 Vertex 或 ColorVertex 数组),将被上传到 GPU 的 VBO GLuint verticesSize; //顶点数据的总字节数(例如:sizeof(ColorVertex) * 顶点数量) GLuint indexSize; //索引数组的元素个数(用于 EBO 绘制时指定索引数量) GLuint VBO, VAO, EBO; //OpenGL 缓冲对象标识符 Shader* shader; //指向使用的着色器程序对象,用于在渲染时激活着色器 protected: GLsizei stride; void createBuffer(GLsizei stride,GLenum ussage); //创建并初始化 VAO/VBO/EBO 缓冲区 // stride: 每个顶点的字节大小,用于 glVertexAttribPointer 设置步长 // usage: 数据使用方式(如 GL_STATIC_DRAW, GL_DYNAMIC_DRAW) public: virtual void initData() = 0; //纯虚函数:子类必须实现,用于初始化顶点和索引数据 virtual void render(); //提供默认实现:绑定着色器 -> 更新数据 -> 渲染对象 virtual void update(float dt) = 0; //纯虚函数:每帧更新逻辑(如动画、变换),dt 为时间增量 virtual void updateDataBuffer(); //可选实现:更新 VBO 中的数据(用于动态变化的顶点) virtual void renderObject() = 0; //纯虚函数:具体渲染调用(如 glDrawArrays 或 glDrawElements) virtual void setShaderString(const char* vs, const char* fs); // 设置新的着色器源文件路径(可重新加载着色器) }; #pragma once #include "Object.h" class Rectangle : public Object { public: Rectangle(); ~Rectangle(); private: float x; //矩形中心点(或左下角)的 X 坐标 float y; //矩形中心点(或左下角)的 Y 坐标 // 注释:具体是中心还是角落取决于顶点生成方式,在 initData() 中确定 public: virtual void initData(); //初始化矩形的顶点数据和 OpenGL 资源 // 功能包括: // - 计算四个顶点(或两个三角形共6个顶点)的坐标 // - 创建并配置 VAO、VBO // - 将顶点数据上传到 GPU 缓冲区 // - 可能设置默认颜色或纹理坐标 virtual void update(float dt) {} // 更新逻辑回调函数(当前为空实现) // 注释:用于处理动画或状态变化(如移动、缩放) // 可在此处更新 x, y 实现平移,然后调用 calcData 或 updateDataBuffer // 默认不执行任何操作,子类可根据需要重写 virtual void renderObject(); //执行矩形的实际绘制操作 // 功能包括: // - 绑定已创建的着色器程序 // - 绑定 VAO // - 调用 glDrawArrays(GL_TRIANGLES, 0, 6) 或 glDrawElements // - 渲染由两个三角形组成的矩形 }; #pragma once //#ifndef SHADER_H //#define SHADER_H #include <glad/glad.h> #include <glm/glm.hpp> #include <string> #include <fstream> #include <sstream> #include <iostream> class Shader { public: unsigned int ID; Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr) { // 1. retrieve the vertex/fragment source code from filePath std::string vertexCode; std::string fragmentCode; std::string geometryCode; std::ifstream vShaderFile; std::ifstream fShaderFile; std::ifstream gShaderFile; // ensure ifstream objects can throw exceptions: vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); try { // open files vShaderFile.open(vertexPath); fShaderFile.open(fragmentPath); std::stringstream vShaderStream, fShaderStream; // read file's buffer contents into streams vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); // close file handlers vShaderFile.close(); fShaderFile.close(); // convert stream into string vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); // if geometry shader path is present, also load a geometry shader if (geometryPath != nullptr) { gShaderFile.open(geometryPath); std::stringstream gShaderStream; gShaderStream << gShaderFile.rdbuf(); gShaderFile.close(); geometryCode = gShaderStream.str(); } } catch (std::ifstream::failure e) { std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; } const char* vShaderCode = vertexCode.c_str(); const char * fShaderCode = fragmentCode.c_str(); unsigned int vertex, fragment; // vertex shader vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, &vShaderCode, NULL); glCompileShader(vertex); checkCompileErrors(vertex, "VERTEX"); // fragment Shader fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, &fShaderCode, NULL); glCompileShader(fragment); checkCompileErrors(fragment, "FRAGMENT"); // if geometry shader is given, compile geometry shader unsigned int geometry; if (geometryPath != nullptr) { const char * gShaderCode = geometryCode.c_str(); geometry = glCreateShader(GL_GEOMETRY_SHADER); glShaderSource(geometry, 1, &gShaderCode, NULL); glCompileShader(geometry); checkCompileErrors(geometry, "GEOMETRY"); } // shader Program ID = glCreateProgram(); glAttachShader(ID, vertex); glAttachShader(ID, fragment); if (geometryPath != nullptr) glAttachShader(ID, geometry); glLinkProgram(ID); checkCompileErrors(ID, "PROGRAM"); // delete the shaders as they're linked into our program now and no longer necessery glDeleteShader(vertex); glDeleteShader(fragment); if (geometryPath != nullptr) glDeleteShader(geometry); } // activate the shader // ------------------------------------------------------------------------ void use() { glUseProgram(ID); } // utility uniform functions // ------------------------------------------------------------------------ void setBool(const std::string &name, bool value) const { glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); } // ------------------------------------------------------------------------ void setInt(const std::string &name, int value) const { glUniform1i(glGetUniformLocation(ID, name.c_str()), value); } // ------------------------------------------------------------------------ void setFloat(const std::string &name, float value) const { glUniform1f(glGetUniformLocation(ID, name.c_str()), value); } // ------------------------------------------------------------------------ void setVec2(const std::string &name, const glm::vec2 &value) const { glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); } void setVec2(const std::string &name, float x, float y) const { glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y); } // ------------------------------------------------------------------------ void setVec3(const std::string &name, const glm::vec3 &value) const { glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); } void setVec3(const std::string &name, float x, float y, float z) const { glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z); } // ------------------------------------------------------------------------ void setVec4(const std::string &name, const glm::vec4 &value) const { glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); } void setVec4(const std::string &name, float x, float y, float z, float w) { glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w); } // ------------------------------------------------------------------------ void setMat2(const std::string &name, const glm::mat2 &mat) const { glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); } // ------------------------------------------------------------------------ void setMat3(const std::string &name, const glm::mat3 &mat) const { glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); } // ------------------------------------------------------------------------ void setMat4(const std::string &name, const glm::mat4 &mat) const { glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); } private: // utility function for checking shader compilation/linking errors. // ------------------------------------------------------------------------ void checkCompileErrors(GLuint shader, std::string type) { GLint success; GLchar infoLog[1024]; if (type != "PROGRAM") { glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(shader, 1024, NULL, infoLog); std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; } } else { glGetProgramiv(shader, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shader, 1024, NULL, infoLog); std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; } } } }; //#endif#pragma once #include <glad/glad.h> #include <string> #include <iostream> using namespace std; class Shader { public: unsigned int id; //着色器程序(Program Object)的唯一标识符(OpenGL ID) Shader() { id = 0; } Shader(const char* vs, const char* fs) { unsigned int vertex, fragment; //临时变量,分别存储顶点着色器和片段着色器的 OpenGL 对象 ID // 注释- vertex: 通过 glCreateShader(GL_VERTEX_SHADER) 创建,- fragment: 通过 glCreateShader(GL_FRAGMENT_SHADER) 创建它们是独立编译的着色器单元,在链接前不会生效 vertex = glCreateShader(GL_VERTEX_SHADER); //创建一个顶点着色器对象,该对象将用于加载、编译顶点着色器源代码 fragment = glCreateShader(GL_FRAGMENT_SHADER); //创建一个片段着色器对象,用于处理像素颜色计算(光栅化后) id = glCreateProgram(); //创建一个着色器程序对象,所有着色器必须附加到此程序才能链接运行链接成功后,可通过 glUseProgram(id) 启用整个管线 glShaderSource(vertex, 1, &vs,nullptr); //将 C++ 字符串 vs(顶点着色器源码)绑定到 vertex 着色器对象 glCompileShader(vertex); //编译顶点着色器,将之前设置的源码编译成 GPU 可执行的形式,若语法错误则编译失败,需调用 checkCompileErrors 检查 checkCompileErrors(vertex, "VERTEX"); //检查顶点着色器是否编译成功如果失败,打印详细的错误日志到控制台 glShaderSource(fragment, 1, &fs, nullptr); //将 fs 字符串作为源码传入片段着色器对象 glCompileShader(fragment); //编译片段着色器 checkCompileErrors(fragment, "FRAGMENT"); //检查片段着色器编译状态 glAttachShader(id, vertex); //将已编译的顶点着色器附加到程序对象 id 上 glAttachShader(id, fragment); //将已编译的片段着色器附加到程序对象 id 上 glLinkProgram(id); //链接着色器程序把所有附加的着色器合并为一个可执行程序检查接口匹配性(如 vs 输出与 fs 输入)、全局符号等成功后方可使用 glDeleteShader(vertex); //链接完成后,删除临时的顶点着色器对象 glDeleteShader(fragment); // 删除临时的片段着色器对象 } void use() { glUseProgram(id); //激活当前着色器程序使 OpenGL 渲染管线使用这个 program 进行绘制后续 draw call 都会使用该着色器逻辑 } private: void checkCompileErrors(GLuint shader, std::string type) //用于检查着色器编译或程序链接是否出错 { GLint success; GLchar infoLog[1024]; if (type != "PROGRAM") { glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(shader, 1024, NULL, infoLog); std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; } } else { glGetProgramiv(shader, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shader, 1024, NULL, infoLog); std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; } } } }; #pragma once #include "Object.h" class Triangle: public Object { public: Triangle(); ~Triangle(); public: virtual void initData() ; //虚函数:初始化与三角形相关的 GPU 数据(如顶点数组、缓冲对象 VAO/VBO) // 通常在此函数中: // - 创建并绑定 VAO 和 VBO // - 上传顶点数据到 GPU // - 配置顶点属性指针(vertex attribute pointers) // 子类可重写此函数以自定义初始化逻辑 virtual void update(float dt) {} //虚函数:更新三角形的逻辑状态,参数 dt 为帧间时间间隔(delta time),单位秒 // 虚函数:更新三角形的逻辑状态,参数 dt 为帧间时间间隔(delta time),单位秒 // 用于实现动画、变换矩阵更新等随时间变化的操作 // 当前为空实现({}),表示默认无需更新;子类可根据需要重写 virtual void renderObject(); //虚函数:执行三角形的渲染操作 // 通常包括: // - 激活着色器程序 // - 绑定 VAO // - 调用 glDrawArrays 或类似绘制命令 // 实现从 GPU 中绘制该三角形到屏幕的过程 void setData(Vertex* data, int size); //设置三角形的顶点数据 // 参数: // - Vertex* data: 指向顶点数据数组的指针(包含位置、颜色、纹理坐标等) // - int size: 顶点数量 // 功能:将 CPU 端的顶点数据传入 Triangle 对象,供后续上传至 GPU 使用 void setShaderString(const char* vs, const char* fs); //设置用于渲染三角形的着色器源码 // 参数: // - const char* vs: 顶点着色器(Vertex Shader)的源代码字符串 // - const char* fs: 片段着色器(Fragment Shader)的源代码字符串 // 功能:保存着色器代码,在初始化时用于创建和编译 Shader 程序 }; #pragma once #ifndef VERTEX_H #define VERTEX_H #include <glm/glm.hpp> struct ColorVertex { glm::vec3 coordinate; glm::vec4 color; }; #endif // VERTEX_H #pragma once #ifndef WAVEHEXAGON_H #define WAVEHEXAGON_H #include <glad/glad.h> // 顶点结构:位置 + 颜色 struct HexVertex3 { float position[3]; float color[3]; // 颜色,用于在 shader 中调制 }; class WaveHexagon { public: WaveHexagon(); ~WaveHexagon(); void init(); // 初始化 VAO/VBO 和着色器 void render(); // 渲染并传入时间 uniform void destroy(); // 释放资源 private: GLuint VAO, VBO; GLuint shaderProgram; GLint uniTime; // uniform location: u_Time }; #endif // WAVEHEXAGON_H 这里是所有.h的头文件,.cpp的文件我现在再发给你
10-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值