void OutdoorLevel::CalculateLOD(const Vect &camPos, float detailAdjust) { DWORD i; Vect adjCamPos = camPos; adjCamPos.y = 0.0f; for(i=0; i<TerrainBlocks.Num(); i++) { TerrainBlock &block = TerrainBlocks[i]; Vect blockPos = block.bounds.GetCenter(); blockPos.y = 0.0f; float dist = blockPos.Dist(adjCamPos); block.curLOD = int(dist / detailAdjust); } for(i=0; i<TerrainBlocks.Num(); i++) { TerrainBlock &block = TerrainBlocks[i]; block.LODFlags = 0; DWORD firstRow = rowCount-1; DWORD lastRow = (rowCount*rowCount)-rowCount; if( (i % rowCount) && (TerrainBlocks[i-1].curLOD > block.curLOD)) block.LODFlags |= LOD_LEFTOPEN; if( ((i+1) % rowCount) && (TerrainBlocks[i+1].curLOD > block.curLOD)) block.LODFlags |= LOD_RIGHTOPEN; if( (i > firstRow) && (TerrainBlocks[i-rowCount].curLOD > block.curLOD)) block.LODFlags |= LOD_TOPOPEN; if( (i < lastRow) && (TerrainBlocks[i+rowCount].curLOD > block.curLOD)) block.LODFlags |= LOD_BOTTOMOPEN; } }
// yes, I realize this breaks on caps when the ray origin is inside the cylinder. // it's not like it's actually going to be in there anyway. BOOL CylinderRayCollision(const Vect ¢er, float radius, float height, const Vect &rayOrig, const Vect &rayDir, Vect *collision, Plane *collisionPlane) { Vect collisionValue; BOOL bHit = FALSE; float fT; Plane axisPlane(0.0f, 1.0f, 0.0f, center.y); //--------------------------------------- // test the cap if(fabs(rayDir.y) > EPSILON) { BOOL bUnder = (rayDir.y<0.0f); Plane planeCap; planeCap.Dir.Set(0.0f, bUnder ? 1.0f : -1.0f, 0.0f); planeCap.Dist = (bUnder ? center.y : -center.y)+height; if(rayOrig.DistFromPlane(planeCap) > 0.0f) { if(planeCap.GetRayIntersection(rayOrig, rayDir, fT)) { collisionValue = rayOrig+(rayDir*fT); Vect CapCenter = center+(planeCap.Dir*height); if(collisionValue.Dist(CapCenter) <= radius) { if(collisionPlane) *collisionPlane = planeCap; bHit = TRUE; } } } } if(!bHit && ((1.0f-fabs(rayDir.y)) > EPSILON)) { //--------------------------------------- // test the body Vect adjDir, adjCenter; adjDir.Set(rayDir.x, 0.0f, rayDir.z).Norm(); adjCenter.Set(center.x, rayOrig.y, center.z); Vect l = (adjCenter-rayOrig); float d = l | adjDir; //distance from adjDir Plane float l2 = l | l; //c-o distance squared float r2 = radius*radius; if(l2 < r2) //if inside the cylinder, fail return FALSE; if((d < 0.0f) && (l2 > r2)) //if the plane distance is negative, and return FALSE; //the distance is over the radius, fail float m2 = l2 - (d*d); //distance from the cylinder center to //the closest ray point if(m2 > r2) //if m2 is larger than the radius, fail return FALSE; float q = sqrt(r2-m2); //real distance from the edge of the //cylinder to the cloest ray point //(forms a sort of triangle) fT = (l2 > r2) ? (d-q) : (d+q); //if the distance is over the radius, //d-q = T, else d+q=T //distance fT /= (adjDir|rayDir); //divide by angle to get the proper //value collisionValue = rayOrig+(rayDir*fT); if(fabs(collisionValue.DistFromPlane(axisPlane)) >= height) return FALSE; if(collisionPlane) { Vect temp = collisionValue; temp.y = center.y; collisionPlane->Dir = (temp-center).Norm(); collisionPlane->Dist = collisionPlane->Dir|temp; } bHit = TRUE; } if(!bHit) return FALSE; if(collision) *collision = collisionValue; return TRUE; }