// render the scene with OpenGL void shade(Scene* scene, ShadeState* state) { // enable depth test glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); // disable culling face glDisable(GL_CULL_FACE); // let the shader control the points glEnable(GL_POINT_SPRITE); // set up the viewport from the scene image size glViewport(0, 0, scene->image_width, scene->image_height); // clear the screen (both color and depth) - set cleared color to background glClearColor(scene->background.x, scene->background.y, scene->background.z, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // enable program glUseProgram(state->gl_program_id); // bind camera's position, inverse of frame and projection // use frame_to_matrix_inverse and frustum_matrix glUniform3fv(glGetUniformLocation(state->gl_program_id,"camera_pos"), 1, &scene->camera->frame.o.x); glUniformMatrix4fv(glGetUniformLocation(state->gl_program_id,"camera_frame_inverse"), 1, true, &frame_to_matrix_inverse(scene->camera->frame)[0][0]); glUniformMatrix4fv(glGetUniformLocation(state->gl_program_id,"camera_projection"), 1, true, &frustum_matrix(-scene->camera->dist*scene->camera->width/2, scene->camera->dist*scene->camera->width/2, -scene->camera->dist*scene->camera->height/2, scene->camera->dist*scene->camera->height/2, scene->camera->dist,10000)[0][0]); // bind ambient and number of lights glUniform3fv(glGetUniformLocation(state->gl_program_id,"ambient"),1,&scene->ambient.x); glUniform1i(glGetUniformLocation(state->gl_program_id,"lights_num"),scene->lights.size()); // foreach light auto count = 0; for(auto light : scene->lights) { // bind light position and internsity (create param name with tostring) glUniform3fv(glGetUniformLocation(state->gl_program_id,tostring("light_pos[%d]",count).c_str()), 1, &light->frame.o.x); glUniform3fv(glGetUniformLocation(state->gl_program_id,tostring("light_intensity[%d]",count).c_str()), 1, &light->intensity.x); count++; } // foreach mesh for(auto mesh : scene->meshes) { // bind material kd, ks, n glUniform3fv(glGetUniformLocation(state->gl_program_id,"material_kd"), 1,&mesh->mat->kd.x); glUniform3fv(glGetUniformLocation(state->gl_program_id,"material_ks"), 1,&mesh->mat->ks.x); glUniform1f(glGetUniformLocation(state->gl_program_id,"material_n"), mesh->mat->n); // YOUR CODE GOES HERE --------------------- // bind texture params (txt_on, sampler) _bind_texture("material_kd_txt", "material_kd_txt_on", mesh->mat->kd_txt, 0, state); _bind_texture("material_ks_txt", "material_ks_txt_on", mesh->mat->ks_txt, 1, state); _bind_texture("material_norm_txt", "material_norm_txt_on", mesh->mat->norm_txt, 2, state); // bind mesh frame - use frame_to_matrix glUniformMatrix4fv(glGetUniformLocation(state->gl_program_id,"mesh_frame"), 1,true,&frame_to_matrix(mesh->frame)[0][0]); // enable vertex attributes arrays and set up pointers to the mesh data auto vertex_pos_location = glGetAttribLocation(state->gl_program_id, "vertex_pos"); auto vertex_norm_location = glGetAttribLocation(state->gl_program_id, "vertex_norm"); // YOUR CODE GOES HERE --------------------- auto vertex_texcoord_location = glGetAttribLocation(state->gl_program_id, "vertex_texcoord"); glEnableVertexAttribArray(vertex_pos_location); glVertexAttribPointer(vertex_pos_location, 3, GL_FLOAT, GL_FALSE, 0, &mesh->pos[0].x); glEnableVertexAttribArray(vertex_norm_location); glVertexAttribPointer(vertex_norm_location, 3, GL_FLOAT, GL_FALSE, 0, &mesh->norm[0].x); // YOUR CODE GOES HERE --------------------- if (!mesh->texcoord.empty()) { glEnableVertexAttribArray(vertex_texcoord_location); glVertexAttribPointer(vertex_texcoord_location, 2, GL_FLOAT, GL_FALSE, 0, &mesh->texcoord[0].x); } // draw triangles and quads if(! scene->draw_wireframe) { if(mesh->triangle.size()) glDrawElements(GL_TRIANGLES, mesh->triangle.size()*3, GL_UNSIGNED_INT, &mesh->triangle[0].x); if(mesh->quad.size()) glDrawElements(GL_QUADS, mesh->quad.size()*4, GL_UNSIGNED_INT, &mesh->quad[0].x); } else { auto edges = EdgeMap(mesh->triangle, mesh->quad).edges(); glDrawElements(GL_LINES, edges.size()*2, GL_UNSIGNED_INT, &edges[0].x); } // draw line sets if(! mesh->line.empty()) glDrawElements(GL_LINES, mesh->line.size()*2, GL_UNSIGNED_INT, mesh->line.data()); for(auto segment : mesh->spline) glDrawElements(GL_LINE_STRIP, 4, GL_UNSIGNED_INT, &segment); // disable vertex attribute arrays glDisableVertexAttribArray(vertex_pos_location); glDisableVertexAttribArray(vertex_norm_location); // YOUR CODE GOES HERE --------------------- if (!mesh->texcoord.empty()) glDisableVertexAttribArray(vertex_texcoord_location); } }
// shade a mesh void shade_mesh(Mesh* mesh, int time, bool wireframe, bool skinning_gpu, bool draw_normals, ShadeState* state) { // bind material kd, ks, n glUniform3fv(glGetUniformLocation(state->gl_program_id,"material_kd"), 1,&mesh->mat->kd.x); glUniform3fv(glGetUniformLocation(state->gl_program_id,"material_ks"), 1,&mesh->mat->ks.x); glUniform1f(glGetUniformLocation(state->gl_program_id,"material_n"), mesh->mat->n); glUniform1i(glGetUniformLocation(state->gl_program_id,"material_is_lines"), GL_FALSE); glUniform1i(glGetUniformLocation(state->gl_program_id,"material_double_sided"), (mesh->mat->double_sided)?GL_TRUE:GL_FALSE); // bind texture params (txt_on, sampler) _bind_texture("material_kd_txt", "material_kd_txt_on", mesh->mat->kd_txt, 0, state); _bind_texture("material_ks_txt", "material_ks_txt_on", mesh->mat->ks_txt, 1, state); _bind_texture("material_norm_txt", "material_norm_txt_on", mesh->mat->norm_txt, 2, state); // bind mesh frame - use frame_to_matrix glUniformMatrix4fv(glGetUniformLocation(state->gl_program_id,"mesh_frame"), 1,true,&frame_to_matrix(mesh->frame)[0][0]); // enable vertex attributes arrays and set up pointers to the mesh data auto vertex_pos_location = glGetAttribLocation(state->gl_program_id, "vertex_pos"); auto vertex_norm_location = glGetAttribLocation(state->gl_program_id, "vertex_norm"); auto vertex_texcoord_location = glGetAttribLocation(state->gl_program_id, "vertex_texcoord"); // YOUR CODE GOES HERE --------------------- // (only for extra credit) auto vertex_skin_bone_ids_location = glGetAttribLocation(state->gl_program_id, "vertex_skin_bone_ids"); auto vertex_skin_bone_weights_location = glGetAttribLocation(state->gl_program_id, "vertex_skin_bone_weights"); glEnableVertexAttribArray(vertex_pos_location); glVertexAttribPointer(vertex_pos_location, 3, GL_FLOAT, GL_FALSE, 0, &mesh->pos[0].x); glEnableVertexAttribArray(vertex_norm_location); glVertexAttribPointer(vertex_norm_location, 3, GL_FLOAT, GL_FALSE, 0, &mesh->norm[0].x); if(not mesh->texcoord.empty()) { glEnableVertexAttribArray(vertex_texcoord_location); glVertexAttribPointer(vertex_texcoord_location, 2, GL_FLOAT, GL_FALSE, 0, &mesh->texcoord[0].x); } else glVertexAttrib2f(vertex_texcoord_location, 0, 0); if (mesh->skinning and skinning_gpu) { // YOUR CODE GOES HERE --------------------- // (only for extra credit) glUniform1i(glGetUniformLocation(state->gl_program_id, "skin_enabled"), true); glEnableVertexAttribArray(vertex_skin_bone_ids_location); glVertexAttribPointer(vertex_skin_bone_ids_location, 4, GL_INT, GL_FALSE, 0, &mesh->skinning->bone_ids[0].x); glEnableVertexAttribArray(vertex_skin_bone_weights_location); glVertexAttribPointer(vertex_skin_bone_weights_location, 4, GL_FLOAT, GL_FALSE, 0, &mesh->skinning->bone_weights[0].x); for (int i = 0; i < 48; i++) { string name = "skin_bone_xforms["+std::to_string(i)+"]"; glUniformMatrix4fv(glGetUniformLocation(state->gl_program_id, name.c_str()), 1, GL_TRUE, &mesh->skinning->bone_xforms[time][i][0].x); } } else { glUniform1i(glGetUniformLocation(state->gl_program_id,"skin_enabled"),GL_FALSE); } // draw triangles and quads if(not wireframe) { if(mesh->triangle.size()) glDrawElements(GL_TRIANGLES, mesh->triangle.size()*3, GL_UNSIGNED_INT, &mesh->triangle[0].x); if(mesh->quad.size()) glDrawElements(GL_QUADS, mesh->quad.size()*4, GL_UNSIGNED_INT, &mesh->quad[0].x); if(mesh->point.size()) glDrawElements(GL_POINTS, mesh->point.size(), GL_UNSIGNED_INT, &mesh->point[0]); if(mesh->line.size()) glDrawElements(GL_LINES, mesh->line.size(), GL_UNSIGNED_INT, &mesh->line[0].x); for(auto segment : mesh->spline) glDrawElements(GL_LINE_STRIP, 4, GL_UNSIGNED_INT, &segment); } else { auto edges = EdgeMap(mesh->triangle, mesh->quad).edges(); glDrawElements(GL_LINES, edges.size()*2, GL_UNSIGNED_INT, &edges[0].x); } // disable vertex attribute arrays glDisableVertexAttribArray(vertex_pos_location); glDisableVertexAttribArray(vertex_norm_location); if(not mesh->texcoord.empty()) glDisableVertexAttribArray(vertex_texcoord_location); if(mesh->skinning) { // YOUR CODE GOES HERE --------------------- // (only for extra credit) glDisableVertexAttribArray(vertex_skin_bone_ids_location); glDisableVertexAttribArray(vertex_skin_bone_weights_location); } // draw normals if needed if(draw_normals) { glUniform3fv(glGetUniformLocation(state->gl_program_id,"material_kd"), 1,&zero3f.x); glUniform3fv(glGetUniformLocation(state->gl_program_id,"material_ks"), 1,&zero3f.x); glBegin(GL_LINES); for(auto i : range(mesh->pos.size())) { auto p0 = mesh->pos[i]; auto p1 = mesh->pos[i] + mesh->norm[i]*0.1; glVertexAttrib3fv(0,&p0.x); glVertexAttrib3fv(0,&p1.x); if(mesh->mat->double_sided) { auto p2 = mesh->pos[i] - mesh->norm[i]*0.1; glVertexAttrib3fv(0,&p0.x); glVertexAttrib3fv(0,&p2.x); } } glEnd(); } }