What subjects should I learn for Structural and Mesh modifying?

Started by
11 comments, last by John Getz 6 years, 9 months ago

Hey all,

It's been ages (years) since I've been on these forums. Last time was a noob. Now it's as... a slightly less noobish noob.

Basically, whilst I'm working on my little 'game/demo a week' challenges to increase my skill I would also like to expand my fundamental knowledge on a certain subject - namely destructible terrain/objects.

Now this, as far as I can work out, includes physics (architectural and structural to some extent) and an understanding of modifying meshes on the fly. Admittedly, that last one is perhaps a LOT more in depth than is necessary, but this is going to be a long term subject I wish to learn.

Therefore, my question is (finely got there - sorry 'bout that) what sorts of subject (the more specific the better) should I learn to get a decent handle on this? And, yes, I know this is going to recquire learning new mathematics - I'm happy to try ;)

P.S. Further information: I have already messed around with the basics of solid-wall-turning-into-bricks when "destroyed", however I would like to understand how to make objects shatter and explode (battlefield style) or slice (metal gear solid whatever style).

Advertisement

There's a lot of different kinds of destruction. Most of them involve taking a mesh, splitting it up into smaller pieces, and making new meshes out of the pieces. Plane slicing is a pretty simple way. Take a mesh, slice it with a plane, and make two new meshes, one from each piece. Maybe try this first.

Hi @RandyGaul

Many thanks for the reply. I'm glad you've said that, I was sorta thinking in that direction, glad to have it confirmed.

I've looked a bit into basic mesh construction (remember a lot from my attempts to learn gamedev straight in c++ and DirectX) and. Vertex manipulation, however I have no idea how to work out how add another plane to the mix and go from there. Is there a particular subject I should research and study?
P.s. gonna look into (google) "plane slicing" and see what I come up with...

I'd say line segment to plane intersection is good to look up. Also some kind of mesh format. Triangle soup, half-edge mesh, winged-edge, etc. I personally implemented plane slicing with segment to plane intersections and half-edge mesh format.

Okay, so I've got it working fine 90% of the time (so it's still essentialy broken, but one problem at a time).

But I'm getting this effect on the sliced meshes.

[attachment=35782:Triangle1.PNG]

[attachment=35783:triangle3.PNG]

As you can see, the 'bricks' ar just cubes with a standard material, but as soon as they are sliced the triangles go a bit awry. I've looked into UV's, and tried copying as much data across from the original mesh as possible, but I cannot work out what's wrong with this.

I've also run mesh.recalculateNormals() and mesh.recalculateTangents() (Unity) still no luck :(

This wouldn't be cured by using an actual mesh format by any chance, would it?

@WiredCat

So have you been getting much luck with mesh slicing/destroying?

i only implemented csg it may lack some face buliding code, i mean maybe not all faces are created, i did this more than year ago i think and left is as it is:

csgf2s.png

csgn.jpg

and a supreme goal not realated to antyhing

device-2016-03-17-173445.png


header
csg.h

#ifndef csgH
#define csgH
#include "DxcMath.h"
#include "modelloading/TachoGLModelSRC.h"
#include "logme.h"

/*
bool * used = new bool[ imaginary_poly.Count ];
float * angles = new float[ imaginary_poly.Count ];
for (int imo=0; imo < imaginary_poly.Count; imo++) used[imo] = false;

used[0] = true;

CSGOut->imaginary_poly.AddVertex(imaginary_poly.V[0]);

//CSGOut->imaginary_poly = imaginary_poly;
t3dpoint<float> center_point;
for (int imo=0; imo < imaginary_poly.Count; imo++)
center_point = center_point + imaginary_poly.V[imo];

center_point = center_point / float(imaginary_poly.Count);

TPolygon<float> CLOCKWISE_POLY;

t3dpoint<float> plane_normal = Normal(imaginary_poly.V[0],imaginary_poly.V[1],imaginary_poly.V[2],true);
float plane_distance = getplaneD(plane_normal, imaginary_poly.V[0]);

CLOCKWISE_POLY.AddVertex(center_point);
CLOCKWISE_POLY.AddVertex(imaginary_poly.V[0] );

TPolygon<float> origin_poly = CreatePoly(plane_normal, imaginary_poly.V[0], 100.0f);

t3dpoint<float> Xvec = vectorAB(origin_poly.V[0], origin_poly.V[1]);
t3dpoint<float> Yvec = vectorAB(origin_poly.V[0], origin_poly.V[3]);

int next_vertex = 0;
while (!nothing_to_check(used,  imaginary_poly.Count))
{
float angle = 5555555.0;
int anglei;


for (int imo=0; imo < imaginary_poly.Count; imo++)
	if (imo != next_vertex)
	{
		t3dpoint<float> vector = vectorAB(imaginary_poly.V[ next_vertex ], imaginary_poly.V[ imo ]);
		t3dpoint<float> x_coord = VectorProjectionBDIR(vector, Xvec, false);
		t3dpoint<float> y_coord = VectorProjectionBDIR(vector, Yvec, false);
		angles[ imo ] = GetAngle(  t3dpoint<float>(VectorLength(x_coord), VectorLength(y_coord), 0.0f)  );
		if ( angles[ imo ] < angle)
		{
			angle = angles[ imo ];
			anglei = imo;
		}
	}

used[anglei] = true;
next_vertex = anglei;
CLOCKWISE_POLY.AddVertex( imaginary_poly.V[ anglei ] );
}*/
//==========================================================================================


//==========================================================================================



//==========================================================================================

/*
 *
 *
 * 	if (CSGSPH == true)
		{
			ican = false;
			CSGSPH = false;
			t3dpoint<float> normal = t3dpoint<float>(-1.0, 0.0, 0.0);
			float dist = -Dot(normal, t3dpoint<float>(0.0, 0.0, -1.0));
			box_model->CalcFaceCenterPoint(); //this funciton is needed for face area calculation (only convex polys)
			box_model->CalculateFaceAreas();
			CAN_LOG =true;
			ALOG("INIT VOL: "+FloatToStr(box_model->CalculateVolume()));
			CAN_LOG= false;
			sphere = CSG.CutModelWithPlane(normal, dist, box_model, true);//CSG.CSG_SUBTRACT(1, box_model, cylinder_model, true);
//			sphere =	CSG.CSG_SUBTRACT(1,box_model, cylinder_model, true);
//			if (sphere != NULL)
//			{
//			dist = -Dot(t3dpoint<float>(0.0, 0.0, 1.0), t3dpoint<float>(3.0, 0.0, 0.0));
//			normal = t3dpoint<float>(0.0, 0.0, 1.0);
//			TachoGLModel<float> * sphere2 = CSG.CutModelWithPlane(normal, dist, sphere, false);
//
//			sphere = sphere2;


			CAN_LOG =true;



			sphere->MoveToGeometricCenter();


			sphere->CalcFaceNormals();

			sphere->PointFaceN(t3dpoint<float>(0.0, 0.0, 0.0));
			sphere->ReverseNormals();
			sphere->CalcFaceCenterPoint();

					sphere->CalculateFaceAreas();

			ALOG("output VOL: "+FloatToStr(sphere->CalculateVolume()));
			CAN_LOG= false;

if (sphere != NULL)
{
			sphere->ForceCalculateNormals();
			sphere->SendToGPU();
}

//			}
CSG_READY = true;
ican = true;
		}
 *
 *
 */

struct TCSGInfo
{
	bool blank;

	TCSGInfo * n;
	TPolygon<float> OUTpoly;
                  int index; //for easier debugging
	TCSGInfo()
	{
	index = -1;
		n = NULL;
		blank = true;
	}
};




struct TCSGOperationResult
{
TPolygon<float> ImaginaryPoly;
	TPolygon<float> LeavePoly;
	TPolygon<float> ToBeCutPoly;
};




struct TCSGOperation
{

TCSGInfo * InverseSlicerChubu(int Leave_side, TachoGLModel<float> * model, TachoGLModel<float> * CUTTING_model);

TPolygon<float> InverseSplitPolyByPlane(t3dpoint<float> n, float d, TPolygon<float> CuttedPoly, int leave_side);

TachoGLModel<float> * CutModelWithPlane(t3dpoint<float> n, float d, TachoGLModel<float> * model, bool create_volume);


TCSGOperationResult SplitPolyByPlane(t3dpoint<float> n, float d, TPolygon<float> CuttedPoly, int leave_side)
{


	TCSGOperationResult result;

		t3dpoint<float> A; t3dpoint<float> B;

		int next;
int i;
int cutperformed = 0;
		for(i=0; i < CuttedPoly.Count; i++)
		{



			A = CuttedPoly.V[i];

			if (i != CuttedPoly.Count-1) next = i + 1; else next = 0;

			B = CuttedPoly.V[next];

			int Aside = classifyapointagainstaplane(A, n,  d);
			int Bside = classifyapointagainstaplane(B, n,  d);


	t3dpoint<float> output;
	bool cut = SegmentPlaneIntersection(n, d, A, B, output);

	if (cut)
	{

if (Aside == leave_side)
result.LeavePoly.AddVertex(A);
else
result.ToBeCutPoly.AddVertex(A);

			result.ImaginaryPoly.AddVertex(output);
			result.LeavePoly.AddVertex(output);
			result.ToBeCutPoly.AddVertex(output);

	} else
	{ //here there is no cut atm
		if	(Aside == leave_side)
			result.LeavePoly.AddVertex(A);
		else
			result.ToBeCutPoly.AddVertex(A);
	}
}

//	ShowMessage("Initial Face vcnt: "+IntToStr(CuttedPoly.Count)+"  leave vcnt: "+IntToStr(result.LeavePoly.Count)
//	+"  To cut vcnt: "+IntToStr(result.ToBeCutPoly.Count));
return result;
}



TCSGOperation()
{

}


TCSGInfo* GetLastCSG(TCSGInfo * first)
{
	TCSGInfo * p = first;
while (p->n != NULL) p = p->n;

return p;
}


TCSGInfo * SlicerChubu(int Leave_side, TachoGLModel<float> * model, TachoGLModel<float> * CUTTING_model) //returns first csg poly that points onto next csg poly from that shape
{
   int csg_index = 0;
	TCSGInfo * CSGOut 		    = new TCSGInfo();


	int vertlen = model->header.LENGTH;
	int i; int F;
/*
* How does that function work? FOR EACH FACE IN MODEL TO BE CUT
* Loop through slicing planes and slice that FACE
*/

for (F=0; F < model->FaceLength; F++) //for all model faces that to be cut
{
		int face_vindex = model->VBO_BE[F].INDEX_START;

		TPolygon<float> poly;
		TPolygon<float> imaginary_poly;

		for(i=0; i < model->VBO_BE[F].length; i++)	poly.V[i] = model->AOS[face_vindex+i].v;

		poly.Count = model->VBO_BE[F].length;



int CSG_F;
for (CSG_F=0; CSG_F < CUTTING_model->FaceLength; CSG_F++) //loop through cutting shape (model) faces to cut with its planes the corresponding model
{
TCSGOperationResult csg_res = SplitPolyByPlane(CUTTING_model->FACE_N[ CSG_F ], CUTTING_model->FACE_DISTANCE[ CSG_F ], poly, Leave_side);

   poly = csg_res.ToBeCutPoly;

   if (csg_res.LeavePoly.Count < 3) continue;
csg_index = csg_index + 1;
	if (CSGOut->blank) //we ski
			{
				if (csg_res.LeavePoly.Count > 0)
				{
			CSGOut->OUTpoly = csg_res.LeavePoly;
			CSGOut->blank = false;
			CSGOut->index = csg_index;
				}
			} else

if (csg_res.LeavePoly.Count > 0)
			{
			TCSGInfo*	 	lCSG = GetLastCSG(CSGOut);
			TCSGInfo*		nCSG = new TCSGInfo();
			lCSG->n = nCSG;
			nCSG->index = csg_index;
			nCSG->blank = false;
			nCSG->OUTpoly = csg_res.LeavePoly;
			}

			 //	if (poly.Count < 3) break; //nothing to cut

}

}

return CSGOut;
}






TachoGLModel<float> * CSG_SUBTRACT(int Leave_side, TachoGLModel<float> * model, TachoGLModel<float> * CUTTING_model, bool recreate_depth)
{
	TachoGLModel<float> * result = new TachoGLModel<float>();
	TCSGInfo * FirstCSG 		= NULL;
	TCSGInfo * FirstInverseCSG 	= NULL;

	int cut_side;

	switch (Leave_side)
	{
	default:
		cut_side = -1;
	    break;

	case 1:
		cut_side = -1;
	    break;

	case -1:
		cut_side = 1;
	    break;
	}

	FirstCSG 		= SlicerChubu(Leave_side, model, CUTTING_model);

	if ( recreate_depth )
	FirstInverseCSG = InverseSlicerChubu(Leave_side, model, CUTTING_model);
	else
		FirstInverseCSG = NULL;

	int face_cnt = 0;
	int vert_cnt = 0;
	TCSGInfo * p;
//****************************************************************************

p = FirstCSG;
if (p != NULL)
{
	while (p->n != NULL)
	{
		vert_cnt = vert_cnt + p->OUTpoly.Count;
		face_cnt = face_cnt + 1;

		p = p->n;
	}

	if (p->n == NULL)
	{
vert_cnt = vert_cnt + p->OUTpoly.Count;
face_cnt = face_cnt + 1;
	}
   }


//****************************************************************************
//****************************************************************************

p = FirstInverseCSG;
if (p != NULL)
{
	while (p->n != NULL)
	{
		vert_cnt = vert_cnt + p->OUTpoly.Count;
		face_cnt = face_cnt + 1;

		p = p->n;
	}

	if (p->n == NULL)
	{
vert_cnt = vert_cnt + p->OUTpoly.Count;
face_cnt = face_cnt + 1;
	}
   }


//****************************************************************************


		result->AOS 		= new TTGLVertex<float,float,float>[ vert_cnt ];
		result->VBO_BE 		= new tvbofacenfo[ face_cnt ];
		result->Matrixarr 	= new tmatrixtype[ face_cnt ];
		result->header.LENGTH 	= vert_cnt;
		result->header.version 	= 32;
		result->header.addon 	= 0;
		result->FaceLength 		= face_cnt;
		for (int i=0; i < face_cnt; i++)
		result->Matrixarr[i] 			= mtTriangleFan;


/*
 * After creating required arrays we need to feed data to it
 */

		face_cnt = 0;
		vert_cnt = 0;
	//****************************************************************************

	p = FirstCSG;
		if (p != NULL)
			{
		while (p->n != NULL)
		{
			for (int i=0; i < p->OUTpoly.Count; i++) result->AOS[ vert_cnt+i ].v = p->OUTpoly.V[i];
			result->VBO_BE[face_cnt].INDEX_START 	= vert_cnt;
			result->VBO_BE[face_cnt].length 		= p->OUTpoly.Count;
			result->Matrixarr[face_cnt] 			= mtTriangleFan;
			vert_cnt = vert_cnt + p->OUTpoly.Count;
			face_cnt = face_cnt + 1;
			p = p->n;
		}

		if (p->n == NULL)
		{
			for (int i=0; i < p->OUTpoly.Count; i++) result->AOS[ vert_cnt+i ].v = p->OUTpoly.V[i];
			result->VBO_BE[face_cnt].INDEX_START 	= vert_cnt;
			result->VBO_BE[face_cnt].length 		= p->OUTpoly.Count;
			result->Matrixarr[face_cnt] 			= mtTriangleFan;
	vert_cnt = vert_cnt + p->OUTpoly.Count;
	face_cnt = face_cnt + 1;
		}
		}


//****************************************************************************
//****************************************************************************
//****************************************************************************
//****************************************************************************
//CAN_LOG = true;
p = FirstInverseCSG;ALOG("INVERSE CSG");
if (p != NULL)
{

	while (p->n != NULL)
	{
		ALOG("outpoly: "+IntToStr(p->OUTpoly.Count));
	for (int i=0; i < p->OUTpoly.Count; i++) result->AOS[ vert_cnt+i ].v = p->OUTpoly.V[i];
			result->VBO_BE[face_cnt].INDEX_START 	= vert_cnt;
			result->VBO_BE[face_cnt].length 		= p->OUTpoly.Count;
			result->Matrixarr[face_cnt] 			= mtTriangleFan;

		vert_cnt = vert_cnt + p->OUTpoly.Count;
		face_cnt = face_cnt + 1;

		p = p->n;
	}

	if (p->n == NULL)
	{
		ALOG("outpoly: "+IntToStr(p->OUTpoly.Count));
	for (int i=0; i < p->OUTpoly.Count; i++) result->AOS[ vert_cnt+i ].v = p->OUTpoly.V[i];
			result->VBO_BE[face_cnt].INDEX_START 	= vert_cnt;
			result->VBO_BE[face_cnt].length 		= p->OUTpoly.Count;
			result->Matrixarr[face_cnt] 			= mtTriangleFan;


vert_cnt = vert_cnt + p->OUTpoly.Count;
face_cnt = face_cnt + 1;
	}
   }


//****************************************************************************





//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


ALOG("done INVERSE CSG");
	ClearSlicerChubu(FirstCSG);
	ClearSlicerChubu(FirstInverseCSG);

	if (vert_cnt == 0)
		return NULL;
	else
	{
	//	result->SaveToBGLCMD("E:\\csg.bglcmd",false);
		return result;
	}
}





void ClearSlicerChubu(TCSGInfo * first)
{
	TCSGInfo * p = first;
	TCSGInfo * pn;
	if (p != NULL)
while (p->n != NULL)
{
	pn = p->n;
	delete p;
	p = pn;
}

if ( (p != NULL) && (p->n == NULL) ) delete p;

}


};











#endif


source

#include "csg.h"


/*
* This returns vertices when theres a cut
*/
TPolygon<float> TCSGOperation::InverseSplitPolyByPlane(t3dpoint<float> n, float d, TPolygon<float> CuttedPoly, int leave_side)
{
		TPolygon<float> result;

			t3dpoint<float> A; t3dpoint<float> B;      t3dpoint<float> output;

			int next;
int i;
int cutperformed = 0;
			for(i=0; i < CuttedPoly.Count; i++)
			{
				A = CuttedPoly.V[i];

				if (i != CuttedPoly.Count-1)
					next = i + 1;
				else
					next = 0;

				B = CuttedPoly.V[next];

			//	int Aside = classifyapointagainstaplane(A, n,  d);
		bool cut = SegmentPlaneIntersection(n, d, A, B, output);

		if (cut)
		//	if	(Aside == leave_side)
	result.AddVertex(output);

	}

return result;
}


TCSGInfo * TCSGOperation::InverseSlicerChubu(int Leave_side, TachoGLModel<float> * model, TachoGLModel<float> * CUTTING_model) //returns first csg poly that points onto next csg poly from that shape
{
   int csg_index = 0;
	TCSGInfo * CSGOut 		    = new TCSGInfo();


	int vertlen = model->header.LENGTH;
	int i; int F;
/*
* How does that function work? FOR EACH FACE IN MODEL TO BE CUT
* Loop through slicing planes and slice that FACE
*/
//CAN_LOG = true;
	  int face_vindex;
ALOG("INV SLIVER CHUBU");

//imaginary_poly.Count = 0;

int CSG_F;
for (CSG_F=0; CSG_F < CUTTING_model->FaceLength; CSG_F++) //loop through cutting shape (model) faces to cut with its planes the corresponding model
{
	  TPolygon<float> imaginary_poly;
	  	  TPolygon<float> poly;

for (F=0; F < model->FaceLength; F++) //for all model faces that to be cut
{

		face_vindex = model->VBO_BE[F].INDEX_START;
		for(i=0; i < model->VBO_BE[F].length; i++)	poly.V[i] = model->AOS[face_vindex+i].v;

		poly.Count = model->VBO_BE[F].length;

TPolygon<float> csg_res = InverseSplitPolyByPlane(CUTTING_model->FACE_N[ CSG_F ], CUTTING_model->FACE_DISTANCE[ CSG_F ], poly, Leave_side);

csg_index = csg_index + 1;
if  (csg_res.Count == 0) continue;


for (i=0; i < csg_res.Count; i++) imaginary_poly.AddVertex(csg_res.V[i]);
}

ALOG("ADD TO output poly "+IntToStr(imaginary_poly.Count));
/*

 bool used[ imaginary_poly.Count ];
for (int h = 0; h < imaginary_poly.Count; h++)
	used[h] = false;

TPolygon<float> convex_poly;
for (int h = 0; h < imaginary_poly.Count; h++)
{
	int n = h+1;
	if (n > imaginary_poly.Count-1) n = 0;

	if (used[h] == false)
	if (used[n] == false)
	{
		float dst = n3ddistance(imaginary_poly.V[h],imaginary_poly.V[n]);
		ALOG("testing against: "+FloatToStr(dst));
if (dst < 0.002) //same verts
{
	ALOG("FOUND");
	convex_poly.AddVertex(imaginary_poly.V[h]);
	used[h] = true;
	used[n] = true;
}
	}
}

imaginary_poly = convex_poly;

*/
ALOG("KK");
ALOG("test if to add");
if (imaginary_poly.Count == 0) continue;
ALOG("KK forward");
	if (CSGOut->blank) //we ski
			{
		ALOG("here");
		ALOG("out poly");
			CSGOut->OUTpoly = imaginary_poly;
			CSGOut->blank = false;
			CSGOut->index = csg_index;
			} else
			{
				ALOG("here2");
			TCSGInfo*	 	lCSG = GetLastCSG(CSGOut);
			TCSGInfo*		nCSG = new TCSGInfo();
			lCSG->n = nCSG;
			ALOG("out poly");
			nCSG->OUTpoly = imaginary_poly;
			nCSG->blank = false;
			nCSG->index = csg_index;
			}

}
ALOG("RETURN RESULT");
return CSGOut;
}



TachoGLModel<float> * TCSGOperation::CutModelWithPlane(t3dpoint<float> n, float d, TachoGLModel<float> * model, bool create_volume)
{
//	CAN_LOG=true;
	//malloc(sizeof(TachoGLModel<double>)* model->header.LENGTH * 10);
	ALOG("CUT MODEL WITH PLANE");
	TachoGLModel<float> * face_model = new TachoGLModel<float>();

	face_model->FACE_N = new t3dpoint<float>[1];
	face_model->FACE_DISTANCE = new float[1];
	face_model->AOS 		= new TTGLVertex<float,float,float>[ 1 ];
	face_model->VBO_BE 		= new tvbofacenfo[ 1 ];
	face_model->Matrixarr 	= new tmatrixtype[ 1 ];
	face_model->header.LENGTH 	= 0;
	face_model->header.version 	= 32;
	face_model->header.addon 	= 0;
	face_model->FaceLength 		= 1;
	face_model->Matrixarr[0] 			= mtTriangleFan;

	face_model->FACE_N[0] = n;
	face_model->FACE_DISTANCE[0] = d;

		TachoGLModel<float> * new_model = new TachoGLModel<float>();
		ALOG("DO CSG");
		new_model = CSG_SUBTRACT(1, model, face_model,create_volume);
		ALOG("RETURN RESULT");

return new_model;
}



VBO_BE is face information face first vertex is the index in the vertex array it stores only index and length

however its been a long time i even used this code so i cant guraantee that it produces same results as shown in pictures above. I recommend that you implement your own csg on the go

i just can't understand how i become a miner with such knowledge, dudes, life is shit

the ides is to cut the 'model' with a low poly sphere that procudes imapct on mesh (and hole), then you draw the 'AND' result in shader with time parameter but thats only my delusion

Okay, so I've solved the weird triangle problem, and I'm posting the solution in case anyone else stumbles upon this thread with a similar issue (although, we're now leaving the OP, so this will be the last post from me).

Basically, in an effort to be clever and efficient (2 things which were not necessary for this simple 'tech demo' that I'm working on) I decided that I wouldn't use duplicate vertices, just draw multiple triangles from the same points.

Problem is that this messes up the normals, which is why I was getting those weird white-ish stretches of colour. Anyway, I simple added each vertex once FOR EACH TRIANGLE (thus, some points were enter multiple times) and this seemed to sort it out.

Still getting the occasional invisible triangle... would need to examine further. But apart from that - it's AWESOME! Thank you so much for all your help @RandyGaul!!!

Okay, final post for now - I promise this time!!!!

The missing triangles is because I hadn't catered for vertices residing DIRECTLY ON THE PLANE. So make sure you follow that section from the article by Randy Gaul, if you wanting to do this yourself of course...

Will prob post my basic solution on here at some point for other noobs like me to pull apart and have a look at. It's nothing new, but might be a helpful stepping stone for someone.

Which article are you reading exactly? Out of curiosity.

This topic is closed to new replies.

Advertisement