void Renderer::frustum_cull(glm::vec3 camera_position, SceneObject *object, float frustum[6][4], std::vector<SceneObject*>& scene_objects, bool need_cull, int planeMask) { // frustumCull() return 3 possible values: // 0 when the HBV of the object is completely outside the frustum: cull itself and all its children out // 1 when the HBV of the object is intersecting the frustum but the object itself is not: cull it out and continue culling test with its children // 2 when the HBV of the object is intersecting the frustum and the mesh BV of the object are intersecting (inside) the frustum: render itself and continue culling test with its children // 3 when the HBV of the object is completely inside the frustum: render itself and all its children without further culling test int cullVal; if (need_cull) { cullVal = object->frustumCull(camera_position, frustum, planeMask); if (cullVal == 0) { return; } if (cullVal >= 2) { scene_objects.push_back(object); } if (cullVal == 3) { need_cull = false; } } else { scene_objects.push_back(object); } const std::vector<SceneObject*> children = object->children(); for (auto it = children.begin(); it != children.end(); ++it) { frustum_cull(camera_position, *it, frustum, scene_objects, need_cull, planeMask); } }
void Renderer::frustum_cull(glm::vec3 camera_position, SceneObject *object, float frustum[6][4], std::vector<SceneObject*>& scene_objects, bool need_cull, int planeMask) { // frustumCull() return 3 possible values: // 0 when the HBV of the object is completely outside the frustum: cull itself and all its children out // 1 when the HBV of the object is intersecting the frustum but the object itself is not: cull it out and continue culling test with its children // 2 when the HBV of the object is intersecting the frustum and the mesh BV of the object are intersecting (inside) the frustum: render itself and continue culling test with its children // 3 when the HBV of the object is completely inside the frustum: render itself and all its children without further culling test int cullVal; if (!object->enabled()) { return; } //allows for on demand calculation of the camera distance; usually matters //when transparent objects are in play RenderData* renderData = object->render_data(); if (nullptr != renderData) { renderData->setCameraDistanceLambda([object, camera_position]() { // Transform the bounding volume BoundingVolume bounding_volume_ = object->getBoundingVolume(); glm::vec4 transformed_sphere_center(bounding_volume_.center(), 1.0f); // Calculate distance from camera glm::vec4 position(camera_position, 1.0f); glm::vec4 difference = transformed_sphere_center - position; float distance = glm::dot(difference, difference); // this distance will be used when sorting transparent objects return distance; }); } if (need_cull) { cullVal = object->frustumCull(camera_position, frustum, planeMask); if (cullVal == 0) { object->setCullStatus(true); return; } if (cullVal >= 2) { object->setCullStatus(false); scene_objects.push_back(object); } if (cullVal == 3) { object->setCullStatus(false); need_cull = false; } } else { object->setCullStatus(false); scene_objects.push_back(object); } const std::vector<SceneObject*> children = object->children(); for (auto it = children.begin(); it != children.end(); ++it) { frustum_cull(camera_position, *it, frustum, scene_objects, need_cull, planeMask); } }
/* * Perform view frustum culling from a specific camera viewpoint */ void Renderer::cullFromCamera(Scene *scene, Camera* camera, ShaderManager* shader_manager) { std::vector<SceneObject*> scene_objects; glm::mat4 view_matrix = camera->getViewMatrix(); glm::mat4 projection_matrix = camera->getProjectionMatrix(); glm::mat4 vp_matrix = glm::mat4(projection_matrix * view_matrix); glm::vec3 campos(view_matrix[3]); scene_objects.reserve(1024); scene_objects.clear(); render_data_vector.clear(); // Travese all scene objects in the scene as a tree and do frustum culling at the same time if enabled // 1. Build the view frustum float frustum[6][4]; build_frustum(frustum, (const float*) glm::value_ptr(vp_matrix)); // 2. Iteratively execute frustum culling for each root object (as well as its children objects recursively) SceneObject *object = scene->getRoot(); if (DEBUG_RENDERER) { LOGD("FRUSTUM: start frustum culling for root %s\n", object->name().c_str()); } // frustum_cull(camera->owner_object()->transform()->position(), object, frustum, scene_objects, scene->get_frustum_culling(), 0); frustum_cull(campos, object, frustum, scene_objects, scene->get_frustum_culling(), 0); if (DEBUG_RENDERER) { LOGD("FRUSTUM: end frustum culling for root %s\n", object->name().c_str()); } // 3. do occlusion culling, if enabled occlusion_cull(scene, scene_objects, shader_manager, vp_matrix); }
/* * Perform view frustum culling from a specific camera viewpoint */ void Renderer::cullFromCamera(Scene *scene, Camera* camera, ShaderManager* shader_manager, std::vector<SceneObject*>& scene_objects) { render_data_vector.clear(); scene_objects.clear(); glm::mat4 view_matrix = camera->getViewMatrix(); glm::mat4 projection_matrix = camera->getProjectionMatrix(); glm::mat4 vp_matrix = glm::mat4(projection_matrix * view_matrix); // 1. Travese all scene objects in the scene as a tree and do frustum culling at the same time if enabled if (scene->get_frustum_culling()) { if (DEBUG_RENDERER) { LOGD("FRUSTUM: start frustum culling\n"); } // 1. Build the view frustum float frustum[6][4]; build_frustum(frustum, (const float*) glm::value_ptr(vp_matrix)); // 2. Iteratively execute frustum culling for each root object (as well as its children objects recursively) std::vector<SceneObject*> root_objects = scene->scene_objects(); for (auto it = root_objects.begin(); it != root_objects.end(); ++it) { SceneObject *object = *it; if (DEBUG_RENDERER) { LOGD("FRUSTUM: start frustum culling for root %s\n", object->name().c_str()); } frustum_cull(camera->owner_object()->transform()->position(), object, frustum, scene_objects, true, 0); if (DEBUG_RENDERER) { LOGD("FRUSTUM: end frustum culling for root %s\n", object->name().c_str()); } } if (DEBUG_RENDERER) { LOGD("FRUSTUM: end frustum culling\n"); } } else scene_objects = scene->getWholeSceneObjects(); // 2. do occlusion culling, if enabled occlusion_cull(scene, scene_objects, shader_manager, vp_matrix); }
int main() { int exit_flag = 0, i; MAT16F tmat; VEC3F pos = vec3f(0.0, 0.0, 0.5), ang = vec3f(0.0, 0.0, 0.0); MD2_MODEL mdl; VERTEX *model_verts; TRI *model_tris; if(load_md2("data/babe.md2", &mdl)) { allegro_message("Error: I need the MD2 model, stupid!"); exit(1); } convert_md2_to_base(&model_verts, &model_tris, &mdl, 0.02); init(); LOCK_VARIABLE(fps); LOCK_VARIABLE(frame_count); LOCK_FUNCTION(update_fps); install_int(update_fps, 1000); float frame = 0.0; int flag = 0, flag2 = 0; int anim_flag = 0, point_flag = 0; while(!exit_flag) { set_texture_mapping_mode(0); if(key[KEY_ESC]) { exit_flag = 1; } if(key[KEY_LEFT]) { pos.x -= 0.01; } if(key[KEY_RIGHT]) { pos.x += 0.01; } if(key[KEY_UP]) { pos.z += 0.02; } if(key[KEY_DOWN]) { pos.z -= 0.02; } if(key[KEY_SPACE]) { frame += 0.1; } if(key[KEY_P]) { anim_flag = anim_flag ? 0 : 1; key[KEY_P] = 0; } if(key[KEY_O]) { point_flag = point_flag ? 0 : 1; key[KEY_O] = 0; } VEC2F mp, cp; cp = vec2f(mouse_x, mouse_y); if(mouse_b == 1) { if(flag == 0) mp = cp; flag = 1; ang.y -= ((cp.x - mp.x) * 0.0002); } else flag = 0; if(mouse_b == 2) { if(flag2 == 0) mp = cp; flag2 = 1; pos.z -= ((cp.y - mp.y) * 0.0002); } else flag2 = 0; ang.x = M_PI * 1.5; convert_md2_frame_to_base(model_verts, &mdl, frame, 0.02); if(anim_flag) frame += 0.1 * (60.0 / (fps + 1.0)); reset_mat16f(tmat); rotate_mat16f(tmat, ang.x, ang.y, ang.z); translate_mat16f(tmat, pos.x, pos.y, pos.z); for(i = 0; i < mdl.header.num_vertices; i++) { transform_vec3f(&model_verts[i].world, model_verts[i].local, tmat); project_vertex(&model_verts[i]); } clear_bitmap(buffer); clear_to_color(zbuffer, ZBUFFER_PRECISION); for(i = 0; i < mdl.header.num_tris; i++) { update_tri_normal(&model_tris[i], model_verts); frustum_cull(&model_tris[i], model_verts, -0.95, 20.0); cull_backface(&model_tris[i], model_verts); } for(i = 0; i < mdl.header.num_tris; i++) if(model_tris[i].vis) my_triangle(buffer, model_verts, model_tris[i]); if(point_flag) for(i = 0; i < mdl.header.num_tris; i++) if(model_tris[i].vis) { int x1 = model_verts[model_tris[i].a].sx, y1 = model_verts[model_tris[i].a].sy, x2 = model_verts[model_tris[i].b].sx, y2 = model_verts[model_tris[i].b].sy, x3 = model_verts[model_tris[i].c].sx, y3 = model_verts[model_tris[i].c].sy; float z, z1 = model_verts[model_tris[i].a].screen.z, z2 = model_verts[model_tris[i].b].screen.z, z3 = model_verts[model_tris[i].c].screen.z; if(on_bitmap(x1, y1, SCREEN_W, SCREEN_H)) { z = (float)RI_PIXEL_Z(x1, y1) / (float)(ZBUFFER_PRECISION); if(z1 < z + 0.001) circlefill(buffer, x1, y1, 1, makecol(255, 0, 0)); } if(on_bitmap(x2, y2, SCREEN_W, SCREEN_H)) { z = (float)RI_PIXEL_Z(x2, y2) / (float)(ZBUFFER_PRECISION); if(z2 < z + 0.001) circlefill(buffer, x2, y2, 1, makecol(255, 0, 0)); } if(on_bitmap(x3, y3, SCREEN_W, SCREEN_H)) { z = (float)RI_PIXEL_Z(x3, y3) / (float)(ZBUFFER_PRECISION); if(z3 < z + 0.001) circlefill(buffer, x3, y3, 1, makecol(255, 0, 0)); } } textprintf_ex(buffer, font, 10, 10, makecol(255, 255, 255), 0, "FPS: %d", fps); blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); frame_count++; } free_md2(&mdl); free(model_tris); free(model_verts); destroy_bitmap(texture); destroy_bitmap(zbuffer); destroy_bitmap(buffer); deinit_renderer(); return 0; }
void main() { tcPosition[ID] = vPosition[ID]; tcIndex[ID] = vIndex[ID]; tcTessCoord[ID] = vTessCoord[ID]; vec4 data = texelFetch(attribute_texture, int(vIndex[ID]) * 5); if ( frustum_cull() ) { if ( abs(vTessCoord[0].x - vTessCoord[1].x) * abs(vTessCoord[1].y - vTessCoord[2].y) == 1.0 ) { vec4 curve_factor = clamp(texelFetch(attribute_texture, int(vIndex[ID]) * 5 + 4), 1, 4); vec4 edgelen = control_polygon_length(parameter_texture, int(data.x), int(data.y), int(data.z)); // 2 // 2------3 //3 | | 1 // | | // 0------1 // 0 float edge01 = edge_tesslevel(edgelen[0]); float edge32 = edge_tesslevel(edgelen[2]); float edge13 = edge_tesslevel(edgelen[1]); float edge20 = edge_tesslevel(edgelen[3]); //Following three must be same for Ist Pass gl_TessLevelInner[0] = inner_tesslevel(); gl_TessLevelOuter[1] = edge01; gl_TessLevelOuter[3] = edge32; //Following three must be same for Ist Pass gl_TessLevelInner[1] = inner_tesslevel(); gl_TessLevelOuter[0] = edge20; gl_TessLevelOuter[2] = edge13; } else { vec4 point_on_plane0 = to_screen_space(vPosition[0]); vec4 point_on_plane1 = to_screen_space(vPosition[1]); vec4 point_on_plane2 = to_screen_space(vPosition[2]); vec4 point_on_plane3 = to_screen_space(vPosition[3]); //Approach I-----> For Outer Tessellation Levels : Take ratio according to the original control polygon length. // For Inner Tessellation Levels : Evaluate the mid point of the patch and get the diagonal length. vec4 edgelen = control_polygon_length(parameter_texture, int(data.x), int(data.y), int(data.z)); vec2 p1 = mix(vTessCoord[0].xy, vTessCoord[1].xy, 0.5); vec2 p2 = mix(vTessCoord[3].xy, vTessCoord[2].xy, 0.5); vec2 mid_uv = mix(p1, p2, 0.5); vec4 du, dv, _puv; HornerBernstein(parameter_texture, int(data.x), int(data.y), int(data.z), mid_uv, du, dv, _puv); _puv = to_screen_space(_puv.xyz); float length1 = length(point_on_plane0.xy - _puv.xy) + length(_puv.xy - point_on_plane3.xy); float length2 = length(point_on_plane2.xy - _puv.xy) + length(_puv.xy - point_on_plane1.xy); float diagonal_length = min(length1, length2); float edge01 = edge_tesslevel(mix(edgelen[0], edgelen[2], abs(vTessCoord[0].y - vTessCoord[2].y))); float edge32 = edge_tesslevel(mix(edgelen[0], edgelen[2], abs(vTessCoord[0].y - vTessCoord[2].y))); float edge13 = edge_tesslevel(mix(edgelen[1], edgelen[3], abs(vTessCoord[0].x - vTessCoord[1].x))); float edge20 = edge_tesslevel(mix(edgelen[1], edgelen[3], abs(vTessCoord[0].x - vTessCoord[1].x))); /*****/ //Approach II-----> For Outer Tessellation Levels : Approximate the curvature length of the edge according to the angle between its normals. // For Inner Tessellation Levels : Approximate the curvature of the surface according to the all edge normals. //Normals projected in XY-Plane /* vec2 normal0 = normalize(transpose(inverse(mat3(view_matrix * model_matrix))) * vNormal[0].xyz).xy; vec2 normal1 = normalize(transpose(inverse(mat3(view_matrix * model_matrix))) * vNormal[1].xyz).xy; vec2 normal2 = normalize(transpose(inverse(mat3(view_matrix * model_matrix))) * vNormal[2].xyz).xy; vec2 normal3 = normalize(transpose(inverse(mat3(view_matrix * model_matrix))) * vNormal[3].xyz).xy; float edge01 = edge_tesslevel(length(point_on_plane0 - point_on_plane1) * acos(dot(normal0, normal1)) / (2.0 * sin(acos(dot(normal0, normal1) / 2.0)))); float edge32 = edge_tesslevel(length(point_on_plane3 - point_on_plane2) * acos(dot(normal3, normal2)) / (2.0 * sin(acos(dot(normal3, normal2) / 2.0)))); float edge13 = edge_tesslevel(length(point_on_plane1 - point_on_plane3) * acos(dot(normal1, normal3)) / (2.0 * sin(acos(dot(normal1, normal3) / 2.0)))); float edge20 = edge_tesslevel(length(point_on_plane2 - point_on_plane0) * acos(dot(normal2, normal0)) / (2.0 * sin(acos(dot(normal2, normal0) / 2.0))));*/ //Following three must be same for Ist Pass gl_TessLevelInner[0] = edge_tesslevel(diagonal_length); gl_TessLevelOuter[1] = edge01; gl_TessLevelOuter[3] = edge32; //Following three must be same for Ist Pass gl_TessLevelInner[1] = edge_tesslevel(diagonal_length); gl_TessLevelOuter[0] = edge20; gl_TessLevelOuter[2] = edge13; } } else { gl_TessLevelInner[0] = 1; gl_TessLevelOuter[1] = 1; gl_TessLevelOuter[3] = 1; gl_TessLevelInner[1] = 1; gl_TessLevelOuter[0] = 1; gl_TessLevelOuter[2] = 1; } }