Notifications
Clear all

[Closed] Select Faces based on normal?

I am trying to select all the faces of a poly that have their normal pointing above the horizon, i.e. “upwards”. Any ideas?? I am not that familar with matrix math and trying to wrap my head around it so any explainations would also be most helpful. Thanks.

6 Replies

gonna cut and paste a few things… not quite a full ready to use script, but it does something similar to what you want



	group "Select Angled Faces: " (
		spinner ui_MinDegree "Min:   " pos:[8,135] width:118 height:16 range:[0,360,15]
		spinner ui_MaxDegree "Max:   " pos:[8,157] width:118 height:16 range:[0,360,90]
		)



	function SelectAngleFaces =
	(
		curObj = (getCurrentSelection())[1]
		if curObj != undefined do
		(
			--if classof curObj == editable_patch then addmodifier curObj (Edit_mesh())
			
			if (getSelectionLevel $ != #face) do
			(
				modPanel.setCurrentObject $.baseObject
				subobjectLevel = 4
			)
			
			numFaces = polyOp.GetNumFaces curObj
			angleSelection = #{}
			minAngle = ui_MinDegree.value
			maxAngle = ui_MaxDegree.value
							
			for f=1 to (numFaces) do
			(
				faceNorm = polyOp.getFaceNormal curObj f
				angle = (acos (dot faceNorm [0,0,1] ))
				if ((angle >= minAngle) and (angle <= maxAngle)) then angleSelection[f] = true
			)
			polyOp.setFaceSelection curObj angleSelection
			forceCompleteRedraw()
		)
	)


	on ui_MinDegree changed val do (
		ui_MinDegree.value = val

		ui_MaxDegree.range = [val,360, ui_MaxDegree.value]

		SelectAngleFaces()
	)
	
	on ui_MaxDegree changed val do (
		ui_MaxDegree.value = val

		ui_MinDegree.range = [0,val, ui_MinDegree.value]

		SelectAngleFaces()
	)


build yourself a rollout for it and you should be good

i think i figured out a way but not sure if it is 100% correct… any comments?


-- check if object is an editable poly
if (classof obj == Editable_Poly) then 
(
	 max modify mode
	 subObjectLevel = 4
	 sf = #()

	 -- loop through all the faces
	 for fIndex = 1 to obj.numfaces do 
	 (

		  -- n1 is set to face normal
		  n1 = getFaceNormal obj fIndex

		  -- n2 is set to "up"
		  n2 = [0,0,1]
		  
		  -- get the angle between the vectors
		  angleBetween = acos(dot n1 n2)	
	
		  -- check if angle is less then 90 degress from "up"
		  if (angleBetween < 90) then 
		  (
				 -- add face index to array
				 append sf fIndex
		  )
	 )
	 obj.selectedFaces = sf
)

thanks for the reply! i didn’t see your post until after i posted my code. Seems like i am doing basically the same things. I like the min max angle spinners though. I will have to implement those.

I might be terribly wrong here, but I think angle = acos faceNorm.z will return the same results as angle = (acos (dot faceNorm [0,0,1] )). So that eliminates the need for a dot product, which might speed up the script a tiny little bit on large datasets.

Cheers,
Martijn

Replacing the dot product line with angle = acos faceNorm.z does seems to work fine so far. Thanks for the suggestion.

Hey, in the first example with the editable poly object…polyop.getFaceNormal will written like that return the local normal to the object. To get it in world coordinates you can add node:curObj to the end…like so: polyop.getFaceNormal curObj f node:curObj Editable meshes returns it in world coordinates by default though.

cheers,
CML