// this function tests if the projection of a bounding sphere along the light direction intersects // the view frustum bool SweptSpherePlaneIntersect( float& t0, float& t1, const SPlane& plane, const SVector3& pos, float radius, const SVector3& sweepDir ) { float b_dot_n = D3DXPlaneDotCoord(&plane, &pos); float d_dot_n = D3DXPlaneDotNormal(&plane, &sweepDir); if (d_dot_n == 0.f) { if (b_dot_n <= radius) { // effectively infinity t0 = 0.f; t1 = 1e32f; return true; } else return false; } else { float tmp0 = ( radius - b_dot_n) / d_dot_n; float tmp1 = (-radius - b_dot_n) / d_dot_n; t0 = min(tmp0, tmp1); t1 = max(tmp0, tmp1); return true; } }
TEST( Plane, dotNormal ) { Plane plane; Vector testPt; testPt.set( 3, 2, -1 ); plane.set( Quad_1000, FastFloat::fromFloat( 10.0f ) ); float dxDot = D3DXPlaneDotNormal( ( const D3DXPLANE* )&plane, ( const D3DXVECTOR3* )&testPt ); float tamyDot = plane.dotNormal( testPt ).getFloat(); CPPUNIT_ASSERT_DOUBLES_EQUAL( dxDot, tamyDot, 1e-3f ); testPt.set( 3, 2, -1 ); plane.set( Quad_Neg_0100, FastFloat::fromFloat( -12.0f ) ); dxDot = D3DXPlaneDotNormal( ( const D3DXPLANE* )&plane, ( const D3DXVECTOR3* )&testPt ); tamyDot = plane.dotNormal( testPt ).getFloat(); CPPUNIT_ASSERT_DOUBLES_EQUAL( dxDot, tamyDot, 1e-3f ); }
ViewFrustum::Containment ViewFrustum::ContainsBox(const BoundingBox& box) const { // Do OBB-plane test for each frustum plane for(size_t f = 0; f < 6; ++f) { D3DXVECTOR4 extent; extent.x = abs(D3DXPlaneDotNormal(&frustum[f], &box.vx)); extent.y = abs(D3DXPlaneDotNormal(&frustum[f], &box.vy)); extent.z = abs(D3DXPlaneDotNormal(&frustum[f], &box.vz)); extent.w = D3DXPlaneDotCoord(&frustum[f], &box.center); // Fail if centre + projected extents is outside the halfspace if(extent.w + extent.x + extent.y + extent.z < 0) return OUTSIDE; } // Neglect to test frustum multi-plane corner cases to save time; this still culls conservatively return INSIDE; }
RWinding *ClipToSeperators ( RWinding *source, RWinding *pass, RWinding *target, CLIP_SEPERATOR_DIR clipdir ) { long cur_src_point; long next_src_point; long cur_pass_point; rvector v1, v2; rplane plane; long i; float d; float length; long front_count; if( ! source || ! pass ) return target; // source의 모서리와 pass의 한점을 선택하는 모든 조합을 만든다. for (cur_src_point=0 ; cur_src_point<source->nCount; cur_src_point++) { // source 로부터 한 모서리를 선택한다. next_src_point = (cur_src_point+1)%source->nCount; v1 = source->pVertices[next_src_point] - source->pVertices[cur_src_point]; for (cur_pass_point=0 ; cur_pass_point<pass->nCount; cur_pass_point++) { // pass 로부터 한 점을 선택한다. v2 = pass->pVertices[cur_pass_point] - source->pVertices[cur_src_point]; // 선택한 모서리와 점으로 평면(plane)을 만든다. rvector normal; CrossProduct( &normal, v1 ,v2 ); length = DotProduct( normal, normal ); if (length < ON_EPSILON) continue; length = (float)sqrt(length); plane.a = normal.x/length; plane.b = normal.y/length; plane.c = normal.z/length; plane.d = -D3DXPlaneDotNormal(&plane,&pass->pVertices[cur_pass_point]); // plane과 source의위치관계를 조사한다. front_count = 0; for (i=0 ; i<source->nCount ; i++) { if (i == cur_src_point || i == next_src_point) continue; d = D3DXPlaneDotCoord(&plane,&source->pVertices[i]); if (d < -ON_EPSILON) break; if (d > ON_EPSILON) { front_count++; // source는 plane의 양쪽에 걸쳐져 있을 수 없다. // 따라서 한점만 앞에있어도 source가 앞에있다고 판단. break; } } // source가 plane상에 있는경우는 취급하지 않는다. // 이것은 [ 가시성 판단 3 ] 에서 처리한다. // [ 가시성 판단 3 ] 을 수행하지 않고 이 함수를 수행하려 한다면 // 함수가 좀 복잡해진다. if (i == source->nCount) continue; // source가 plane의 뒤쪽에 위치하도록 평면방정식을 조정한다. if ( front_count ) plane=-plane; // plane과 pass의위치관계를 조사한다. // pass가 plane의 앞쪽에 완전히 포함되는 경우, // plane으로 target을 클리핑한다. front_count = 0; for (i=0 ; i<pass->nCount; i++) { if (i==cur_pass_point) continue; d = D3DXPlaneDotCoord(&plane,&pass->pVertices[i]); if (d < -ON_EPSILON) break; if (d > ON_EPSILON) front_count++; } // 한점이라도 plane의 뒤쪽에 있으면 안된다. if (i != pass->nCount) continue; // pass가 평면에 포함되어서도 안된다. if ( ! front_count ) continue; // 입력된 parameter 가 // source -> pass -> target 순이 아니라 // pass -> source -> target 순이라면 plane을 뒤집어야 한다. if ( clipdir == CLIP_SEPERATOR_BACKWARD ) { plane=-plane; } // 여기까지 왔다면 plane은 뷰볼륨을 이루는 평면이다. // target을 잘라낸다. target = ClipWinding (target, plane); if (!target) return NULL; // target is not visible } } return target; }