2 Physics Effects Copyright(C) 2010 Sony Computer Entertainment Inc.
\r
5 Physics Effects is open software; you can redistribute it and/or
\r
6 modify it under the terms of the BSD License.
\r
8 Physics Effects is distributed in the hope that it will be useful,
\r
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
\r
11 See the BSD License for more details.
\r
13 A copy of the BSD License is distributed with
\r
14 Physics Effects under the filename: physics_effects_license.txt
\r
17 #include "../../../include/physics_effects/base_level/collision/pfx_contact_manifold.h"
\r
20 namespace PhysicsEffects {
\r
22 #define SCE_PFX_CONTACT_SAME_POINT 0.01f
\r
23 #define SCE_PFX_CONTACT_THRESHOLD_NORMAL 0.01f // 衝突点の閾値(法線方向)
\r
24 #define SCE_PFX_CONTACT_THRESHOLD_TANGENT 0.002f // 衝突点の閾値(平面上)
\r
26 int PfxContactManifold::findNearestContactPoint(const PfxPoint3 &newPoint,const PfxVector3 &newNormal)
\r
28 int nearestIdx = -1;
\r
29 PfxFloat minDiff = SCE_PFX_CONTACT_SAME_POINT;
\r
30 for(int i=0;i<m_numContacts;i++) {
\r
31 PfxFloat diff = lengthSqr(pfxReadVector3(m_contactPoints[i].m_localPointA) - PfxVector3(newPoint));
\r
32 if(diff < minDiff && dot(newNormal,pfxReadVector3(m_contactPoints[i].m_constraintRow[0].m_normal)) > 0.99f) {
\r
40 int PfxContactManifold::sort4ContactPoints(const PfxPoint3 &newCP,PfxFloat newDistance)
\r
42 int maxPenetrationIndex = -1;
\r
43 PfxFloat maxPenetration = newDistance;
\r
45 // 最も深い衝突点は排除対象からはずす
\r
46 for(int i=0;i<SCE_PFX_NUMCONTACTS_PER_BODIES;i++) {
\r
47 if(m_contactPoints[i].m_distance < maxPenetration) {
\r
48 maxPenetrationIndex = i;
\r
49 maxPenetration = m_contactPoints[i].m_distance;
\r
53 PfxFloat res[4] = {0.0f};
\r
55 // 各点を除いたときの衝突点が作る面積のうち、最も大きくなるものを選択
\r
56 PfxVector3 newp(newCP);
\r
58 p[0] = pfxReadVector3(m_contactPoints[0].m_localPointA);
\r
59 p[1] = pfxReadVector3(m_contactPoints[1].m_localPointA);
\r
60 p[2] = pfxReadVector3(m_contactPoints[2].m_localPointA);
\r
61 p[3] = pfxReadVector3(m_contactPoints[3].m_localPointA);
\r
63 if(maxPenetrationIndex != 0) {
\r
64 PfxVector3 a0 = newp-p[1];
\r
65 PfxVector3 b0 = p[3]-p[2];
\r
66 res[0] = lengthSqr(cross(a0,b0));
\r
69 if(maxPenetrationIndex != 1) {
\r
70 PfxVector3 a1 = newp-p[0];
\r
71 PfxVector3 b1 = p[3]-p[2];
\r
72 res[1] = lengthSqr(cross(a1,b1));
\r
75 if(maxPenetrationIndex != 2) {
\r
76 PfxVector3 a2 = newp-p[0];
\r
77 PfxVector3 b2 = p[3]-p[1];
\r
78 res[2] = lengthSqr(cross(a2,b2));
\r
81 if(maxPenetrationIndex != 3) {
\r
82 PfxVector3 a3 = newp-p[0];
\r
83 PfxVector3 b3 = p[2]-p[1];
\r
84 res[3] = lengthSqr(cross(a3,b3));
\r
88 PfxFloat maxVal = res[0];
\r
90 if (res[1] > maxVal) {
\r
95 if (res[2] > maxVal) {
\r
100 if (res[3] > maxVal) {
\r
108 void PfxContactManifold::addContactPoint(
\r
109 PfxFloat newDistance,
\r
110 const PfxVector3 &newNormal, // world coords
\r
111 const PfxPoint3 &newPointA, // local to the objectA
\r
112 const PfxPoint3 &newPointB, // local to the objectB
\r
113 PfxSubData subData)
\r
115 int id = findNearestContactPoint(newPointA,newNormal);
\r
117 if(id < 0 && m_numContacts < SCE_PFX_NUMCONTACTS_PER_BODIES) {
\r
119 id = m_numContacts++;
\r
120 m_contactPoints[id].reset();
\r
124 id = sort4ContactPoints(newPointA,newDistance);
\r
125 m_contactPoints[id].reset();
\r
128 m_contactPoints[id].m_distance = newDistance;
\r
129 m_contactPoints[id].m_subData = subData;
\r
130 pfxStorePoint3(newPointA,m_contactPoints[id].m_localPointA);
\r
131 pfxStorePoint3(newPointB,m_contactPoints[id].m_localPointB);
\r
132 pfxStoreVector3(newNormal,m_contactPoints[id].m_constraintRow[0].m_normal);
\r
135 void PfxContactManifold::addContactPoint(const PfxContactPoint &cp)
\r
137 PfxPoint3 pA = pfxReadPoint3(cp.m_localPointA);
\r
139 int id = findNearestContactPoint(pA,pfxReadVector3(cp.m_constraintRow[0].m_normal));
\r
143 PfxVector3 nml1(pfxReadVector3(m_contactPoints[id].m_constraintRow[0].m_normal));
\r
144 PfxVector3 nml2(pfxReadVector3(cp.m_constraintRow[0].m_normal));
\r
145 if(fabsf(dot(nml1,nml2)) > 0.99f ) {
\r
146 // 同一点を発見、蓄積された情報を継続
\r
147 m_contactPoints[id].m_distance = cp.m_distance;
\r
148 m_contactPoints[id].m_localPointA[0] = cp.m_localPointA[0];
\r
149 m_contactPoints[id].m_localPointA[1] = cp.m_localPointA[1];
\r
150 m_contactPoints[id].m_localPointA[2] = cp.m_localPointA[2];
\r
151 m_contactPoints[id].m_localPointB[0] = cp.m_localPointB[0];
\r
152 m_contactPoints[id].m_localPointB[1] = cp.m_localPointB[1];
\r
153 m_contactPoints[id].m_localPointB[2] = cp.m_localPointB[2];
\r
154 m_contactPoints[id].m_constraintRow[0].m_normal[0] = cp.m_constraintRow[0].m_normal[0];
\r
155 m_contactPoints[id].m_constraintRow[0].m_normal[1] = cp.m_constraintRow[0].m_normal[1];
\r
156 m_contactPoints[id].m_constraintRow[0].m_normal[2] = cp.m_constraintRow[0].m_normal[2];
\r
159 // 同一点ではあるが法線が違うため更新
\r
160 m_contactPoints[id] = cp;
\r
163 if(m_contactPoints[id].m_distance > cp.m_distance) {
\r
165 m_contactPoints[id].m_distance = cp.m_distance;
\r
166 m_contactPoints[id].m_localPointA[0] = cp.m_localPointA[0];
\r
167 m_contactPoints[id].m_localPointA[1] = cp.m_localPointA[1];
\r
168 m_contactPoints[id].m_localPointA[2] = cp.m_localPointA[2];
\r
169 m_contactPoints[id].m_localPointB[0] = cp.m_localPointB[0];
\r
170 m_contactPoints[id].m_localPointB[1] = cp.m_localPointB[1];
\r
171 m_contactPoints[id].m_localPointB[2] = cp.m_localPointB[2];
\r
172 m_contactPoints[id].m_constraintRow[0].m_normal[0] = cp.m_constraintRow[0].m_normal[0];
\r
173 m_contactPoints[id].m_constraintRow[0].m_normal[1] = cp.m_constraintRow[0].m_normal[1];
\r
174 m_contactPoints[id].m_constraintRow[0].m_normal[2] = cp.m_constraintRow[0].m_normal[2];
\r
178 else if(m_numContacts < SCE_PFX_NUMCONTACTS_PER_BODIES) {
\r
180 m_contactPoints[m_numContacts++] = cp;
\r
184 id = sort4ContactPoints(pA,cp.m_distance);
\r
187 m_contactPoints[id] = cp;
\r
191 void PfxContactManifold::merge(const PfxContactManifold &contact)
\r
193 SCE_PFX_ALWAYS_ASSERT(m_rigidBodyIdA == contact.getRigidBodyIdA());
\r
194 SCE_PFX_ALWAYS_ASSERT(m_rigidBodyIdB == contact.getRigidBodyIdB());
\r
196 for(int i=0;i<contact.getNumContacts();i++) {
\r
197 addContactPoint(contact.getContactPoint(i));
\r
201 void PfxContactManifold::refresh(const PfxVector3 &pA,const PfxQuat &qA,const PfxVector3 &pB,const PfxQuat &qB)
\r
204 // 両衝突点間の距離が閾値(CONTACT_THRESHOLD)を超えたら消去
\r
205 for(int i=0;i<(int)m_numContacts;i++) {
\r
206 if(m_contactPoints[i].m_duration > 0) {
\r
207 PfxVector3 normal = pfxReadVector3(m_contactPoints[i].m_constraintRow[0].m_normal);
\r
208 PfxVector3 cpA = pA + rotate(qA,pfxReadVector3(m_contactPoints[i].m_localPointA));
\r
209 PfxVector3 cpB = pB + rotate(qB,pfxReadVector3(m_contactPoints[i].m_localPointB));
\r
211 // 貫通深度がプラスに転じたかどうかをチェック
\r
212 PfxFloat distance = dot(normal,(cpA - cpB));
\r
213 if(distance > SCE_PFX_CONTACT_THRESHOLD_NORMAL) {
\r
214 removeContactPoint(i);
\r
218 m_contactPoints[i].m_distance = distance;
\r
220 // 深度方向を除去して両点の距離をチェック
\r
221 cpA = cpA - m_contactPoints[i].m_distance * normal;
\r
222 PfxFloat distanceAB = lengthSqr(cpA - cpB);
\r
223 if(distanceAB > SCE_PFX_CONTACT_THRESHOLD_TANGENT) {
\r
224 removeContactPoint(i);
\r
229 if(m_contactPoints[i].m_duration < 255) m_contactPoints[i].m_duration++;
\r
231 if(m_numContacts > 0 && m_duration < 65535) m_duration++;
\r
233 } //namespace PhysicsEffects
\r