Notifications
Clear all

[Closed] Align To Quad part2

In previous thread Denis showed excellent example how to scatter flags over uneven terrain.
But why same approch not works on simple cube which is orient in non-axis direction?
This cube have already selected center faces on each side where flags need to be placed.

fn scatterNodes ground brush = if iskindof ground Editable_Mesh and isvalidnode brush do
  (
  	faces = ground.selectedfaces as bitarray
  	done = #{} 
  	for f in faces where not done[f] collect
  	(
  		polys = meshop.getpolysusingface ground f
  		ground.selectedverts = meshop.getvertsusingface ground polys
  		done += polys
  
  		center = (averageSelVertCenter ground)*ground.objecttransform
  		normal = averageSelVertNormal ground
  		
  		copy brush pos:center dir:normal wirecolor:green
  	)
  )
  (
  	delete objects
  	brush = 
  	(
  		top = box widthsegs:1 lengthsegs:1 heightsegs:1 width:6 length:0.1 height:4 pos:[3,0,7.5]
  		top.mat = standard diffuse:red
  		bot = Cylinder name:"flag" smooth:on heightsegs:1 capsegs:1 sides:24 height:12 radius:0.2 pos:[0,0,0] wirecolor:red
  		bot.mat = standard diffuse:yellow
  		attach (bot = converttomesh bot) top
  		bot
  	)
  	ground = Box length:50 width:50 height:50 lengthsegs:3 widthsegs:3 heightsegs:3 wirecolor:green \
  	pos:[-50,-50,0] dir:[0.665714,0.202268,0.718271] material:(standard diffuse:blue)
  	converttomesh ground ; ground.selectedfaces = #{9..10, 27..28, 45..46, 63..64, 81..82, 99..100}
  		/*ground = mesh name:"ground" length:100 width:100 lengthsegs:10 widthsegs:10 wirecolor:yellow pos:[-50,-50,0]
  		addmodifier ground (Noisemodifier fractal:on strength:[25,25,25] seed:(random 0 1000000)) -- add a little fun*/
  	scatterNodes ground brush 
  )

Same thing here

fn scatterNodes ground brush = if iskindof ground Editable_Mesh and isvalidnode brush do
  (
  	faces = ground.selectedfaces as bitarray
  	done = #{} 
  	for f in faces where not done[f] collect
  	(
  		polys = meshop.getpolysusingface ground f
  		ground.selectedverts = meshop.getvertsusingface ground polys
  		done += polys
  
  		center = (averageSelVertCenter ground)*ground.objecttransform
  		normal = averageSelVertNormal ground
  		
  		tm = 
  		(
  			face = (polys as array)[1]
  			vv = getface ground face
  			front = normalize ((getVert ground vv[2]) - (getVert ground vv[1]))
  			side = normalize (cross front normal)
  			_front = normalize (cross normal side)
  			matrix3 _front side normal center			
  		)
  		b = copy brush wirecolor:green
  		b.transform = tm
  		b
  	)
  )
  (
  	delete objects
  	brush = 
  	(
  		top = box widthsegs:1 lengthsegs:1 heightsegs:1 width:6 length:0.1 height:4 pos:[3,0,7.5]
  		top.mat = standard diffuse:red
  		bot = Cylinder name:"flag" smooth:on heightsegs:1 capsegs:1 sides:24 height:12 radius:0.2 pos:[0,0,0] wirecolor:red
  		bot.mat = standard diffuse:yellow
  		attach (bot = converttomesh bot) top
  		bot
  	)
  	ground = Box length:50 width:50 height:50 lengthsegs:3 widthsegs:3 heightsegs:3 wirecolor:green \
  	pos:[-50,-50,0] dir:[0.665714,0.202268,0.718271] material:(standard diffuse:blue)
  	converttomesh ground ; ground.selectedfaces = #{9..10, 27..28, 45..46, 63..64, 81..82, 99..100}
  		/*ground = mesh name:"ground" length:100 width:100 lengthsegs:10 widthsegs:10 wirecolor:yellow pos:[-50,-50,0]
  		addmodifier ground (Noisemodifier fractal:on strength:[25,25,25] seed:(random 0 1000000)) -- add a little fun*/
  	scatterNodes ground brush 
  )
6 Replies

ok … lets modify the scatterNodes function

fn scatterNodes ground brush = if iskindof ground Editable_Mesh and isvalidnode brush do
  (
 	 faces = ground.selectedfaces as bitarray
 	 done = #{} 
 	fn averageFaceNormal mesh faces = 
 	(
 		normal = [0,0,0]
 		for f in faces do normal += getfacenormal mesh f
 		normalize (normal/faces.numberset)
 	)
 	 for f in faces where not done[f] collect
 	 (
 		 polys = meshop.getpolysusingface ground f
 		 ground.selectedverts = meshop.getvertsusingface ground polys
 		 done += polys
  
 		 center = (averageSelVertCenter ground)*ground.objecttransform
 		 normal = averageFaceNormal ground polys
 		--averageSelVertNormal ground
 		 
 		 copy brush pos:center dir:normal wirecolor:green
 	 )
  )

Ok. Now is direction and position of the flags corrected. Why this flag and on the other side is slightly rotated.

Also how to make this to works on TriMesh. Only problem here is averageSelVertCenter fn.
If we throw out this fn then we can use maybe something like this

	 fn averageFacePosNormal mesh faces = 
 	 (
 		 local normal = [0,0,0], center = [0,0,0]
 		 for f in faces do normal += getfacenormal mesh f
 		 for f in faces do center += getface mesh f
 		 datapair normal:(normalize (normal/2)) center:(center/2)
 	 )

edit:
I tried this but is wrong

(
	faces = ground.selectedfaces as bitarray
	done = #{} 
	fn averageFacePosNormal mesh faces = 
	(
		local n = [0,0,0], c = [0,0,0]
		for f in faces do n += getfacenormal mesh f
		for f in faces do c += getface mesh f
		dataPair normal:(normalize (n/2)) center:((c/2)*mesh.objecttransform)
	)
	for f in faces where not done[f] collect
	(
		polys = meshop.getpolysusingface ground f
		ground.selectedverts = meshop.getvertsusingface ground polys
		done += polys
		dp = averageFacePosNormal ground polys
		copy brush pos:dp.center dir:dp.normal wirecolor:green
	)
)

a flag rotated? but how do you specify what it has to be? we can use the ground coordinate system… or whatever… we are calculating a normal to surface, but for the side (of front) vector we need some extra axis

1 Reply
(@gazybara)
Joined: 11 months ago

Posts: 0

You mean like this

fn scatterNodes ground brush = if canConvertTo ground Editable_Mesh and isvalidnode brush do
(
	ground = snapshotAsMesh ground
	local faces = ground.selectedfaces as bitarray , done = #{}
	fn averageFacePosNormal mesh faces = 
	(
		local n = [0,0,0], c = [0,0,0], faceCenter = meshop.getFaceCenter
		for f in faces do n += getfacenormal mesh f
		for f in faces do c += faceCenter mesh f
		dataPair normal:(normalize (n/2)) center:(c/2)
	)
	for f in faces where not done[f] collect
	(
		polys = meshop.getpolysusingface ground f ; done += polys
		dp = averageFacePosNormal ground polys
		face = (polys as array)[1]
		vv = getface ground face
		right = normalize ((getVert ground vv[2]) - (getVert ground vv[1]))
		side = normalize (cross right dp.normal)
		front = normalize (cross dp.normal side)
		tm = matrix3 front side dp.normal dp.center
		copy brush transform:tm wirecolor:green
	) ; delete ground
)
(
	delete objects
	brush = 
	(
		top = box widthsegs:1 lengthsegs:1 heightsegs:1 width:6 length:0.1 height:4 pos:[3,0,7.5]
		top.mat = standard diffuse:red
		bot = Cylinder name:"flag" smooth:on heightsegs:1 capsegs:1 sides:24 height:12 radius:0.2 pos:[0,0,0] wirecolor:red
		bot.mat = standard diffuse:yellow
		attach (bot = converttomesh bot) top
		bot
	)
	ground = Box length:50 width:50 height:50 lengthsegs:3 widthsegs:3 heightsegs:3 wirecolor:green \
	pos:[-50,-50,0] dir:[0.665714,0.202268,0.718271] material:(standard diffuse:blue)
	converttopoly ground ; ground.EditablePoly.SetSelection #Face #{5, 14, 23, 32, 41, 50}
	scatterNodes ground brush 
)

yup… exactly right

… maybe better to rename ‘right’ vector to ‘dir’

I will do that. Thanks Denis for your time:beer: