detect inside of object

Become a member of the CGSociety

Connect, Share, and Learn with our Large Growing CG Art Community. It's Free!

THREAD CLOSED
 
Thread Tools Search this Thread Display Modes
Old 03 March 2009   #1
detect inside of object

Hi all,
Can anyone help me find a way to check if a point is inside an object or outside? I need better accuracy than coincident to the bounding box, and I strongly prefer mel. I'm basically trying to voxel-ize an object, if that makes sense, imagine a very pixelated image but in 3d.
Thanks for your help
Dave.
 
Old 03 March 2009   #2
This example should work, though it was written to check one point at a time so it'll be very slow. But you can use the concept.



{
   proc int isPointInsideMesh(float $ptPos[], string $meshObj) {
	  // Create a closestPointOnMesh node
	  // We get all of our information about the relationship
	  // between the mesh and the point in space from this node
	  string $cpomNode = `createNode closestPointOnMesh`;
	  // Connect the mesh to the closestPointOnMesh node
	  connectAttr ($meshObj + ".worldMesh") ($cpomNode + ".inMesh");
	  // Set the closestPointOnMesh node input value to the point's position
	  setAttr ($cpomNode + ".inPositionX") $ptPos[0];
	  setAttr ($cpomNode + ".inPositionY") $ptPos[1];
	  setAttr ($cpomNode + ".inPositionZ") $ptPos[2];
	  // Put the point's position values into a vector so we can do math on it
	  vector $queryPoint = <<$ptPos[0], $ptPos[1], $ptPos[2]>>;
	  // Get the closest point on the mesh to the point we are checking
	  float $cPosX = `getAttr ($cpomNode + ".positionX")`;
	  float $cPosY = `getAttr ($cpomNode + ".positionY")`;
	  float $cPosZ = `getAttr ($cpomNode + ".positionZ")`;
	  // Subtrect the point's position and the closest point on the mesh
	  // Normalize the resulting vector using the unit function
	  vector $pos = unit($queryPoint - <<$cPosX, $cPosY, $cPosZ>>);
	  // Get the surface normal at the closest point on the mesh
	  float $nX = `getAttr ($cpomNode + ".normalX")`;
	  float $nY = `getAttr ($cpomNode + ".normalY")`;
	  float $nZ = `getAttr ($cpomNode + ".normalZ")`;
	  // Make the normal into a normalized vector
	  vector $normal = unit(<<$nX, $nY, $nZ>>);
	  // Delete the closestPointOnMesh node because we're done with it
	  delete $cpomNode;
	  // If the dot product of the normal and the normalized difference in positions
	  // is greater than zero, then the point is inside the mesh
	  // This assumes that the mesh normals are pointing outward
	  if (dot($normal, $pos) <= 0) {
		 // If the dot product is less than zero, then we're inside
		 return true;
	  } else {
		 // If the dot product is greater than zero, then we're outside
		 return false;
	  }
   }
   string $newSphere[] = `polySphere -r 10.0`;
   float $x, $y, $z;
   for ($x=-10; $x<10; $x++) {
	  for ($y=-10; $y<10; $y++) {
		 for ($z=-10; $z<10; $z++) {
			if (`isPointInsideMesh {$x, $y, $z} $newSphere[0]` == 1) {
			   spaceLocator -p $x $y $z;
			}
		 }
	  }
   }
}


Based on the dot product of the surface normal compared to the difference between the position and the closest point on surface, you can tell if you are inside the mesh.

You could speed this up by creating one closestPointOnMesh node and just change the inPosition depending on what you are checking.


Stev
 
Old 03 March 2009   #3
Thanks Stev,

I'm hoping to implement something like this in a shatter script. Have a look at the shatter help thread in dynamics.

Dave.
 
Old 04 April 2009   #4
Here's one using ray casting. I'm basing it on the fact that if a point's inside a mesh, a raycast from that point will hit an odd number of faces to get outside. If it hits an even number, we're already on the outside.

It's not dependant on normals, only volume based manifold meshes including multiple shells and non-convex hulls.

global proc int isPointInsideOfMesh(vector $point, string $mesh)
  {
  	if (!`pluginInfo -q -loaded "rayIntersect"`)
  		loadPlugin "rayIntersect";
  	string $triNode[] = `polyTriangulate -ch 1 $mesh`; //we can't assume there's no n-sided faces which 'fold'
  	float $tolerance = 0.0001;
  	int $count = 0;
  
  	if (`rayIntersect -inPosition ($point.x) ($point.y) ($point.z) -direction 0 1 0 -q -i1 $mesh`) //we've hit something
  	{
  		float $n[]= (`rayIntersect -inPosition ($point.x) ($point.y) ($point.z) -direction 0 1 0 -q -i2 $mesh`);
  		if ($n[0]) //we've hit n something's
  		{
  			int $lastFaceID = `rayIntersect -inPosition ($point.x) ($point.y) ($point.z) -direction 0 1 0 -q -f2 $mesh`;
  			int $faceID = `rayIntersect -inPosition ($point.x) ($point.y) ($point.z) -direction 0 1 0 -q -f1 $mesh`;
  			//get the location of the last 'hit' $newPoint
  			vector $newPoint = 	`rayIntersect -inPosition ($point.x) ($point.y) ($point.z) -direction 0 1 0 -q -p1 $mesh`;
  
  			while ( $lastFaceID != $faceID) //step through the face until we hit the last.
  			{			
  				$faceID = `rayIntersect -inPosition ($newPoint.x) ($newPoint.y + $tolerance) ($newPoint.z) -direction 0 1 0 -q -f1 $mesh`;
  				$newPoint =  `rayIntersect -inPosition ($newPoint.x) ($newPoint.y + $tolerance) ($newPoint.z) -direction 0 1 0 -q -p1 $mesh`;
  				$count++;
  			}			
  		}
  		$count++;
  	}
  	delete $triNode[0]; //cleanup
  	return (`fmod $count 2`);
  }
  
  int $insideOutside = isPointInsideOfMesh(<<0,0,0>> ,"pCube1");
  if ($insideOutside)
  {
  	print "\n Is Inside";
  }
  else
  {
  	print "\n Is Outside";
  }
  

The triangulation is there incase there's some iffy n sided faces that are non planar, and we don't really want to treat them as one face.

The only thing nasty is the tolerance, used to just nudge the previously found intersection along the direction vector and is a limitation of the plugin I'm using (I've used +y for this, but it could be any vector really).

The rayIntersect plugin is originaly from Highend3D.
 
Old 04 April 2009   #5
Originally Posted by davegreenwood: Thanks Stev,

I'm hoping to implement something like this in a shatter script. Have a look at the shatter help thread in dynamics.

Dave.


Me too!

I posted this earlier!

http://forums.cgsociety.org/showthr...p?f=89&t=748959
 
Old 04 April 2009   #6
Hi all, yep compiling the rayIntersect plug from Highend3D is the way to go with this. But, I did wonder if anyone knows how to use that API command using a bit of py†hon? I'd seen an example using pymel... but again that's something that's not in a standard installation. Is it possible in the clunky maya python implementation?

Cheers
Dave.
 
Old 04 April 2009   #7
Hmmmm interesting! This will come in handy with the shatter script! Nice job Paul!
 
Old 04 April 2009   #8
Heres a little wrapper function for the allIntersections api call in python.
It just returns whether your point is inside the mesh or not, the wrapper could be made to return any of the possible informtion provided by the api function.

#A simple wrapper for the maya api function allIntersections to test if  point lies inside of a mesh or not
  #returns true or false if the point is inside the mesh or not
  #
  #point is the position of interest in world space
  #direction is the ray direction to test in
  #mesh is the geometry to test against
  import maya.OpenMaya as OM
  from math import fmod
  
  def rayIntersect(mesh, point, direction=(0.0, 1.0, 0.0)):
  	OM.MGlobal.selectByName(mesh)
  	sList = OM.MSelectionList()
  	#Assign current selection to the selection list object
  	OM.MGlobal.getActiveSelectionList(sList)
  
  	item = OM.MDagPath()
  	sList.getDagPath(0, item)
  	item.extendToShape()
  
  	fnMesh = OM.MFnMesh(item)
  
  	raySource = OM.MFloatPoint(point[0], point[1], point[2], 1.0)
  	rayDir = OM.MFloatVector(direction[0], direction[1], direction[2])
  	faceIds = None
  	triIds = None
  	idsSorted = False
  	testBothDirections = False
  	worldSpace = OM.MSpace.kWorld
  	maxParam = 999999
  	accelParams = None
  	sortHits = True
  	hitPoints = OM.MFloatPointArray()
  	#hitRayParams = OM.MScriptUtil().asFloatPtr()
  	hitRayParams = OM.MFloatArray()
  	hitFaces = OM.MIntArray()
  	hitTris = None
  	hitBarys1 = None
  	hitBarys2 = None
  	tolerance = 0.0001
  	hit = fnMesh.allIntersections(raySource, rayDir, faceIds, triIds, idsSorted, worldSpace, maxParam, testBothDirections, accelParams, sortHits, hitPoints, hitRayParams, hitFaces, hitTris, hitBarys1, hitBarys2, tolerance)
  	
  	result = int(fmod(len(hitFaces), 2))
  	
  	#clear selection as may cause problem if the function is called multiple times in succession
  	OM.MGlobal.clearSelectionList()
  	return result


Maybe someone finds it useful.

Ta
__________________
::Octupe::
 
Old 04 April 2009   #9
Octupe, nice work! I tried your code and passed the name of a mesh and a vector for the position of a locator and it worked great. Although I think i broke something now because it keeps giving me an error whenever i try to pass a vector to it again . . . :-\ Not sure what I changed / did wrong.
 
Old 04 April 2009   #10
Nevermind, haha, just figured it out. I was passing the name of an object like:

Quote: mesh = "pSphere1"


when it should be:

Quote: mesh = 'pSphere1'


Awesome script!!
 
Old 04 April 2009   #11
very nice wrapper indeed. Thanks for sharing!
 
Old 04 April 2009   #12
Joy! thank U!
__________________
http://www.claydough.net
 
Old 04 April 2009   #13
This is great, thanks very much
 
Old 04 April 2009   #14
Thread automatically closed

This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.
__________________
CGTalk Policy/Legalities
Note that as CGTalk Members, you agree to the terms and conditions of using this website.
 
Thread Closed share thread



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
CGSociety
Society of Digital Artists
www.cgsociety.org

Powered by vBulletin
Copyright ©2000 - 2006,
Jelsoft Enterprises Ltd.
Minimize Ads
Forum Jump
Miscellaneous

All times are GMT. The time now is 04:52 AM.


Powered by vBulletin
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.