Notifications
Clear all

[Closed] Scaling Vertices

Does anyone know how I can scale the selected vertices in an edit mesh?

I’ve tried a number of things but just about the only thing I’ve managed to do on the vertex level is move the vertices.

s = $.selectedVerts
move s [2,2,2]

7 Replies
1 Reply
(@bobo)
Joined: 1 year ago

Posts: 0

Surprise! Both scaling and rotation at sub-object level are actually translations of vertices!
Knowing the center of scaling (assuming you know it), for each vertex you take the current vertex position, subtract the center position and multiply the resulting vector by the scale factor. The resulting vector can then be added to the center again and will represent the point in space your vertex would end up after the scaling. Alternatively, you could build a scaling matrix with position at the center and transform each vertex by it.

(
	theMesh = sphere pos:[10,20,30] radius:50 segs:32 --create a sphere
	convertToMesh theMesh --collapse
	setVertSelection theMesh #{1..97} --select some vertices on top
	theCoordCenter = [40,50,60]  --this will be the ref. coordinate center
	theVerts = getVertSelection theMesh --get the SO selection
	for v in theVerts do  --for each vertex
	(
		theVert = getVert theMesh v --get the vertex position in world space
		theVector = (theVert - theCoordCenter)*[2.0,2.0,2.0] --scale the vector 2x rel. to center
		setVert theMesh v (theCoordCenter + theVector) --assign back the scaled vertex
	)	
	update theMesh --refresh
)

Here is the matrix method:


(
	theMesh = sphere pos:[10,20,30] radius:50 segs:32 --create a sphere
	convertToMesh theMesh --collapse
	setVertSelection theMesh #{1..97} --select some vertices on top
	theCoordCenter = Point pos:[40,50,60]  --create a ref.coordsys
	theVerts = getVertSelection theMesh --get the SO selection
	theScaleMatrix = scaleMatrix [2.0,2.0,2.0] --define the scaling as 2x along X, Y and Z
	theCoordSysMatrix =  theCoordCenter.transform --get the coordsys trnasformation
	for v in theVerts do  --for each vertex
	(
		theVert = getVert theMesh v --get the vertex position in world space
		theVert *= (inverse theCoordSysMatrix) --convert into new coordinate space
		theVert *= theScaleMatrix --scale in that space relatively to the Point01
		theVert *= theCoordSysMatrix --convert out of coord. space into world space
		setVert theMesh v theVert --set the vertex to the new scaled position
	)	
	update theMesh --refresh
)

You can use non-uniform scaling factors like [2.0,3.0,4.0] to scale differently along each axis.

just whipped this up then:

fn scaleVertsEMesh obj amount = 
 (
 verts = (getVertSelection obj) as array
 cnt = verts.count
 if verts.count > 1 then
 (
 mid = [0,0,0]
 for v in verts do mid += getVert obj v
 mid /= cnt
 vectors = for v in verts collect ( normalize ((getVert obj v) - mid) )
 
 for v = 1 to cnt do
 (
 newPos = (getVert obj verts[v]) + (vectors[v] * amount)
 setVert obj verts[v] newPos
 )
 update obj
 )
 )
 
 scaleVertsEMesh $Box01 [2,0,0]

There could be more error checking but it should give you an idea.

Cool, they worked. Gravey’s sort of inflated the object. Bobo’s scaled as max normally does.

Is there any way to do these scale operations in the Edit Mesh modifier and keep the stack? Right now they only work if you collapse. The setVert method complains and the help file even collapses the stack in their example.

SnapshotAsMesh didn’t seem to help much either.
Nor $.mesh

1 Reply
(@bobo)
Joined: 1 year ago

Posts: 0

The Edit Mesh is not scriptable at all.
You can, of course, add an XForm modifier to the SO selection anywhere on the stack (using modPanel.addModToSelection()) and scale its gizmo…

for v in theVerts do  --for each vertex
(
theVert = getVert theMesh v --get the vertex position in world space
theVert *= (inverse theCoordSysMatrix) --convert into new coordinate space
theVert *= theScaleMatrix --scale in that space relatively to the Point01
theVert *= theCoordSysMatrix --convert out of coord. space into world space
setVert theMesh v theVert --set the vertex to the new scaled position
) 

Can you multiply these matrices together, and then apply the result to the vertex?

2 Replies
(@bobo)
Joined: 1 year ago

Posts: 0

Of course, you can do that, and it will speed up calculations a lot because the matrix multiplications can be taken out of the loop and only the vertex scaling would happen inside:

(
 	theMesh = sphere pos:[10,20,30] radius:50 segs:32 --create a sphere
 	convertToMesh theMesh --collapse
 	setVertSelection theMesh #{1..97} --select some vertices on top
 	theCoordCenter = Point pos:[40,50,60]  --create a ref.coordsys
 	theVerts = getVertSelection theMesh --get the SO selection
 	--Now build a matrix to scale every vertex 2x:
 	theTM = (inverse theCoordCenter.transform) * (scaleMatrix [2.0,2.0,2.0]) * theCoordCenter.transform
 	for v in theVerts do  --for each vertex, scale by the matrix and set the vertex
 		setVert theMesh v ((getVert theMesh v)*theTM) 
 	redrawViews()
 )

The main reason for my initial code was to have more room for comments so people would understand WHY they have to multiply the value by 3 matrices. You must admit it was easier to read…

The update() call was actually not necessary as we are not changing topology.
RedrawViews() takes care of refreshing the viewports to show the scaled vertices.

(@drdubosc)
Joined: 1 year ago

Posts: 0

Sure … I partly asked the question because I can never remember the order you do the multiplications in.