bool HeightFieldPrimitive::Intersect(const Ray &ray, Intersection *in) const { float tHit, rayEpsilon; if (TriangleIntersect(ray, pts, &tHit, &rayEpsilon) || TriangleIntersect(ray, &(pts[1]), &tHit, &rayEpsilon)) { in->tHit = tHit; in->primitive = this; in->rayEpsilon = rayEpsilon; return true; } return false; }
bool Intersect(const Ray &ray, RayHit& rayHit, BVHAccelArrayNode* bvhTree, Triangle *triangles, Point *vertices) { rayHit.t = INFINITY; rayHit.index = 0xffffffffu; unsigned int currentNode = 0; // Root Node unsigned int stopNode = bvhTree[0].skipIndex; // Non-existent bool hit = false; RayHit triangleHit; while (currentNode < stopNode) { if (BBox_IntersectP(bvhTree[currentNode].bbox, ray, NULL, NULL)) { if (bvhTree[currentNode].primitive != 0xffffffffu) { //float tt, b1, b2; Triangle t = triangles[bvhTree[currentNode].primitive]; if (TriangleIntersect(&t,ray, vertices, &triangleHit)) { hit = true; // Continue testing for closer intersections if (triangleHit.t < rayHit.t) { rayHit.t = triangleHit.t; rayHit.b1 = triangleHit.b1; rayHit.b2 = triangleHit.b2; rayHit.index = bvhTree[currentNode].primitive; } } } currentNode++; } else currentNode = bvhTree[currentNode].skipIndex; } return hit; }
//------------------------------------------------------------------------------- // @ ::CoplanarTriangleIntersect() //------------------------------------------------------------------------------- // Helper for TriangleIntersect() // // This projects the two triangles down to 2D, maintaining the largest area by // dropping the dimension where the normal points the farthest. //------------------------------------------------------------------------------- inline bool CoplanarTriangleIntersect( const IvVector3& P0, const IvVector3& P1, const IvVector3& P2, const IvVector3& Q0, const IvVector3& Q1, const IvVector3& Q2, const IvVector3& planeNormal ) { IvVector3 absNormal( ::IvAbs(planeNormal.x), ::IvAbs(planeNormal.y), ::IvAbs(planeNormal.z) ); IvVector2 projP0, projP1, projP2; IvVector2 projQ0, projQ1, projQ2; // if x is direction of largest magnitude if ( absNormal.x > absNormal.y && absNormal.x >= absNormal.z ) { projP0.Set( P0.y, P0.z ); projP1.Set( P1.y, P1.z ); projP2.Set( P2.y, P2.z ); projQ0.Set( Q0.y, Q0.z ); projQ1.Set( Q1.y, Q1.z ); projQ2.Set( Q2.y, Q2.z ); } // if y is direction of largest magnitude else if ( absNormal.y > absNormal.x && absNormal.y >= absNormal.z ) { projP0.Set( P0.x, P0.z ); projP1.Set( P1.x, P1.z ); projP2.Set( P2.x, P2.z ); projQ0.Set( Q0.x, Q0.z ); projQ1.Set( Q1.x, Q1.z ); projQ2.Set( Q2.x, Q2.z ); } // z is the direction of largest magnitude else { projP0.Set( P0.x, P0.y ); projP1.Set( P1.x, P1.y ); projP2.Set( P2.x, P2.y ); projQ0.Set( Q0.x, Q0.y ); projQ1.Set( Q1.x, Q1.y ); projQ2.Set( Q2.x, Q2.y ); } return TriangleIntersect( projP0, projP1, projP2, projQ0, projQ1, projQ2 ); }
//線分と三角形ポリゴンとの衝突判定 bool CCollision::IntersectTriangleRay(CVector3D *corss,const CVector3D &p1, const CVector3D &p2,const CVector3D &v0, const CVector3D &v1, const CVector3D &v2,float *pt ) { CVector3D e1, e2,normal,pv1,pv2; e1 = v1 - v0; e2 = v2 - v0; //面の法線を求める normal = CVector3D::Cross(e1, e2).GetNormalize(); //始点からポリゴン上のある地点(どこでもいい)へのベクトル pv1 = p1-v0; //終点からポリゴン上のある地点(どこでもいい)へのベクトル pv2 = p2-v0; //ポリゴンの法線との内積を求める float d1 = CVector3D::Dot(pv1,normal); float d2 = CVector3D::Dot(pv2,normal); //ポリゴンを貫通していない if(d1*d2>0) return false; //始点からポリゴンまでの距離と線分の長さの比率を求める //接地地点を出すのに使用する float t = d1/(d1-d2); if( *pt < t ) return false; //裏から貫通している場合は衝突していないことにする if(t<0) return false; //線分と平面の接地地点を求める CVector3D c = p1+(p2-p1)*t; //接地地点が三角形ポリゴン上か調べる if(!TriangleIntersect(c,v0,v1,v2,normal)) return false; if(pt) *pt = t; if(corss) *corss = c; return true; }
bool CCollision::CollisionTriangleCapsule(const CVector3D &v0,const CVector3D &v1,const CVector3D &v2,const CVector3D &top,const CVector3D &bottom,float radius,CVector3D *cross,float *length ){ CVector3D V(top-bottom); CVector3D VP; float Dist = 1e10; //ポリゴンの法線を求める CVector3D N(CVector3D::Cross(v1 - v0, v2 - v0).GetNormalize()); //始点からポリゴン上のある地点(どこでもいい)へのベクトル CVector3D PV1 = top-v0; //終点からポリゴン上のある地点(どこでもいい)へのベクトル CVector3D PV2 = bottom-v0; //ポリゴンの法線との内積を求める float d1 = CVector3D::Dot(PV1,N); float d2 = CVector3D::Dot(PV2,N); if(d1*d2<0) { //貫通している場合は線とポリゴンの判定を行う if(IntersectTriangleRay(cross,top+CVector3D(0,radius,0),bottom+CVector3D(0,-radius,0),v0,v1,v2,&Dist)) { if(length) { //貫通点までの距離を求める float lt = (*cross - top).LengthSq(); float lb = (*cross - bottom).LengthSq(); if(lt<lb) *length = sqrt(lt); else *length = sqrt(lb); } return true; } } d1=abs(d1); d2=abs(d2); //平面上の点との最短地点を求める CVector3D C1(top-N*d1); CVector3D C2(bottom-N*d2); //点が平面上にない場合は無効、後の辺との接触で調べる if(!TriangleIntersect(C1,v0,v1,v2,N)) d1=1e10; if(!TriangleIntersect(C2,v0,v1,v2,N)) d2=1e10; //面との距離が近い点の距離を選択 Dist = (d1<d2) ? d1:d2; if(Dist<=radius) { //追加 if(length) *length = Dist; return true; } //各辺との距離を求める Dist = min(min(DistanceLine(v0,v1,top,bottom),DistanceLine(v1,v2,top,bottom)),DistanceLine(v2,v0,top,bottom)); if(length) *length = Dist; return (Dist<=radius); }
//----------------------------------------------------------------------------- bool CCollision::CollisionTriangleSphere( const CVector3D &v0,const CVector3D &v1,const CVector3D &v2,const CVector3D ¢er,float radius ,CVector3D *cross,float *length) { CVector3D V1(v1-v0); CVector3D V2(v2-v1); CVector3D N(CVector3D::Cross(V1,V2).GetNormalize()); CVector3D V = center - v0; //平面と点の距離を求める float Dist = CVector3D::Dot(V,N); //球の半径より離れている場合は接触無し if(abs(Dist) > radius) return false; //点から平面上に垂直に下ろした地点を求める CVector3D Point = center - ( N * Dist ); //上記の点が三角形ポリゴン内なら接触している if(TriangleIntersect( Point, v0, v1, v2 , N)) { if(cross) *cross = Point; if(length) *length = Dist; return true; } //各辺に球がかすっている可能性がある //1辺ごとに球と辺の最短距離を求める //最短距離 float l; //最短接触地点 CVector3D c; //距離比較用 float LengthSq; //辺1(v0→v1) Point = PointOnLineSegmentNearestPoint( v0, v1, center ); LengthSq = (center - Point).LengthSq(); l = LengthSq; c = Point; //辺2(v1→v2) Point = PointOnLineSegmentNearestPoint( v1, v2, center ); LengthSq = (center - Point).LengthSq(); if(l>LengthSq) { l = LengthSq; c = Point; } //辺3(v2→v0) Point = PointOnLineSegmentNearestPoint( v2, v0, center ); LengthSq = (center - Point).LengthSq(); if(l>LengthSq) { l = LengthSq; c = Point; } l = sqrt(l); //最短距離を確定 if(length) *length = l; //最短地点を確定 if(cross) *cross = c; return (l<=radius); }
bool Heightfield2::Intersect(const Ray &r, float *tHit, float *rayEpsilon, DifferentialGeometry *dg) const{ Ray ray; (*WorldToObject)(r, &ray); float rayT; if(bounds.Inside(ray(ray.mint))) rayT = ray.mint; else if(!bounds.IntersectP(ray, &rayT)) return false; Point gridIntersect = ray(rayT); // Set up 2D DDA for ray float NextCrossingT[2], DeltaT[2]; int Step[2], Out[2], Pos[2]; for (int axis = 0; axis < 2; ++axis) { // Compute current voxel for axis Pos[axis] = posToVoxel(gridIntersect, axis); if (ray.d[axis] >= 0) { // Handle ray with positive direction for voxel stepping NextCrossingT[axis] = rayT + (voxelToPos(Pos[axis]+1, axis) - gridIntersect[axis]) / ray.d[axis]; DeltaT[axis] = width[axis] / ray.d[axis]; Step[axis] = 1; Out[axis] = nVoxels[axis]; } else { // Handle ray with negative direction for voxel stepping NextCrossingT[axis] = rayT + (voxelToPos(Pos[axis], axis) - gridIntersect[axis]) / ray.d[axis]; DeltaT[axis] = -width[axis] / ray.d[axis]; Step[axis] = -1; Out[axis] = -1; } } // Walk ray through voxel grid bool hitSomething = false; int index[3]; for (;;) { // Check for intersection in current voxel and advance to next index[0] = Pos[0] + Pos[1]*nx; index[1] = Pos[0]+1 + Pos[1]*nx; index[2] = Pos[0]+1 + (Pos[1]+1)*nx; hitSomething |= TriangleIntersect(r, tHit, rayEpsilon, dg, index); index[1] = Pos[0]+1 + (Pos[1]+1)*nx; index[2] = Pos[0] + (Pos[1]+1)*nx; hitSomething |= TriangleIntersect(r, tHit, rayEpsilon, dg, index); if(hitSomething) return hitSomething; // Advance to next voxel // Find _stepAxis_ for stepping to next voxel int stepAxis = (NextCrossingT[0] < NextCrossingT[1])? 0 : 1; Pos[stepAxis] += Step[stepAxis]; if (Pos[stepAxis] == Out[stepAxis]) break; NextCrossingT[stepAxis] += DeltaT[stepAxis]; } return hitSomething; }