Notifications
Clear all

[Closed] Find verts inside other mesh

 JHN

I’m basicly looking for pointers on how the volume select modifier works when you pick another node to select verts in the current node. I have looked in the forum and it looks like I need to shoot some rays, but I’m just not certain how to capture something like a torus for example. I think it’s not very trivial to do, but any suggestions would be greatly appreciated!

-Johan

5 Replies

I think something like this might work:

  1. Get position of vert in question
  2. Cycle through all faces of volume object and find the closest face to that vert
  3. Get the face center of that face and shoot an intersect ray from the position of the vert to that face center
  4. If the intersect ray comes back undefined, you’re inside the object. If it comes back as a ray, you’re outside the object.

Here’s a very simple implementation:


  try(destroydialog insideOutside)catch()
  
  rollout insideOutside "Inside or Outside?" --main rollout
  (
  	label l1 ""
  	button bTest "Test"
  	
  	on bTest pressed do
  	(
  		vObj = $Volume --volume to test
  		pObj = $Point01 --point 
  		
  		converttomesh vObj
  		numF = getnumfaces vObj --get number of faces of volume
  		
  		dist = 10000000 --initialize face-distance check
  		testPoint = undefined
  		
  		for q in 1 to numF do --loop through all faces
  		(
  			fCenter = meshop.getfacecenter vObj q --get point at center of current face
  			testDist = distance fCenter pObj.pos --test distance from center of face to point object
  			if testDist < dist then --check if current face is closer to point than last face
  			(
  				dist = testDist
  				testPoint = fCenter --if we're closer this time than last time, set current face as test face
  			)				
  		)
  		
  		vec1 = testPoint - pObj.pos --get vector between test point and test face center point
  		ray1 = ray pObj.pos vec1 --construct ray 
  		
  		intRay = intersectRay vObj ray1 --shoot ray
  		
  		if intRay == undefined then 
  		(
  			l1.text = "Inside Object"			
  		)else
  		(
  			l1.text = "Outside Object"
  		)
  		
  	)
  	
  )
 
  createdialog insideOutside
  

To successfully run the script, create a point in the viewport, then create your volume object and name it “Volume”. Then run the script and click the “Test” button. Moving the point around (inside or outside the object” and then pressing the “Test” button will return the results in the rollout label.

Note: you might not even need the “find closest face” functionality of the script if the object has a closed surface, since shooting a ray in any direction will return a value of “undefined” if there are no missing faces in the surface (because when you’re inside an object with a closed surface, all normals point away from you)

Also, if your volume mesh has self-intersections, this could cause problems because “outside” faces will intersect into the interior of the volume and skew the intersectray results, if one of those intersecting “outside” faces happens to be the face you test with the ray.

To implement this type of thing into your own script, just use vertex positions instead of a point helper’s position, and loop the main function for however many verts the mesh has.

 JHN

Tyson, thanks very much for this… cannot work on it for a few days unfortunately, but I will post back if it’s what I need in the end! Many thanks,
-Johan

Finding the closest face to every point could slow down your script very much.
There is a way to do this a bit different without the need for this loop inside a loop.
In this method you will have to fire every ray twice, but I think it should pay up in the end by a much faster result.

Pseudocode:

1. 	add a normal modifier to the volume object, with the flip option turned ON
2. 	loop through all verts
2.1. 	p = position of current vert
2.2. 	fire a ray from p in an arbitrary direction like [0,0,1] at the volume object
2.3. 	if the ray missed then 
			you are out side the volume
		else
2.3.1		turn the normal modifier on the volume object OFF
2.3.2		fire another ray from p in the same direction at the volume object
2.3.3		if the 2nd ray missed or distance from p to hit1 < distance from p to hit2 then
				you are inside the volume
			else
				you are outside the volume
2.3.4		turn the normal modifier on the volume object ON

Hey,
I’ve created a script according to the workflow of Matan. My script checks if a vraylight is within a volume and adjusts its multiplier accordingly. It is intended to animate lights on and off by using an animated volume. First tests are looking good. Here’s the script so far:

/*
  Switch light by volume
  Switches lights on and off if they are within a specified volume/mesh
  
  2010-09-21 Klaas Nienhuis
  main procedure taken from  http://forums.cgsociety.org/showpost.php?p=6691768&postcount=5 
  Animates the multiplier of the vraylights during the entire animationrange
  If the light is within a specific volume, the multiplier is high, otherwise it is low.
  */
  
  function fn_isObjInsideVolume theObj theVolume=
  (
  	/*
  	fn_isObjInsideVolume
  	handles the calculation if an object is within a specified mesh-volume
  	*/
  	local inside = false
  	addModifier theVolume (normalModifier flip:true)
  	local myHit = intersectRay theVolume (ray theObj.pos [0,0,1])
  	if myHit == undefined then
  	(
  		inside = false
  	)else 
  	(
  		theVolume.modifiers[1].flip = false
  		local myHit2 = intersectRay theVolume (ray theObj.pos [0,0,1])
  		if myHit2 == undefined OR (distance myHit.pos theObj.pos) < (distance myHit2.pos theObj.pos) then
  		(
  			inside = true
  		)else
  		(
  			inside = false
  		)
  	)
  	deleteModifier theVolume 1
  	inside
  )
  
  function fn_animateLightMultiplier arrLight objVolume minMultiplier maxMultiplier =
  (
  	/*
  	fn_animateLightMultiplier
  	animates the light multipliers of an array of lights during the animationrange
  	the lights are switched on if they're within a specified volume
  	Works on vraylights only
  	*/
  	for t = animationRange.start to animationRange.end do at time t
  	(
  		for l in arrLight where classof l == VRaylight do
  		(
  			if fn_isObjInsideVolume l objVolume then
  			(
  				animate on l.multiplier = maxMultiplier
  			)else
  			(
  				animate on l.multiplier = minMultiplier
  			)
  		)
  	)		
  )
  
  global roll_switchLightByVolume
  try (destroyDialog roll_switchLightByVolume)catch()
  
  rollout roll_switchLightByVolume "Switch light by volume"
  (
  	spinner spnMinMultiplier "Min light multiplier" range:[0,500,0] width:130 type:#float across:2 align:#left
  	spinner spnMaxMultiplier "Max light multiplier" range:[0,500,30] width:130 type:#float offset:[30,0]
  	pickbutton pckVolume "Pick volume" autoDisplay:true width:320
  	button btnDo "Switch selected lights by volume" width:320
  	
  	on btnDo pressed do if pckVolume.object != undefined do
  	(
  		fn_animateLightMultiplier selection pckVolume.object spnMinMultiplier.value spnMaxMultiplier.value
  	)
  )
  
  createDialog roll_switchLightByVolume width:350 height:80

Create an array of vrayLights and animate a volume across the lights. Run the script.
Also available on my blog