Possibility of multiple material per object?

A place to discuss everything related to Newton Dynamics.

Moderators: Sascha Willems, walaber

Possibility of multiple material per object?

Postby jiandingzhe » Sat Jul 23, 2011 2:05 am

The game I'm making is related with armor and armor piercing. In real world, different sides of a tank / vessel / turret has different thickness of armor.
So I need to know which surface a bullet hits at, and I need to attach some armor related data to surfaces. How can I do that with Newton?
User avatar
jiandingzhe
 
Posts: 48
Joined: Fri Jul 08, 2011 11:21 am
Location: Beijing


Re: Possibility of multiple material per object?

Postby jiandingzhe » Sat Jul 30, 2011 11:44 pm


Thanks! So I should firstly look at the advanced tutorials.
User avatar
jiandingzhe
 
Posts: 48
Joined: Fri Jul 08, 2011 11:21 am
Location: Beijing

Re: Possibility of multiple material per object?

Postby jiandingzhe » Tue Aug 02, 2011 10:54 pm


It does not help on my situation.
It seems NewtonMaterialGetContactFaceAttribute() only works with tree collisions, and tree collisions can only be used as static objects. However, what I need is colliding faces of moving objects.
User avatar
jiandingzhe
 
Posts: 48
Joined: Fri Jul 08, 2011 11:21 am
Location: Beijing

Re: Possibility of multiple material per object?

Postby Julio Jerez » Wed Aug 03, 2011 1:30 pm

convex pieces are monolitic objects, It will be too difficult to add per feature infomation as internal funtion of the engine.
however you could do it in your side with a small amount of work, all of the funtionality is in the engine tools.

Basically a convex hull in an array of featutes, the convex hull structure contain a list features as indices, faces, and edges.
all you need to do subclass dgConvexFull3d, and add an array of indices to place per face ids.

then save then add a function similar to closest point, but have that function returning the index to the closest feature to a point.
then that value index by that array will value on the table will be the ID you want.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Possibility of multiple material per object?

Postby jiandingzhe » Wed Aug 10, 2011 11:02 pm

Julio Jerez wrote:convex pieces are monolitic objects, It will be too difficult to add per feature infomation. as a funtion of teh engine.
however you could do it in your side with a small amopunt of work, all of teh funtionality is in the engine tools.

Basically a convex hull in an array of featutes, the convex hull structure contain a listt features as indices as faces, and edges.
all you need to do subclass dgConvexFull, and add an array of indices and place the ids on the array.
then save then add a function similar to closest point, but have that function returning the index to the closest feature to a point.
then that value index by that array will value on the table will be the ID you want.


I've had a look at your code of dgCollisionConvexHull, but don't really understand its data organization.

I've notices there is an array named "m_faceArray", which stores info about traverse through all half-edges, and an vertex index. However where is the data of vertices? And does the convex hull actually has NO surface data, but ONLY have vertex data, and semi-edge traverse?
User avatar
jiandingzhe
 
Posts: 48
Joined: Fri Jul 08, 2011 11:21 am
Location: Beijing

Re: Possibility of multiple material per object?

Postby Julio Jerez » Fri Aug 12, 2011 11:37 am

No I do not mean dgCollisionConvexHull, that class funtion Create to generate a general convex hull, and the compile it for faster acess.
beasicall it places the information into array, removing pointer indirection, it also add some other arrays for faster loock using in collision.


I've notices there is an array named "m_faceArray", which stores info about traverse through all half-edges, and an vertex index. However where is the data of vertices? And does the convex hull actually has NO surface data, but ONLY have vertex data, and semi-edge traverse?

yes this is correct, teh face are face array is no stored because face can be any size, however you cna ge teh face by usin teh face and flowwing teh next pointr lie this

Code: Select all
faceIndex[N]
index = 0;
ptr = face;
do {
   FaceIndex[index ++] = ptr->vertexIndex;
   facePtr = ptr->Next
} while (ptr != face);



the function that Generate teh Hull uses that General Purpose routine is this.
Code: Select all
bool dgCollisionConvexHull::Create (dgInt32 count, dgInt32 strideInBytes, const dgFloat32* const vertexArray, dgFloat32 tolerance)
{
   dgInt32 stride = strideInBytes / sizeof (dgFloat32);
   dgStack<dgFloat64> buffer(3 * count);
   for (dgInt32 i = 0; i < count; i ++) {
      buffer[i * 3 + 0] = vertexArray[i * stride + 0];
      buffer[i * 3 + 1] = vertexArray[i * stride + 1];
      buffer[i * 3 + 2] = vertexArray[i * stride + 2];
   }

   dgConvexHull3d* convexHull =  new (GetAllocator()) dgConvexHull3d (GetAllocator(), &buffer[0], 3 * sizeof (dgFloat64), count, tolerance);
   if (!convexHull->GetCount()) {
      delete convexHull;
      return false;
   }

   // check for degenerated faces
   for (bool success = false; !success;  ) {
      success = true;
      const dgBigVector* const hullVertexArray = convexHull->GetVertexPool();

      dgStack<dgInt8> mask(convexHull->GetVertexCount());
      memset (&mask[0], 1, mask.GetSizeInBytes());
      for (dgConvexHull3d::dgListNode* node = convexHull->GetFirst(); node; node = node->GetNext()) {
         dgConvexHull3DFace& face = node->GetInfo();
         const dgBigVector& p0 = hullVertexArray[face.m_index[0]];
         const dgBigVector& p1 = hullVertexArray[face.m_index[1]];
         const dgBigVector& p2 = hullVertexArray[face.m_index[2]];
         dgBigVector p1p0 (p1 - p0);
         dgBigVector p2p0 (p2 - p0);
         dgBigVector normal (p2p0 * p1p0);
         dgFloat64 mag2 = normal % normal;
         if (mag2 < dgFloat64 (1.0e-6f * 1.0e-6f)) {
            success = false;
            dgInt32 index = -1;
            dgBigVector p2p1 (p2 - p1);
            dgFloat64 dist10 = p1p0 % p1p0;
            dgFloat64 dist20 = p2p0 % p2p0;
            dgFloat64 dist21 = p2p1 % p2p1;
            if ((dist10 >= dist20) && (dist10 >= dist21)) {
               index = 2;
            } else if ((dist20 >= dist10) && (dist20 >= dist21)) {
               index = 1;
            } else if ((dist21 >= dist10) && (dist21 >= dist20)) {
               index = 0;
            }
            _ASSERTE (index != -1);
            mask[face.m_index[index]] = 0;
         }
      }
      if (!success) {
         dgInt32 count = 0;
         dgInt32 vertexCount = convexHull->GetVertexCount();
         for (dgInt32 i = 0; i < vertexCount; i ++) {
            if (mask[i]) {
               buffer[count * 3 + 0] = hullVertexArray[i].m_x;
               buffer[count * 3 + 1] = hullVertexArray[i].m_y;
               buffer[count * 3 + 2] = hullVertexArray[i].m_z;
               count ++;
            }
         }
         delete convexHull;
         convexHull =  new (GetAllocator()) dgConvexHull3d (GetAllocator(), &buffer[0], 3 * sizeof (dgFloat64), count, tolerance);
      }
   }


   dgInt32 vertexCount = convexHull->GetVertexCount();
   const dgBigVector* const hullVertexArray = convexHull->GetVertexPool();

   dgPolyhedra polyhedra (GetAllocator());
   polyhedra.BeginFace();
   for (dgConvexHull3d::dgListNode* node = convexHull->GetFirst(); node; node = node->GetNext()) {
      dgConvexHull3DFace& face = node->GetInfo();
      polyhedra.AddFace (face.m_index[0], face.m_index[1], face.m_index[2]);
   }

   polyhedra.EndFace();
   

   if (vertexCount > 4) {
      bool edgeRemoved = false;
      while (RemoveCoplanarEdge (polyhedra, hullVertexArray)) {
         edgeRemoved = true;
      }
      if (edgeRemoved) {
         if (!CheckConvex (polyhedra, hullVertexArray)) {
            return false;
         }
      }
   }

   dgInt32 maxEdgeCount = polyhedra.GetCount();

   dgStack<dgEdge*> stack(1024 + maxEdgeCount);
   dgEdge* firstFace = &polyhedra.GetRoot()->GetInfo();

   _ASSERTE (firstFace->m_twin->m_next != firstFace);

   dgInt32 stackIndex = 1;
   stack[0] = firstFace;

   dgStack<dgInt32> vertexMap(vertexCount);
   memset (&vertexMap[0], -1, vertexCount * sizeof (dgInt32));

//   m_edgeCount = 0;
//   m_vertexCount = 0;

   dgInt32 i1 = polyhedra.IncLRU();
   while (stackIndex) {
      stackIndex --;
      dgEdge* const edge0 = stack[stackIndex];

      if (edge0->m_mark != i1) {
         if (vertexMap[edge0->m_incidentVertex] == -1) {
            vertexMap[edge0->m_incidentVertex] = m_vertexCount;
            m_vertexCount ++;
         }
         dgEdge* ptr = edge0;
         do {
            stack[stackIndex] = ptr->m_twin;
            stackIndex++;
            ptr->m_mark = i1;
            ptr->m_userData = m_edgeCount;
            m_edgeCount ++;
            ptr = ptr->m_twin->m_next;
         } while (ptr != edge0) ;
      }
   }

   m_vertex = (dgVector*) m_allocator->Malloc (dgInt32 (m_vertexCount * sizeof (dgVector)));
   m_simplex = (dgConvexSimplexEdge*) m_allocator->Malloc (dgInt32 (m_edgeCount * sizeof (dgConvexSimplexEdge)));

   for (dgInt32 i = 0; i < vertexCount; i ++) {
      if (vertexMap[i] != -1) {
         m_vertex[vertexMap[i]] = hullVertexArray[i];
         m_vertex[vertexMap[i]].m_w = dgFloat32 (1.0f);
      }
   }

   i1 = polyhedra.IncLRU();
   stackIndex = 1;
   stack[0] = firstFace;
   while (stackIndex) {

      stackIndex --;
      dgEdge* const edge0 = stack[stackIndex];

      if (edge0->m_mark != i1) {

         dgEdge *ptr = edge0;
         do {
            ptr->m_mark = i1;
            stack[stackIndex] = ptr->m_twin;
            stackIndex++;

            dgConvexSimplexEdge* const simplexPtr = &m_simplex[ptr->m_userData];
            simplexPtr->m_vertex = vertexMap[ptr->m_incidentVertex];
            simplexPtr->m_next = &m_simplex[ptr->m_next->m_userData];
            simplexPtr->m_prev = &m_simplex[ptr->m_prev->m_userData];
            simplexPtr->m_twin = &m_simplex[ptr->m_twin->m_userData];

            ptr = ptr->m_twin->m_next;
         } while (ptr != edge0) ;
      }
   }

   SetVolumeAndCG ();
   m_faceCount = 0;
   dgStack<char> mark (m_edgeCount);
   memset (&mark[0], 0, m_edgeCount * sizeof (dgInt8));

   dgStack<dgConvexSimplexEdge*> faceArray (m_edgeCount);
   for (dgInt32 i = 0; i < m_edgeCount; i ++) {
      dgConvexSimplexEdge* const face = &m_simplex[i];
      if (!mark[i]) {
         dgConvexSimplexEdge* ptr = face;
         do {
            _ASSERTE ((ptr - m_simplex) >= 0);
            mark[dgInt32 (ptr - m_simplex)] = '1';
            ptr = ptr->m_next;
         } while (ptr != face);

         faceArray[m_faceCount] = face;
         m_faceCount ++;
      }
   }
   m_faceArray = (dgConvexSimplexEdge **) m_allocator->Malloc(dgInt32 (m_faceCount * sizeof(dgConvexSimplexEdge *)));
   memcpy (m_faceArray, &faceArray[0], m_faceCount * sizeof(dgConvexSimplexEdge *));

   delete convexHull;
   return true;
}




as you can see teh fist part

Code: Select all
bool dgCollisionConvexHull::Create (dgInt32 count, dgInt32 strideInBytes, const dgFloat32* const vertexArray, dgFloat32 tolerance)
{
   dgInt32 stride = strideInBytes / sizeof (dgFloat32);
   dgStack<dgFloat64> buffer(3 * count);
   for (dgInt32 i = 0; i < count; i ++) {
      buffer[i * 3 + 0] = vertexArray[i * stride + 0];
      buffer[i * 3 + 1] = vertexArray[i * stride + 1];
      buffer[i * 3 + 2] = vertexArray[i * stride + 2];
   }

   dgConvexHull3d* convexHull =  new (GetAllocator()) dgConvexHull3d (GetAllocator(), &buffer[0], 3 * sizeof (dgFloat64), count, tolerance);
...


make a General conve Hull using class dgConvexHull3d
then it uses that class to create the optimized for collison struture

what I mean is the you can do the same, subclass dgConvexHull3d , and then add an extra array to store the face infomation for each face index.
Then to get a Per Face collision info you call RayCast for by Making a Line segmen startion from teh contact point and move alone the normal.

That will be the simpler wat toi get teh most acurate indomation,

Adding the funtionality to the dgCollisionConvexHull is not a solution since the contact point caculated during teh narraw face collision are posprosses by the dgMinsloasky code.
so the contact may no be teh same.

you can however add faceAtribute array to class dgCollisionConvexHull instead of having a parallel struture, but that is harder and may add problem with future updates.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Possibility of multiple material per object?

Postby jiandingzhe » Mon Aug 15, 2011 6:22 am

Julio Jerez wrote:
what I mean is the you can do the same, subclass dgConvexHull3d , and then add an extra array to store the face infomation for each face index.
Then to get a Per Face collision info you call RayCast for by Making a Line segmen startion from teh contact point and move alone the normal.

That will be the simpler wat toi get teh most acurate indomation,

Adding the funtionality to the dgCollisionConvexHull is not a solution since the contact point caculated during teh narraw face collision are posprosses by the dgMinsloasky code.
so the contact may no be teh same.

you can however add faceAtribute array to class dgCollisionConvexHull instead of having a parallel struture, but that is harder and may add problem with future updates.


How can I know the face index from RayCast?
Code: Select all
dgFloat64 dgConvexHull3d::RayCast (const dgBigVector& localP0, const dgBigVector& localP1) const

It only returns a float. Do I need to create my own version of RayCast that store the hit face?
User avatar
jiandingzhe
 
Posts: 48
Joined: Fri Jul 08, 2011 11:21 am
Location: Beijing

Re: Possibility of multiple material per object?

Postby Julio Jerez » Mon Aug 15, 2011 10:40 am

Yes you make you version adpedted to you need, that is what teh convex hull shape does.
you subclass class dgConvexHull3d, then you take function RayCast and you write a similar one but keeping track of the face number that was last hit by the race.
something like this:

Code: Select all
class MyConveHull: public dgConvexHull3d
{
    ..

   dgInt32 GetFaceHit() const
   {
      return m_lastFaceHit;
   }
   
   dgFloat64 MyRayCast (const dgBigVector& localP0, const dgBigVector& localP1) const
   {
      dgFloat64 interset = dgFloat32 (1.2f);

      dgFloat64 tE = dgFloat64 (0.0f);           //for the maximum entering segment parameter;
      dgFloat64 tL = dgFloat64 (1.0f);           //for the minimum leaving segment parameter;
      dgBigVector dS (localP1 - localP0); // is the segment direction vector;

      // addapt raycast to track face hit
      m_lastFaceHit = -1;
      dgInt32 faceIndex = -1;

      dgInt32 hasHit = 0;
      
      for (dgListNode* node = GetFirst(); node; node = node->GetNext()) {
         const dgConvexHull3DFace* const face = &node->GetInfo();

         // addapt raycast to track face hit
         faceIndex ++;
         dgInt32 i0 = face->m_index[0];
         dgInt32 i1 = face->m_index[1];
         dgInt32 i2 = face->m_index[2];

         const dgBigVector& p0 = m_points[i0];
         dgBigVector normal ((m_points[i1] - p0) * (m_points[i2] - p0));

         dgFloat64 N = -((localP0 - p0) % normal);
         dgFloat64 D = dS % normal;

         if (fabs(D) < dgFloat64 (1.0e-12f)) { //
            if (N < dgFloat64 (0.0f)) {
               m_lastFaceHit = -1;
               return dgFloat64 (1.2f);
            } else {
               continue;
            }
         }

         dgFloat64 t = N / D;
         if (D < dgFloat64 (0.0f)) {
            if (t > tE) {
               tE = t;
               hasHit = 1;
               //hitNormal = normal;
               m_lastFaceHit = faceIndex;
            }
            if (tE > tL) {
               m_lastFaceHit = -1;
               return dgFloat64 (1.2f);
            }
         } else {
            _ASSERTE (D >= dgFloat64 (0.0f));
            tL = GetMin (tL, t);
            if (tL < tE) {
               m_lastFaceHit = -1;
               return dgFloat64 (1.2f);
            }
         }
      }

      if (hasHit) {
         interset = tE;   
      }

      return interset;
   }


   dgInt32 m_lastFaceHit;

};



Note:
-you can change the funtion to return the Face ID itself of maybe even the Face itself, you can do whatever you need.

-if your convex shapes have lot of trangles, say over 30 or more and you are using this for real time, then you can use a more optimize version Raycast on conve shapes.
the engine uses both function, the linear search tah check everface, and one base of steepest decent. Then it uses an arbitraruy test to decide which one to use.
In general convex full for Game object ar on the small number of face, 20 or less, so the linear time on is ussially good.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Possibility of multiple material per object?

Postby jiandingzhe » Mon Aug 15, 2011 9:55 pm

Julio Jerez wrote:Yes you make you version adpedted to you need, that is what teh convex hull shape does.
you subclass class dgConvexHull3d, then you take function RayCast and you write a similar one but keeping track of the face number that was last hit by the race.

So, I should do these things:
1. Extend class dgConvexHull3d to store face info, and extend the RayCast method.
2. Also extend the class dgCollisionConvexHull, to let it use the extended Hull3d.
As a descendant class "is a" parent class, I should not need to modify the collision dispatching system.

Moreover, when creating the convex hull, it is being optimized to reduce amount of faces, thus original face order is not kept. How should I bypass this mechanism? Create my own version of creation function?

Where does the face optimization happens?
User avatar
jiandingzhe
 
Posts: 48
Joined: Fri Jul 08, 2011 11:21 am
Location: Beijing

Re: Possibility of multiple material per object?

Postby Julio Jerez » Mon Aug 15, 2011 10:34 pm

You only need to do step 1
1.Extend class dgConvexHull3d to store face info, and extend the RayCast method.

You can save the convexhull3d with your visual object and use it anywhere you want in the code.
All you need is a point and the normal of the contact point to determine the face on the Hull,
It does no really matter if the faces of the collision are optimized or not, the result is the same hull.
When a collision happens you will get a point and a normal, that will be sufficient to find the actual face the generated the collision using your raycast.
Julio Jerez
Moderator
Moderator
 
Posts: 12426
Joined: Sun Sep 14, 2003 2:18 pm
Location: Los Angeles

Re: Possibility of multiple material per object?

Postby jiandingzhe » Tue Aug 16, 2011 2:17 am

Julio Jerez wrote:You only need to do step 1
1.Extend class dgConvexHull3d to store face info, and extend the RayCast method.

You can save the convexhull3d with your visual object and use it anywhere you want in the code.
All you need is a point and the normal of the contact point to determine the face on the Hull,
It does no really matter if the faces of the collision are optimized or not, the result is the same hull.
When a collision happens you will get a point and a normal, that will be sufficient to find the actual face the generated the collision using your raycast.

You mean I actually use two Hull3d for each collision: the original one for newton engine, and my customized one for raycast and face detection? That's a little bit too much redundancy.

Actually, maybe I can store the per-face data in graphic engine, and use the graphic engine's raycasting facilities. I can even implement my own class just for face data storage and ray casting :) . I'll ask these further questions on OGRE's forum. Thanks a lot!!
User avatar
jiandingzhe
 
Posts: 48
Joined: Fri Jul 08, 2011 11:21 am
Location: Beijing


Return to General Discussion

Who is online

Users browsing this forum: No registered users and 1 guest