奇异编程 2026-02-18 15:48 采纳率: 50%
浏览 6

opengl代码优化问题

性能问题:
帧率仅35, 经过计时问题在这行代码
glBindFramebuffer(GL_FRAMEBUFFER, shadow_buffer); //这行代码耗费了0.02s!!!


```c++
static void SetupBuffers(GLFWwindow* window, GLuint* buffer, GLuint* depth, GLuint* texture) {
    GLuint buffer_id[1]{};
    glGenBuffers(1, buffer_id);
    glfwGetFramebufferSize(window, &WIDTH, &HEIGHT);
    glGenFramebuffers(1, buffer_id);
    *buffer = buffer_id[0];
    glBindFramebuffer(GL_FRAMEBUFFER, *buffer);
    glGenTextures(1, buffer_id);
    *texture = buffer_id[0];
    glBindTexture(GL_TEXTURE_2D, *texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texture, 0);
    glDrawBuffer(GL_COLOR_ATTACHMENT0);
    glGenTextures(1, buffer_id);
    *depth = buffer_id[0];
    glBindTexture(GL_TEXTURE_2D, *depth);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, WIDTH, HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, *depth, 0);
}
static void init(GLFWwindow* window) {
    camera.vmat = glm::mat4(1.0f);
    camera.tmat = glm::mat4(1.0f);
    camera.rmat = glm::mat4(1.0f);
    camera.pmat = glm::perspective(1.4f, aspect, 2000.0f, 0.2f);
    reflect_camera.vmat = glm::mat4(1.0f);
    reflect_camera.tmat = glm::mat4(1.0f);
    reflect_camera.rmat = glm::mat4(1.0f);
    reflect_camera.pmat = glm::perspective(1.4f, aspect, 2000.0f, 0.2f);
    proj_mat = ortho_matrix(sunshine.direction, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));

    rendering_program = CreateShaderProgram("vert_shader.glsl", "frag_shader.glsl");
    grassland_program = CreateShaderProgram("grass_vert.glsl", "grass_frag.glsl");
    shadow_program = CreateShaderProgram("shadow_vert.glsl", "shadow_frag.glsl");
    water_program = CreateShaderProgram("water_vert.glsl", "water_frag.glsl");
    plain_program = CreateShaderProgram("plain_vert.glsl", "plain_frag.glsl");
    snow_program = CreateShaderProgram("snow_vert.glsl", "snow_frag.glsl");
    sky_program = CreateShaderProgram("sky_vert.glsl", "sky_frag.glsl");
    sky_texture = CreateNoisy3DTexture(glm::vec4(0.0f, 0.5f, 1.0f, 1.0f), glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), 256, MD);
    water_texture = CreateNoisy3DHeight(256, NULL, [](float x, float y, float z) -> float{ return 0.5f * sin(x * 32.0f * PI) * sin(z * 32.0f * PI) - 0.5f; });
    grass_texture = CreateRandom2DTexture(128);
    snow_texture = CreateRandom2DTexture(512);
    SetupBuffers(window, &shadow_buffer, &shadow_depth, &shadow_texture);
    SetupBuffers(window, &reflect_buffer, &reflect_depth, &reflect_texture);
    SetupBuffers(window, &refract_buffer, &refract_depth, &refract_texture);
    glGenVertexArrays(numVAOs, vm.vao);
    glBindVertexArray(vm.vao[0]);
    glGenBuffers(numVBOs, vm.vbo);

    glClearDepth(0.0f);
    glClearColor(0.7f, 0.7f, 0.7f, 1.0f);

    square = CreateSquare(&vm, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f));
    water = CreateSquare(&vm, glm::vec3(0.0f, 1.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));
    snow = CreateSnow(&vm, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec4(0.8f, 0.8f, 0.8f, 1.0f));
    tetrahedron = CreateTetrahedron(&vm, glm::vec3(6.0f, 2.0f, 0.0f), glm::vec4(1.0f, 0.0f, 0.0f, 0.0f));
    icosahedron = CreateIcosahedron(&vm, glm::vec3(6.0f, 4.0f, 0.0f), glm::vec4(1.0f, 0.0f, 0.0f, 0.0f));
    cube = CreateCube(&vm, glm::vec3(6.0f, 6.0f, 0.0f), glm::vec4(1.0f, 0.0f, 0.0f, 0.0f));
    cone = CreateCone(&vm, glm::vec3(6.0f, 8.0f, 0.0f), glm::vec4(1.0f, 0.0f, 0.0f, 1.0f), PI / 6.0f);
    grass = CreateGrass(&vm, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.6f, 0.0f, 0.0f));
    float* chunk = new float[80000];
    sky = CreateSphere(&vm, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), chunk, 80000);
    sphere = CreateSphere(&vm, glm::vec3(6.0f, 10.0f, 0.0f), glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), chunk, 80000);
    water_droplet = CreateWaterDroplet(&vm, glm::vec3(6.0f, 12.0f, 0.0f), glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), chunk, 80000);
    glm::vec3 p[4][4] = {
        glm::vec3(-1.0f,0.0f, -1.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(-1.0f, 0.0f, 1.0f), glm::vec3(-1.0f, 0.0f, 2.0f),
        glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 1.0f, 1.0f), glm::vec3(0.0f, 0.0f, 2.0f),
        glm::vec3(1.0f, 0.0f, -1.0f), glm::vec3(1.0f, 1.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 0.0f, 2.0f),
        glm::vec3(2.0f, 0.0f, -1.0f), glm::vec3(2.0f, 0.0f, 0.0f), glm::vec3(2.0f, 0.0f, 1.0f), glm::vec3(2.0f, 0.0f, 2.0f)
    };
    surface = CreateSurface(&vm, glm::vec3(0.0f, 4.0f, 0.0f), glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), p, chunk, 80000);
    penguin = CreatePenguin(&vm, chunk, 80000);
    delete[] chunk;

}
static void WindowReshapeCallback(GLFWwindow* window, int new_width, int new_height) {
    WIDTH = new_width;
    HEIGHT = new_height;
    aspect = (float)WIDTH / (float)HEIGHT;
    glViewport(0, 0, WIDTH, HEIGHT);
    camera.pmat = glm::perspective(1.4f, aspect, 2000.0f, 0.2f);
    glDeleteTextures(1, &shadow_depth);
    glDeleteTextures(1, &shadow_texture);
    glDeleteFramebuffers(1, &shadow_buffer);
    SetupBuffers(window, &shadow_buffer, &shadow_depth, &shadow_texture);
    reflect_camera.pmat = glm::perspective(1.4f, aspect, 2000.0f, 0.2f);
    glDeleteTextures(1, &reflect_depth);
    glDeleteTextures(1, &reflect_texture);
    glDeleteFramebuffers(1, &reflect_buffer);
    SetupBuffers(window, &reflect_buffer, &reflect_depth, &reflect_texture);
    glDeleteTextures(1, &refract_depth);
    glDeleteTextures(1, &refract_texture);
    glDeleteFramebuffers(1, &refract_buffer);
    SetupBuffers(window, &refract_buffer, &refract_depth, &refract_texture);
}
static void InstallLight(GLuint program) {
    global_amb_loc = glGetUniformLocation(program, "GlobalAmbient");
    sunshine.dirlight_amb_loc = glGetUniformLocation(program, "DirLightAmbient");
    sunshine.dirlight_dif_loc = glGetUniformLocation(program, "DirLightDiffuse");
    sunshine.dirlight_spe_loc = glGetUniformLocation(program, "DirLightSpecular");
    sunshine.dirlight_dir_loc = glGetUniformLocation(program, "DirLightDirection");
    glProgramUniform4fv(program, global_amb_loc, 1, glm::value_ptr(global_ambient));
    glProgramUniform4fv(program, sunshine.dirlight_amb_loc, 1, glm::value_ptr(sunshine.direction_light_ambient));
    glProgramUniform4fv(program, sunshine.dirlight_dif_loc, 1, glm::value_ptr(sunshine.direction_light_diffuse));
    glProgramUniform4fv(program, sunshine.dirlight_spe_loc, 1, glm::value_ptr(sunshine.direction_light_specular));
    glProgramUniform3fv(program, sunshine.dirlight_dir_loc, 1, glm::value_ptr(sunshine.direction));
}
static void InstallCamera(GLuint program, Camera* came) {
    came->mvloc = glGetUniformLocation(program, "mvmat");
    came->ploc = glGetUniformLocation(program, "pmat");
    came->vloc = glGetUniformLocation(program, "vmat");
    came->cloc = glGetUniformLocation(program, "texture_color");
}
static void process1(Camera* came, double current_time) {
    glClear(GL_COLOR_BUFFER_BIT);
    glClear(GL_DEPTH_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);
    if (weather == sunny) {
        glUseProgram(sky_program);
        temp_location = glGetUniformLocation(sky_program, "light_angle");
        came->vloc = glGetUniformLocation(sky_program, "light_direction");            //临时替用
        came->mvloc = glGetUniformLocation(sky_program, "mvmat");
        came->ploc = glGetUniformLocation(sky_program, "pmat");
        came->mvmat = came->vmat * glm::translate(glm::mat4(1.0f), came->position);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_3D, sky_texture);
        glUniform1f(temp_location, direction_light_angle);
        glUniform3fv(came->vloc, 1, glm::value_ptr(sunshine.direction));
        glUniformMatrix4fv(came->mvloc, 1, GL_FALSE, glm::value_ptr(came->mvmat));
        glUniformMatrix4fv(came->ploc, 1, GL_FALSE, glm::value_ptr(came->pmat));
        glBindBuffer(GL_ARRAY_BUFFER, vm.vbo[sky->vbo_index[0]]);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(0);
        glDrawArrays(GL_TRIANGLES, 0, sky->size / 3);
    }
#ifdef DEBUG
    using_time[run_times][program_num++] = glfwGetTime() - debug_pre;
    debug_pre = glfwGetTime();
#endif
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_GEQUAL);
    glUseProgram(rendering_program);
    InstallLight(rendering_program);
    InstallCamera(rendering_program, came);
    DrawObject(came, &vm, cone);
    DrawObject(came, &vm, surface);
    glEnable(GL_CULL_FACE);
    DrawObject(came, &vm, cube);
    DrawObject(came, &vm, tetrahedron);
    DrawObject(came, &vm, icosahedron);
    DrawObject(came, &vm, sphere);
    DrawObject(came, &vm, water_droplet);
#ifdef DEBUG
    using_time[run_times][program_num++] = glfwGetTime() - debug_pre;
    debug_pre = glfwGetTime();
#endif
}
static void process2(Camera* came, double current_time) {
    glClear(GL_COLOR_BUFFER_BIT);
    glClear(GL_DEPTH_BUFFER_BIT);
    glDisable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_GEQUAL);
    glUseProgram(plain_program);
    InstallLight(plain_program);
    came->mvloc = glGetUniformLocation(plain_program, "mvmat");
    came->ploc = glGetUniformLocation(plain_program, "pmat");
    came->vloc = glGetUniformLocation(plain_program, "vmat");
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, shadow_texture);
    came->mvmat = came->vmat * glm::translate(glm::mat4(1.0f), square->position);
    glUniformMatrix4fv(came->mvloc, 1, GL_FALSE, glm::value_ptr(came->mvmat));
    glUniformMatrix4fv(came->ploc, 1, GL_FALSE, glm::value_ptr(came->pmat));
    glUniformMatrix4fv(came->vloc, 1, GL_FALSE, glm::value_ptr(came->vmat));
    glBindBuffer(GL_ARRAY_BUFFER, vm.vbo[square->vbo_index[0]]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vm.vbo[square->vbo_index[1]]);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(1);
    glDrawArrays(GL_TRIANGLES, 0, square->size / 3);
#ifdef DEBUG
    using_time[run_times][program_num++] = glfwGetTime() - debug_pre;
    debug_pre = glfwGetTime();
#endif
    glUseProgram(grassland_program);
    global_amb_loc = glGetUniformLocation(grassland_program, "GlobalAmbient");
    sunshine.dirlight_amb_loc = glGetUniformLocation(grassland_program, "DirLightAmbient");
    sunshine.dirlight_dif_loc = glGetUniformLocation(grassland_program, "DirLightDiffuse");
    sunshine.dirlight_dir_loc = glGetUniformLocation(grassland_program, "DirLightDirection");
    glProgramUniform4fv(grassland_program, global_amb_loc, 1, glm::value_ptr(global_ambient));
    glProgramUniform4fv(grassland_program, sunshine.dirlight_amb_loc, 1, glm::value_ptr(sunshine.direction_light_ambient));
    glProgramUniform4fv(grassland_program, sunshine.dirlight_dif_loc, 1, glm::value_ptr(sunshine.direction_light_diffuse));
    glProgramUniform3fv(grassland_program, sunshine.dirlight_dir_loc, 1, glm::value_ptr(sunshine.direction));
    InstallCamera(grassland_program, came);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, shadow_texture);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, grass_texture);
    came->mvmat = came->vmat * glm::translate(glm::mat4(1.0f), grass->position);
    glUniformMatrix4fv(came->mvloc, 1, GL_FALSE, glm::value_ptr(came->mvmat));
    glUniformMatrix4fv(came->ploc, 1, GL_FALSE, glm::value_ptr(came->pmat));
    glUniformMatrix4fv(came->vloc, 1, GL_FALSE, glm::value_ptr(came->vmat));
    glUniform4fv(came->cloc, 1, glm::value_ptr(grass->texture_color));
    glBindBuffer(GL_ARRAY_BUFFER, vm.vbo[grass->vbo_index[0]]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vm.vbo[grass->vbo_index[1]]);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(1);
    glDrawArraysInstanced(GL_TRIANGLES, 0, grass->size / 3, 16384);
#ifdef DEBUG
    using_time[run_times][program_num++] = glfwGetTime() - debug_pre;
    debug_pre = glfwGetTime();
#endif
    glUseProgram(rendering_program);
    InstallLight(rendering_program);
    InstallCamera(rendering_program, came);
    glEnable(GL_CULL_FACE);
    DrawModel(came, &vm, penguin->penguin_model, glm::translate(glm::mat4(1.0f), penguin->penguin_model->position) * glm::rotate(glm::mat4(1.0f), PI, glm::vec3(0.0f, 1.0f, 0.0f)));
#ifdef DEBUG
    using_time[run_times][program_num++] = glfwGetTime() - debug_pre;
    debug_pre = glfwGetTime();
#endif
}
static void process3(Camera* came, double current_time) {
    glClear(GL_COLOR_BUFFER_BIT);
    glClear(GL_DEPTH_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);
    if (weather == sunny) {
        glUseProgram(sky_program);
        temp_location = glGetUniformLocation(sky_program, "light_angle");
        came->vloc = glGetUniformLocation(sky_program, "light_direction");            //临时替用
        came->mvloc = glGetUniformLocation(sky_program, "mvmat");
        came->ploc = glGetUniformLocation(sky_program, "pmat");
        came->mvmat = came->vmat * glm::translate(glm::mat4(1.0f), came->position);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_3D, sky_texture);
        glUniform1f(temp_location, direction_light_angle);
        glUniform3fv(came->vloc, 1, glm::value_ptr(sunshine.direction));
        glUniformMatrix4fv(came->mvloc, 1, GL_FALSE, glm::value_ptr(came->mvmat));
        glUniformMatrix4fv(came->ploc, 1, GL_FALSE, glm::value_ptr(came->pmat));
        glBindBuffer(GL_ARRAY_BUFFER, vm.vbo[sky->vbo_index[0]]);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(0);
        glDrawArrays(GL_TRIANGLES, 0, sky->size / 3);
    }
#ifdef DEBUG
    using_time[run_times][program_num++] = glfwGetTime() - debug_pre;
    debug_pre = glfwGetTime();
#endif
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_GEQUAL);
    if (weather == snowy) {
        glUseProgram(snow_program);
        temp_location = glGetUniformLocation(snow_program, "camera");
        time_location = glGetUniformLocation(snow_program, "current_time");
        came->mvloc = glGetUniformLocation(snow_program, "mvmat");
        came->ploc = glGetUniformLocation(snow_program, "pmat");
        came->mvmat = came->vmat;
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, snow_texture);
        glUniformMatrix4fv(came->mvloc, 1, GL_FALSE, glm::value_ptr(came->mvmat));
        glUniformMatrix4fv(came->ploc, 1, GL_FALSE, glm::value_ptr(came->pmat));
        glUniform3fv(temp_location, 1, glm::value_ptr(came->position));
        glUniform1f(time_location, (GLfloat)current_time);
        glBindBuffer(GL_ARRAY_BUFFER, vm.vbo[snow->vbo_index[0]]);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(0);
        glDrawArraysInstanced(GL_TRIANGLES, 0, snow->size / 3, 262144);
    }
#ifdef DEBUG
    using_time[run_times][program_num++] = glfwGetTime() - debug_pre;
    debug_pre = glfwGetTime();
#endif
    glUseProgram(plain_program);
    InstallLight(plain_program);
    came->mvloc = glGetUniformLocation(plain_program, "mvmat");
    came->ploc = glGetUniformLocation(plain_program, "pmat");
    came->vloc = glGetUniformLocation(plain_program, "vmat");
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, shadow_texture);
    came->mvmat = came->vmat * glm::translate(glm::mat4(1.0f), square->position);
    glUniformMatrix4fv(came->mvloc, 1, GL_FALSE, glm::value_ptr(came->mvmat));
    glUniformMatrix4fv(came->ploc, 1, GL_FALSE, glm::value_ptr(came->pmat));
    glUniformMatrix4fv(came->vloc, 1, GL_FALSE, glm::value_ptr(came->vmat));
    glBindBuffer(GL_ARRAY_BUFFER, vm.vbo[square->vbo_index[0]]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vm.vbo[square->vbo_index[1]]);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(1);
    glDrawArrays(GL_TRIANGLES, 0, square->size / 3);
#ifdef DEBUG
    using_time[run_times][program_num++] = glfwGetTime() - debug_pre;
    debug_pre = glfwGetTime();
#endif
    glUseProgram(grassland_program);
    InstallLight(grassland_program);
    InstallCamera(grassland_program, came);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, shadow_texture);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, grass_texture);
    came->mvmat = came->vmat * glm::translate(glm::mat4(1.0f), grass->position);
    glUniformMatrix4fv(came->mvloc, 1, GL_FALSE, glm::value_ptr(came->mvmat));
    glUniformMatrix4fv(came->ploc, 1, GL_FALSE, glm::value_ptr(came->pmat));
    glUniformMatrix4fv(came->vloc, 1, GL_FALSE, glm::value_ptr(came->vmat));
    glUniform4fv(came->cloc, 1, glm::value_ptr(grass->texture_color));
    glBindBuffer(GL_ARRAY_BUFFER, vm.vbo[grass->vbo_index[0]]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vm.vbo[grass->vbo_index[1]]);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(1);
    glDrawArraysInstanced(GL_TRIANGLES, 0, grass->size / 3, 16384);
#ifdef DEBUG
    using_time[run_times][program_num++] = glfwGetTime() - debug_pre;
    debug_pre = glfwGetTime();
#endif
    glUseProgram(rendering_program);
    InstallLight(rendering_program);
    InstallCamera(rendering_program, came);
    DrawObject(came, &vm, cone);
    DrawObject(came, &vm, surface);
    glEnable(GL_CULL_FACE);
    DrawObject(came, &vm, cube);
    DrawObject(came, &vm, tetrahedron);
    DrawObject(came, &vm, icosahedron);
    DrawObject(came, &vm, sphere);
    DrawObject(came, &vm, water_droplet);
    DrawModel(came, &vm, penguin->penguin_model, glm::translate(glm::mat4(1.0f), penguin->penguin_model->position) * glm::rotate(glm::mat4(1.0f), PI, glm::vec3(0.0f, 1.0f, 0.0f)));
#ifdef DEBUG
    using_time[run_times][program_num++] = glfwGetTime() - debug_pre;
    debug_pre = glfwGetTime();
#endif
}
static void display(GLFWwindow* window, double current_time) {
#ifdef DEBUG
    program_num = 0;
    debug_pre = glfwGetTime();
#endif
    /*第一轮:绘制阴影,记录颜色*/
    glBindFramebuffer(GL_FRAMEBUFFER, shadow_buffer);                //这行代码耗费了0.02s!!!
    glClear(GL_COLOR_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glUseProgram(shadow_program);
    camera.mvloc = glGetUniformLocation(shadow_program, "mat");
    /*绘制除水,平面,草坪以外的物体*/
    glm::mat4 temp_mat = camera.pmat * camera.vmat * proj_mat;
    DrawShadow(&camera, &vm, cone, temp_mat * glm::translate(glm::mat4(1.0f), cone->position));
    DrawShadow(&camera, &vm, surface, temp_mat * glm::translate(glm::mat4(1.0f), surface->position));
    DrawShadow(&camera, &vm, cube, temp_mat * glm::translate(glm::mat4(1.0f), cube->position));
    DrawShadow(&camera, &vm, tetrahedron, temp_mat * glm::translate(glm::mat4(1.0f), tetrahedron->position));
    DrawShadow(&camera, &vm, icosahedron, temp_mat * glm::translate(glm::mat4(1.0f), icosahedron->position));
    DrawShadow(&camera, &vm, sphere, temp_mat * glm::translate(glm::mat4(1.0f), sphere->position));
    DrawShadow(&camera, &vm, water_droplet, temp_mat * glm::translate(glm::mat4(1.0f), water_droplet->position));
    DrawShadow(&camera, &vm, penguin->penguin_model, temp_mat * glm::translate(glm::mat4(1.0f), penguin->penguin_model->position) *
        glm::rotate(glm::mat4(1.0f), PI, glm::vec3(0.0f, 1.0f, 0.0f)));
#ifdef DEBUG
    using_time[run_times][program_num++] = glfwGetTime() - debug_pre;
    debug_pre = glfwGetTime();
#endif
    //第二轮:绘制反射,记录颜色
    glBindFramebuffer(GL_FRAMEBUFFER, reflect_buffer);
    //不绘制雪,水面以下物体
    process1(&reflect_camera, current_time);
    //第三轮:绘制折射,记录颜色
    glBindFramebuffer(GL_FRAMEBUFFER, refract_buffer);
    //不绘制雪,水面以上的物体
    process2(&camera, current_time);
    //第三轮:绘制除阴影外的物体
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    process3(&camera, current_time);
    glDisable(GL_CULL_FACE);
    glUseProgram(water_program);
    camera.mvmat = camera.vmat * glm::translate(glm::mat4(1.0f), water->position);
    camera.mvloc = glGetUniformLocation(water_program, "mvmat");
    camera.ploc = glGetUniformLocation(water_program, "pmat");
    camera.cloc = glGetUniformLocation(water_program, "texture_color");
    temp_location = glGetUniformLocation(water_program, "camera");
    time_location = glGetUniformLocation(water_program, "time");
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, reflect_texture);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, refract_texture);
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_3D, water_texture);
    glUniformMatrix4fv(camera.mvloc, 1, GL_FALSE, glm::value_ptr(camera.mvmat));
    glUniformMatrix4fv(camera.ploc, 1, GL_FALSE, glm::value_ptr(camera.pmat));
    glUniform4fv(camera.cloc, 1, glm::value_ptr(water->texture_color));
    glUniform3fv(temp_location, 1, glm::value_ptr(camera.position - water->position));
    glUniform1f(time_location, (GLfloat)current_time);
    glBindBuffer(GL_ARRAY_BUFFER, vm.vbo[water->vbo_index[0]]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);
    glDrawArrays(GL_TRIANGLES, 0, water->size / 3);
#ifdef DEBUG
    using_time[run_times][program_num++] = glfwGetTime() - debug_pre;
    debug_pre = glfwGetTime();
#endif
}
int main() {
    if (!glfwInit()) { exit(EXIT_FAILURE); }
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "HelloWorld", NULL, NULL);
    glfwMakeContextCurrent(window);
    if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); }
    glfwSwapInterval(1);
    glfwSetWindowSizeCallback(window, WindowReshapeCallback);

    init(window);
    double pre = glfwGetTime();

    while (!glfwWindowShouldClose(window)) {
        MoveCamera(window);
        display(window, pre);
        glfwSwapBuffers(window);
        glfwPollEvents();
#ifndef DEBUG
        while (glfwGetTime() - pre <= 0.02);
        std::cout << "FPS:" << 1.0 / (glfwGetTime() - pre) << std::endl;    //帧率
#else
        run_times++;
        std::cout << "FPS:" << 1.0 / (glfwGetTime() - pre) << std::endl;    //帧率
#endif
        pre = glfwGetTime();
    }
    DestroyObject(square);
    DestroyObject(water);
    DestroyObject(snow);
    DestroyObject(tetrahedron);
    DestroyObject(icosahedron);
    DestroyObject(cube);
    DestroyObject(cone);
    DestroyObject(grass);
    DestroyObject(sky);
    DestroyObject(sphere);
    DestroyObject(water_droplet);
    DestroyObject(surface);
    DestroyModel(penguin->penguin_model);
#ifdef DEBUG
    double sum[32]{};
    std::fstream fout("analysis.txt", std::ios::out);
    for (GLuint i = 0; i < program_num; i++)
        sum[i] = 0.0f;
    for (GLuint i = 0; i < program_num; i++) {
        for (GLuint j = 256; j < run_times; j++)                            //除去前256次
            sum[i] += using_time[j][i];
        sum[i] /= double(run_times - 256);
    }
    fout << "shadow_program:" << sum[0] << std::endl;
    fout << "process1-sky_program:" << sum[1] << std::endl;
    fout << "process1-rendering_program:" << sum[2] << std::endl;
    fout << "process2-plain_program:" << sum[3] << std::endl;
    fout << "process2-grassland_program:" << sum[4] << std::endl;
    fout << "process2-rendering_program:" << sum[5] << std::endl;
    fout << "process3-sky_program:" << sum[6] << std::endl;
    fout << "process3-snow_program:" << sum[7] << std::endl;
    fout << "process3-plain_program:" << sum[8] << std::endl;
    fout << "process3-grassland_program:" << sum[9] << std::endl;
    fout << "process3-rendering_program:" << sum[10] << std::endl;
    fout << "water_program:" << sum[11] << std::endl;
    fout.close();
#endif
    glfwDestroyWindow(window);
    glfwTerminate();
    exit(EXIT_SUCCESS);
}

```

  • 写回答

1条回答 默认 最新

  • 檀越@新空间 2026-02-18 16:01
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    在 OpenGL 中,glBindFramebuffer(GL_FRAMEBUFFER, shadow_buffer); 这一行代码耗费了 0.02s 的时间,这表明它可能是性能瓶颈。我们可以通过以下方式优化该问题,并提升整体帧率。


    ✅ 问题分析

    1. 频繁绑定 FBO(Frame Buffer Object)

      • 每次调用 glBindFramebuffer 都会触发一次状态切换,这在 OpenGL 中是昂贵的操作。
      • 如果你在一个渲染循环中频繁地绑定和解绑 FBO(例如:阴影贴图、反射、折射等),就会导致性能下降。
    2. 可能的冗余操作

      • 你在 SetupBuffers 函数中多次使用了 buffer_id[1],但每次只生成一个 ID,这可能会导致错误或内存浪费。
    3. 未正确设置 FBO 状态

      • 在创建 FBO 后,需要确保其完整性(通过 glCheckFramebufferStatus),否则可能导致性能问题。
    4. 未启用深度/模板缓冲区

      • 在某些情况下,如果你没有正确设置深度或模板缓冲区,可能导致渲染异常或性能下降。

    ✅ 解决方案

    1. 减少 FBO 绑定次数

    • 避免在每一帧都绑定 FBO:如果 FBO 是固定的(如阴影贴图、反射贴图等),只需要在初始化时绑定一次即可。
    • 批量处理 FBO 操作:将所有 FBO 相关的绑定操作集中到一个地方,而不是在多个函数中重复调用。

    建议修改:SetupBuffers 改为仅在初始化时调用一次,不要在每一帧中重新创建或绑定。


    2. 优化 SetupBuffers 函数

    static void SetupBuffers(GLFWwindow* window, GLuint* buffer, GLuint* depth, GLuint* texture) {
        glGenFramebuffers(1, buffer);
        glBindFramebuffer(GL_FRAMEBUFFER, *buffer);
    
        glGenTextures(1, texture);
        glBindTexture(GL_TEXTURE_2D, *texture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texture, 0);
    
        glGenTextures(1, depth);
        glBindTexture(GL_TEXTURE_2D, *depth);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, WIDTH, HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, *depth, 0);
    
        // Check if the framebuffer is complete
        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
            std::cerr << "Framebuffer not complete!" << std::endl;
        }
    
        glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind after setup
    }
    

    注意:SetupBuffers 中,我们不再重复使用 buffer_id[1],而是直接生成一个 ID 并赋值给参数。


    3. 避免频繁绑定 FBO

    在你的主渲染循环中,不要每帧都调用 glBindFramebuffer(...),除非你需要切换不同的 FBO(如阴影贴图、反射、折射等)。

    示例:

    // 在初始化阶段调用一次
    SetupBuffers(window, &shadow_buffer, &shadow_depth, &shadow_texture);
    
    // 在渲染循环中,只在需要的时候绑定
    if (render_shadow_map) {
        glBindFramebuffer(GL_FRAMEBUFFER, shadow_buffer);
        // 渲染阴影贴图
        glBindFramebuffer(GL_FRAMEBUFFER, 0); // 解绑
    }
    

    4. 检查 FBO 完整性

    在创建 FBO 后,添加如下代码以确保其完整性:

    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE) {
        std::cerr << "Framebuffer is not complete: " << status << std::endl;
    }
    

    5. 使用纹理目标和格式优化

    • 确保 GL_TEXTURE_2D 的格式与 FBO 的颜色附件匹配。
    • 使用 GL_RGBAGL_RGB 而不是 GL_RGBA8 等更具体的格式,以提高兼容性和性能。

    6. 减少不必要的 OpenGL 状态切换

    • 避免在渲染循环中频繁切换 FBO、VAO、VBO、Shader Program
    • 尽量将相似的操作合并,比如将所有的阴影绘制放在一个批次中。

    ✅ 总结

    | 问题 | 解决方案 | |------|----------| | 频繁绑定 FBO | 只在初始化时绑定一次,避免每帧都绑定 | | 冗余的 FBO 创建 | 优化 SetupBuffers 函数,避免重复生成 ID | | FBO 不完整 | 添加 glCheckFramebufferStatus 检查 | | 多个 FBO 切换 | 合并 FBO 操作,减少状态切换 | | 纹理格式不匹配 | 确保纹理格式与 FBO 的颜色附件一致 |


    ✅ 修改后的代码片段(关键部分)

    // 优化后的 SetupBuffers
    static void SetupBuffers(GLFWwindow* window, GLuint* buffer, GLuint* depth, GLuint* texture) {
        glGenFramebuffers(1, buffer);
        glBindFramebuffer(GL_FRAMEBUFFER, *buffer);
    
        glGenTextures(1, texture);
        glBindTexture(GL_TEXTURE_2D, *texture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texture, 0);
    
        glGenTextures(1, depth);
        glBindTexture(GL_TEXTURE_2D, *depth);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, WIDTH, HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, *depth, 0);
    
        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
            std::cerr << "Framebuffer not complete!" << std::endl;
        }
    
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
    
    // 在初始化阶段调用一次
    SetupBuffers(window, &shadow_buffer, &shadow_depth, &shadow_texture);
    
    // 在渲染循环中只在需要时绑定
    if (render_shadow_map) {
        glBindFramebuffer(GL_FRAMEBUFFER, shadow_buffer);
        // 渲染阴影贴图
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
    

    ✅ 建议进一步优化方向

    • 使用多线程渲染:将一些计算密集型任务(如阴影贴图生成)放到后台线程。
    • 使用 VAO 和 VBO 缓存:避免重复生成 VAO/VBO。
    • 使用纹理缓存机制:避免重复加载相同纹理。

    如有更多关于 OpenGL 的性能优化问题,欢迎继续提问!

    评论

报告相同问题?

问题事件

  • 创建了问题 2月18日