int FrustumContainsSphere( CD3DCamera * pCamera, Sphere3f pSphere) { // various distances float fDistance; //$$$TEMP get the frustum planes from the camera's CULLINFO Plane3f plane[6]; CULLINFO *cInfo = pCamera->GetCullInfo(); for (int j=0; j<6; j++) { plane[j] = Plane3f( Vector3f(cInfo->planeFrustum[j].a, cInfo->planeFrustum[j].b, cInfo->planeFrustum[j].c), cInfo->planeFrustum[j].d); } // calculate our distances to each of the planes for(int i = 0; i < 6; ++i) { // find the distance to this plane //fDistance = plane[i].GetNormal().Dot(pSphere.Center()) + plane[i].GetNormal().Length(); //fDistance = plane[i].GetNormal().Dot(pSphere.Center()) + plane[i].DistanceTo(pSphere.Center()); fDistance = plane[i].GetNormal().Dot(pSphere.Center()) + plane[i][3]; // if this distance is < -sphere.radius, we are outside if(fDistance < -pSphere.Radius()) return(OUTSIDE); // else if the distance is between +- radius, then we intersect if((float)fabs(fDistance) < pSphere.Radius()) return(INTERSECT); } // otherwise we are fully in view return (INSIDE); }
void FrustumCamera::zoom( const Sphere3f &sphere, float fovy, bool adjustClipPlanes ) { DP_ASSERT( isPositive(sphere) ); // with some simple trigonometry, we get some factors for the distance and the window size: // alpha = fovy / 2 // dist from camera position to center = p => // sin( alpha ) = r / ( p * r ) = 1 / p // => p = 1 / sin( alpha ) // window size is 2 * q * r => // tan( alpha ) = ( q * r ) / ( p * r ) = q / p = q * sin( alpha ) // => q = tan( alpha ) / sin( alpha ) = 1 / cos( alpha ) float aspectRatio = getAspectRatio(); if ( fovy < 0.0f ) { // with negative fovy we keep the current // consider the aspect ratio with default fovy calculation float windowSize = (aspectRatio <= 1.0) ? getWindowSize()[0] : getWindowSize()[1]; fovy = (float)( 2.0 * atan( windowSize / ( 2.0 * getFocusDistance() ) ) ); } float alpha = fovy / 2.0f; float p = (float)( 1.0f / sinf( alpha ) ); float q = (float)( 1.0f / cosf( alpha ) ); // from the center go p*radius steps along the direction as the new position setPosition( sphere.getCenter() - p * sphere.getRadius() * getDirection() ); float radius = sphere.getRadius(); setFocusDistance( p * radius ); float size = q * 2.0f * radius; if ( aspectRatio <= 1.0f ) { // the window is higher than wide, so fit to the width and keep the aspect ratio setWindowSize( Vec2f( size, size / aspectRatio ) ); } else { // the window is wider than high, so fit to the height and keep the aspect ratio setWindowSize( Vec2f( size / aspectRatio, size ) ); } // note: don't touch near/far distance if AutoClipPlanes is off if ( adjustClipPlanes ) { // adjust the near and far distances to best fit m_nearDist = ( p - 1.0f ) * radius; m_farDist = ( p + 1.0f ) * radius; notify( PropertyEvent( this, PID_NearDistance ) ); notify( PropertyEvent( this, PID_FarDistance ) ); } }
void generateTexCoordsPlane( VertexAttributeSetSharedPtr const& vas, const Sphere3f &sphere, unsigned int tu ) { Buffer::ConstIterator<Vec3f>::Type vertices = vas->getVertices(); // get the bounding box of vas and determine the axes u,v to use to texture along unsigned int u, v, w; getSortedAxes( vertices, vas->getNumberOfVertices(), u, v, w ); // create the texture coordinates std::vector<Vec2f> texCoords( vas->getNumberOfVertices() ); Vec2f tp; float oneOverTwoR = 0.5f / sphere.getRadius(); Vec2f tpMin( 1.0f, 1.0f ); Vec2f tpMax( 0.0f, 0.0f ); for ( unsigned int i=0 ; i<vas->getNumberOfVertices() ; i++ ) { Vec3f p = vertices[i] - sphere.getCenter(); tp[0] = p[u] * oneOverTwoR + 0.5f; // 0.0 <= tp[0] <= 1.0 if ( tp[0] < tpMin[0] ) { tpMin[0] = tp[0]; } else if ( tp[0] > tpMax[0] ) { tpMax[0] = tp[0]; } tp[1] = p[v] * oneOverTwoR + 0.5f; // 0.0 <= tp[1] <= 1.0 if ( tp[1] < tpMin[1] ) { tpMin[1] = tp[1]; } else if ( tp[1] > tpMax[1] ) { tpMax[1] = tp[1]; } texCoords[i] = tp; } // scale the texcoords to [0..1] DP_ASSERT( ( FLT_EPSILON < ( tpMax[0] - tpMin[0] ) ) && ( FLT_EPSILON < ( tpMax[1] - tpMin[1] ) ) ); Vec2f tpScale( 1.0f / ( tpMax[0] - tpMin[0] ), 1.0f / ( tpMax[1] - tpMin[1] ) ); for ( unsigned int i=0 ; i<vas->getNumberOfVertices() ; i++ ) { texCoords[i] = Vec2f( ( texCoords[i][0] - tpMin[0] ) * tpScale[0], ( texCoords[i][1] - tpMin[1] ) * tpScale[1] ); } vas->setTexCoords( tu, &texCoords[0], vas->getNumberOfVertices() ); }
void generateTexCoordsCylinder( VertexAttributeSetSharedPtr const& vas, const Sphere3f &sphere, unsigned int tu ) { Buffer::ConstIterator<Vec3f>::Type vertices = vas->getVertices(); // get the bounding box of vas and determine the axes u,v to use to texture along unsigned int u, v, w; getSortedAxes( vertices, vas->getNumberOfVertices(), u, v, w ); // create the texture coordinates std::vector<Vec2f> texCoords( vas->getNumberOfVertices() ); Vec2f tp; float oneOverTwoR = 0.5f / sphere.getRadius(); float tpuMin = 1.0f; float tpuMax = 0.0f; for ( unsigned int i=0 ; i<vas->getNumberOfVertices() ; i++ ) { Vec3f p = vertices[i] - sphere.getCenter(); // largest axis as the cylinder axis tp[0] = p[u] * oneOverTwoR + 0.5f; // 0.0 <= tp[1] <= 1.0 if ( tp[0] < tpuMin ) { tpuMin = tp[0]; } else if ( tpuMax < tp[0] ) { tpuMax = tp[0]; } if ( FLT_EPSILON < fabsf( p[v] ) ) { tp[1] = 0.5f * atan2f( p[w], -p[v] ) / (float) PI + 0.5f; } else { tp[1] = (float)( ( 0.0f <= p[w] ) ? 0.75f : 0.25f ); } texCoords[i] = tp; } // scale the texcoords to [0..1] DP_ASSERT( FLT_EPSILON < ( tpuMax - tpuMin ) ); float tpuScale = 1.0f / ( tpuMax - tpuMin ); for ( unsigned int i=0 ; i<vas->getNumberOfVertices() ; i++ ) { texCoords[i][0] = ( texCoords[i][0] - tpuMin ) * tpuScale; } vas->setTexCoords( tu, &texCoords[0], vas->getNumberOfVertices() ); }
void generateTexCoordsSphere( VertexAttributeSetSharedPtr const& vas, const Sphere3f &sphere, unsigned int tu ) { Buffer::ConstIterator<Vec3f>::Type vertices = vas->getVertices(); std::vector<Vec2f> texCoords( vas->getNumberOfVertices() ); Vec2f tp; for ( unsigned int i=0 ; i<vas->getNumberOfVertices() ; i++ ) { Vec3f p = vertices[i] - sphere.getCenter(); if ( fabsf( p[1] ) > FLT_EPSILON ) { tp[0] = 0.5f * atan2f( p[0], -p[1] ) / (float) PI + 0.5f; } else { tp[0] = (float)( ( p[0] >= 0.0f ) ? 0.75f : 0.25f ); } float d = sqrtf( square( p[0] ) + square( p[1] ) ); if ( d > FLT_EPSILON ) { tp[1] = atan2f( p[2], d ) / (float) PI + 0.5f; } else { tp[1] = (float)( ( p[2] >= 0.0f ) ? 1.0f : 0.0f ); } texCoords[i] = tp; } vas->setTexCoords( tu, &texCoords[0], vas->getNumberOfVertices() ); }
Ego::Math::Relation sphere_intersects_sphere(const Sphere3f& lhs, const Sphere3f& rhs) { Ego::Math::Relation retval = Ego::Math::Relation::error; // Get the separating axis Vector3f vdiff = lhs.getCenter() - rhs.getCenter(); // Get the distance squared. float dist2 = vdiff.length_2(); if (rhs.getRadius() < lhs.getRadius()) { if (dist2 < lhs.getRadius() * lhs.getRadius()) { retval = Ego::Math::Relation::inside; } } if (Ego::Math::Relation::inside != retval) { // Get the sum of the radii. float fRadiiSum = lhs.getRadius() + rhs.getRadius(); // If the distance between the centers is less than the sum of the radii, // then we have an intersection we calculate lhs using the squared lengths for speed. if (dist2 < fRadiiSum * fRadiiSum) { retval = Ego::Math::Relation::intersect; } else { retval = Ego::Math::Relation::outside; } } return retval; }
CullCode PerspectiveCamera::determineCullCode( const Sphere3f &sphere ) const { // For each of the six frustum planes determine the signed distance of the center to the plane. // Take the plane equation n*x + d = 0, with n the plane normal, x a point on the plane, and d // the negative distance of the plane to the origin. // With p an arbitrary point, we get n*p + d = c, with c the signed distance of p from the plane. // c > 0 <=> p is 'above' the plane (the normal points from the plane to the point) // c < 0 <=> p is 'below' the plane (the normal points from the point to the plane) // Determine for each of the six frustum planes a plane equation with the normal pointing // inward, meaning positive values of c are in, negative are out. // Taking as the arbitrary point p the center of the bounding sphere, we get the following // results (with r the radius of the bounding sphere): // c + r < 0 <=> center is more than radius below the plane <=> bounding sphere is completely outside // c - r > 0 <=> center is more than radius above the plane <=> bounding sphere is completely inside // otherwise <=> bounding sphere intersects the frustum at this plane. // If the bounding sphere is completely outside relative to at least one plane, it is out. // If the bounding sphere is completely inside relative to all planes, it is in. // Otherwise it is partial. const Box2f & region = getWindowRegion(); // Determine the (signed) distances of the left and right window border from the target point. float hl = getWindowOffset()[0] + getWindowSize()[0] * ( region.getLower()[0] - 0.5f ); float hr = getWindowOffset()[0] + getWindowSize()[0] * ( region.getUpper()[0] - 0.5f ); // Determine the (signed) distances of the bottom and top window border from the target point. float hb = getWindowOffset()[1] + getWindowSize()[1] * ( region.getLower()[1] - 0.5f ); float ht = getWindowOffset()[1] + getWindowSize()[1] * ( region.getUpper()[1] - 0.5f ); // Each of the four side planes are determined by two of the window vertices and the origin // (apex of the frustum. The normals of the right and left side are in the x-z-plane; the // normals of the top and bottom side are in the y-z-plane. // With t the target distance, sx the window size in x, we get d = sqrt( t*t + 0.25*sx*sx ), // the distance from the camera to the right border of the window. With alpha horizontal // field of view, we get sinAlpha = 0.5 * sx / d, cosAlpha = t / d. // We also have to take the window offset and window region into account (e.g. in a cluster). // front plane: n = 0,0,-1, p = 0,0,-near => n*p + d = near + d = 0 => d = -near // => cf = n * c + d = -center.z - near // back plane : n = 0,0,+1, p = 0,0,-far => n*p + d = -far + d = 0 => d = far // => cb = n * c + d = center.z + far // Determine the distances from the camera to those points. float tSquare = square( getFocusDistance() ); float dl = sqrt( tSquare + square( hl ) ); float dr = sqrt( tSquare + square( hr ) ); // Determine sine and cosine of the vector from the camera along the border of the frustum. float sal = hl / dl; float cal = getFocusDistance() / dl; float sar = hr / dr; float car = getFocusDistance() / dr; // Now the vectors from the camera to the left and right borders are // vl = [sal,0,-cal] => nl = [cal,0,sal] // vr = [sar,0,-car] => nr = [-car,0,-sar] // left plane: nl = [-cal,0,sal], p = 0,0,0 => n*p + d = 0 + d = 0 => d = 0 // => cl = nl * c + d = cal * center.x + sal * center.z // right plane: nr = [-car,0,-sar], p = 0,0,0 => n*p + d = 0 + d = 0 => d = 0 // => cr = nr * c + d = -car * center.x - sar * center.z float cl = cal * sphere.getCenter()[0] + sal * sphere.getCenter()[2]; float cr = - car * sphere.getCenter()[0] - sar * sphere.getCenter()[2]; // Determine the distances from the camera to those points. float db = sqrt( tSquare + square( hb ) ); float dt = sqrt( tSquare + square( ht ) ); // Determine sine and cosine of the vector from the camera along the border of the frustum. float sab = hb / db; float cab = getFocusDistance() / db; float sat = ht / dt; float cat = getFocusDistance() / dt; // Now the vectors from the camera to the bottom and top borders are // vb = [0,sab,-cab] => nb = [0,cab,sab] // vt = [0,sat,-cat] => nt = [0,-cat,-sat] // bottom plane: nb = [0,cab,sab], ... => d = 0 // => cb = nb * c + d = cab * center.y + sab * center.z // top plane: nt = [0,-cat,-sat], ... => d = 0 // => ct = nt * c + d = -cat * center.y - sat * center.z float cb = cab * sphere.getCenter()[1] + sab * sphere.getCenter()[2]; float ct = - cat * sphere.getCenter()[1] - sat * sphere.getCenter()[2]; CullCode cc; if ( ( - sphere.getCenter()[2] - getNearDistance() + sphere.getRadius() < 0.0f ) || ( sphere.getCenter()[2] + getFarDistance() + sphere.getRadius() < 0.0f ) || ( cl + sphere.getRadius() < 0.0f ) || ( cr + sphere.getRadius() < 0.0f ) || ( cb + sphere.getRadius() < 0.0f ) || ( ct + sphere.getRadius() < 0.0f ) ) { cc = CC_OUT; } else if ( ( 0.0f < - sphere.getCenter()[2] - getNearDistance() - sphere.getRadius() ) && ( 0.0f < sphere.getCenter()[2] + getFarDistance() - sphere.getRadius() ) && ( 0.0f < cl - sphere.getRadius() ) && ( 0.0f < cr - sphere.getRadius() ) && ( 0.0f < cb - sphere.getRadius() ) && ( 0.0f < ct - sphere.getRadius() ) ) { cc = CC_IN; } else { cc = CC_PART; } return( cc ); }