void clipSegmentPlane(plane_struct* pl, polygon_struct** o, polygon_struct* pp1, polygon_struct* pp2) { if(!pl || !o)return; const vect3D v1=pp1->v;const vect3D v2=pp2->v; int32 val1=evaluatePlanePoint(pl,v1); int32 val2=evaluatePlanePoint(pl,v2); // const int32 val1=pp1->val; // const int32 val2=pp2->val=evaluatePlanePoint(pl,v2); if(val1>=0) { polygon_struct* p=createPolygon(v1); if(!p)return; p->next=*o; *o=p; if(val2<0) { vect3D dir=vectDifference(v2,v1); dir=vect(dir.x<<8,dir.y<<8,dir.z<<8); //improves precision, but limits polygon size; so be careful not to use polygons that are too big int32 dist=magnitude(dir); //not the actual distance between v1 and v2 but intersectSegmentPlane doesn't need it so... dir=divideVect(dir,dist); vect3D v=intersectSegmentPlane(pl,v1,dir,dist); p=createPolygon(v); if(!p)return; p->next=*o; *o=p; } }else{ if(val2>=0) { vect3D dir=vectDifference(v2,v1); dir=vect(dir.x<<8,dir.y<<8,dir.z<<8); //improves precision, but limits polygon size; so be careful not to use polygons that are too big int32 dist=magnitude(dir); //not the actual distance between v1 and v2 but intersectSegmentPlane doesn't need it so... dir=divideVect(dir,dist); vect3D v=intersectSegmentPlane(pl,v1,dir,dist); polygon_struct* p=createPolygon(v); if(!p)return; p->next=*o; *o=p; } } }
void ProjectorCamera::loadMatrices() { Camera::loadMatrices(); // adjust the camera frustum glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); const REAL ratio = m_width / static_cast<REAL>(m_height); const REAL scale = settings.dv_scale; gluPerspective(m_fovy * scale, ratio, m_near, m_far-1.0); GLdouble p[16]; glGetDoublev(GL_PROJECTION_MATRIX, p); Matrix4x4 perspective = Matrix4x4((REAL *)p).getTranspose(); glPopMatrix(); Matrix4x4 viewproj = perspective * m_modelview; Matrix4x4 inv_viewproj = viewproj.getInverse(); Vector4 *corners = new Vector4[8]; // Near plane (at z = 0) corners[0].x = -1, corners[0].y = -1, corners[0].z = 0, corners[0].w = 1; corners[1].x = 1, corners[1].y = -1, corners[1].z = 0, corners[1].w = 1; corners[2].x = -1, corners[2].y = 1, corners[2].z = 0, corners[2].w = 1; corners[3].x = 1, corners[3].y = 1, corners[3].z = 0, corners[3].w = 1; // Far plane (should be at z = 1) corners[4].x = -1, corners[4].y = -1, corners[4].z = 1, corners[4].w = 1; corners[5].x = 1, corners[5].y = -1, corners[5].z = 1, corners[5].w = 1; corners[6].x = -1, corners[6].y = 1, corners[6].z = 1, corners[6].w = 1; corners[7].x = 1, corners[7].y = 1, corners[7].z = 1, corners[7].w = 1; // transform to world space Vector4 v; for (int i = 0; i < 8; i++) { v = corners[i]; corners[i] = inv_viewproj * v; corners[i].homogenize(); } // get intersection points between the edges of // the camera frustum and the displacable volume std::list<Vector4> intersections; // delta denotes absolute distance of the bounding planes of the displaceable volume from the y=0 plane. // the value is set to 0 as I'm never going to use the displaceable volume idea. const REAL delta = 0.0; for (int i = 0; i < 4; i++) { if (intersectSegmentPlane(corners[i], corners[i+4], delta, v)) { v.y = 0; // project the point onto S_base intersections.push_front(v); } // don't intersect twice if delta is 0 if (delta > DBL_EPSILON && intersectSegmentPlane(corners[i], corners[i+4], -delta, v)) { v.y = 0; // project the point onto S_base intersections.push_front(v); } } /* * Intersect the edges of the far plane * The edge vertex indices are as follows: * * 6----------7 * | | * | | * | | * 4----------5 */ for (int i = 4; i < 8; i += 3) { for (int j = 5; j < 7; j++) { if (intersectSegmentPlane(corners[i], corners[j], delta, v)) { v.y = 0; // project the point onto S_base intersections.push_front(v); } if (delta > DBL_EPSILON && intersectSegmentPlane(corners[i], corners[j], -delta, v)) { v.y = 0; // project the point onto S_base intersections.push_front(v); } } } /* * Intersect the edges of the near plane * The edge vertex indices are as follows: * * 2----------3 * | | * | | * | | * 0----------1 */ for (int i = 0; i < 4; i += 3) { for (int j = 1; j < 3; j++) { if (intersectSegmentPlane(corners[i], corners[j], delta, v)) { v.y = 0; // project the point onto S_base intersections.push_front(v); } if (delta > DBL_EPSILON && intersectSegmentPlane(corners[i], corners[j], -delta, v)) { v.y = 0; // project the point onto S_base intersections.push_front(v); } } } // check if any of the corner points lie inside the volume and add them as well if (delta > DBL_EPSILON) { for (int i = 0; i < 8; i++) { v = corners[i]; if (v.y > -delta && v.y < delta) { v.y = 0; intersections.push_front(v); } } } // if no intersections are found, return false so that the surface isn't rendered if (intersections.size() == 0) { #ifdef PRINT_VALS logln("NOT VISIBLE"); #endif delete[] corners; grid_visible = false; return; } #ifdef PRINT_VALS logln("VISIBLE"); #endif grid_visible = true; // find the corner points of the grid // TODO: TEST THIS!! Vector4 center; for (std::list<Vector4>::iterator it = intersections.begin(); it != intersections.end(); ++it) { center += (viewproj * (*it)).getHomogenized(); } center /= intersections.size(); Vector4 lli,lri,uli,uri; lri = uli = uri = lli = center; for (std::list<Vector4>::iterator it = intersections.begin(); it != intersections.end(); ++it) { v = viewproj * (*it); v.homogenize(); if (v.x < center.x && v.y < lli.y) { lli = v; ll = (*it); } else if (v.x > center.x && v.y > uri.y) { uri = v; ur = (*it); } else if (v.x < center.x && v.y > uli.y) { uli = v; ul = (*it); } else if (v.x > center.x && v.y < lri.y) { lri = v; lr = (*it); } } #ifdef PRINT_VALS logln(intersections.size()); logln("RESULTS: \n"); logln(lli); logln(lri); logln(uli); logln(uri); #endif delete[] corners; // store the left and right sides of the projected grid delete[] left_points; left_points = new Vector4[settings.grid_resolution + 1]; delete[] right_points; right_points = new Vector4[settings.grid_resolution + 1]; delete[] depths; depths = new float[settings.grid_resolution + 1]; Vector4 screen_left = viewproj * ul; screen_left.homogenize(); Vector4 screen_right = viewproj * ur; screen_right.homogenize(); Vector4 left_dir = (viewproj * ll).homogenize() - screen_left; left_dir.unhomgenize(); left_dir = left_dir.getNormalized() * (left_dir.getMagnitude()/static_cast<REAL>(settings.grid_resolution)); Vector4 right_dir = (viewproj * lr).homogenize() - screen_right; right_dir.unhomgenize(); right_dir = right_dir.getNormalized() * (right_dir.getMagnitude()/static_cast<REAL>(settings.grid_resolution)); // handle boundary cases seperately, as the transformations cause epsilon errors left_points[0] = ul; right_points[0] = ur; left_points[settings.grid_resolution] = ll; right_points[settings.grid_resolution] = lr; screen_left += left_dir; screen_right += right_dir; depths[0] = 1; depths[settings.grid_resolution] = 0; Vector4 near, far; float OPTIMIZED_BIOTCH = (ul - ll).getMagnitude(); for (unsigned i = 1; i < settings.grid_resolution; i++) { far = (inv_viewproj * Vector4(screen_left.x, screen_left.y, 1, 1)).homogenize(); near = (inv_viewproj * Vector4(screen_left.x, screen_left.y, 0, 1)).homogenize(); intersectSegmentPlane(near, far, 0, v); left_points[i] = v; screen_left += left_dir; depths[i] = (v - ll).getMagnitude() / OPTIMIZED_BIOTCH; far = (inv_viewproj * Vector4(screen_right.x, screen_right.y, 1, 1)).homogenize(); near = (inv_viewproj * Vector4(screen_right.x, screen_right.y, 0, 1)).homogenize(); intersectSegmentPlane(near, far, 0, v); right_points[i] = v; screen_right += right_dir; } }