Pivot Painter - Understanding Values corretly

Hi,
The data format is listed in the help section of the script. The actual packing of data is fairly simple although a little non intuitive. The bulk of the script relates to the ui and prep tools section.

This is the text defining the data layout in the help section of the script (ignore the \r markup ):

---------------------------------\r
Hierachy Painter Output\r
---------------------------------\r
Child data:\r
Vert Alpha: parent[X][X] (0-1) \r
Vert Color: parent position XYZ (0-1)\r
UV channel 3: child pivot position XY (WS)\r + child [X][X],[X][Y] (0-1)\r
UV channel 4 R: child pivot position Z (WS)\r + child [X]Z\r
UV channel 4 G: parent[X]Y * Z sign\r

Parent Information: \r
Vert Alpha: parent[X][X] (0-1)\r
Vert Color: parent position XYZ (0-1)\r
UV channel 3: 0\r
UV channel 4 R: 0\r
UV channel 4 G: parent[X][Y] (0-1) * Z sign\r
---------------------------------\r
Per Object Painter Output\r
---------------------------------\r
With Optimize Off:\r
Vert alpha : Custom Falloff\r
Vertex color : X Vector (rotation) (0-1)\r
UV channel 3: Pivot position XY (WS)\r
UV channel 4 R: Pivot position Z (WS)\r
UV channel 4 G: Random value (0-1)\r

With Optimize On:\r
Vert alpha : Empty\r
Vertex color : Empty\r
UV channel 3: Pivot position XY(WS)\r
UV channel 4 R: Pivot position Z (WS)\r
UV channel 4 G: Random value (0-1)


This is the code specifically used to paint per object values (I’ll point out the necessary parts after) :



fn paintLocalValues paintVectorOrRotation:1	optimized:false=(
		try 
		with redraw off (
			localMaxOperations=LeafArray.count
			for i=1 to LeafArray.count do(
					currMesh = LeafArray*
					pivotPos=currMesh.pos*255
				if optimized==true then (
					polyop.setVertColor currMesh 3 #all [pivotPos[1],pivotPos[2],0]
					polyop.setVertColor currMesh 4 #all [pivotPos[3],(random 0.0 255.0),0]
				) else (
					localBoundingBox=nodeGetBoundingBox currMesh currMesh.transform
					localBoundingBoxDist= distance localBoundingBox[1] localBoundingBox[2]
		
					if paintVectorOrRotation == 1 then (
						myAngle=((((normalize currMesh.transform[1])*[1,-1,1])+1)/2)*255 -- Branch x axis vector --make the value 0-1 in unreal -- unreal inverts vert color y
					) else (
						myAngle= in coordsys world quatToEuler2 (inverse currMesh.rotation);
						myAngle= [myAngle.x,myAngle.y,myAngle.z]
						myAngle=(myAngle*(256.0/360.0))+128
					)
					polyop.setVertColor currMesh 0 #all myAngle
					polyop.setVertColor currMesh 3 #all pivotPos
					polyop.setVertColor currMesh 4 #all [pivotPos[3],(random 0.0 255.0),0]--leaf pivot (0-1), leaf z rotation
					--Paint alpha per vertex 
					for v=1 to (getNumVerts currmesh) do (
						if keyboard.escPressed do ResumeEditing()
						currVert=polyop.getVert currMesh v
						currVertBaseObj=polyop.getVert currMesh.baseobject v
						gradBBX=[0,localBoundingBox[1][1],0]
						gradBBXTwo=[0,localBoundingBox[2][1],0]
						gradBBY=[0,localBoundingBox[1][2],0]
						gradBBYTwo=[0,localBoundingBox[2][2],0]
						gradBBZ=[0,localBoundingBox[1][3],0]
						gradBBZTwo=[0,localBoundingBox[2][3],0]
						finXScale = (distance gradBBX gradBBXTwo)
						finYScale = (distance gradBBY gradBBYTwo)
						finZScale = (distance gradBBZ gradBBZTwo)
						finXVal= (pow ((distance [0,currVertBaseObj[1],0] gradBBX)/finXScale) leafWingFalloffPowerX ) + (pow((distance [0,currVertBaseObj[1],0] gradBBXTwo)/finXScale) leafWingFalloffPowerX)
						finYVal= (pow ((distance [0,currVertBaseObj[2],0] gradBBY)/finYScale) leafWingFalloffPowerY ) + (pow((distance [0,currVertBaseObj[2],0] gradBBYTwo)/finYScale) leafWingFalloffPowerY)
						finZVal= (pow ((distance [0,currVertBaseObj[3],0] gradBBZ)/finZScale) leafWingFalloffPowerZ ) + (pow((distance [0,currVertBaseObj[3],0] gradBBZTwo)/finZScale) leafWingFalloffPowerZ)
						distanceToPivot=distance currVert currMesh.pos/255
						finalAlpha= clamp (((pow (distanceToPivot*leafLengthFalloff)leafLengthFalloffPower) +(finYVal*leafWingFalloffY)+(finXVal*leafWingFalloffX)+(finZVal*leafWingFalloffZ))*255) 0 255
						polyop.setVertColor currmesh -2 v [finalAlpha,finalAlpha,finalAlpha] 
					)
				)
				updateProgBar maxOperations:localMaxOperations currentOperation:i bar:2
			)
		) catch(displayAutoErrorMessage())
	)




A lot of that code is for the custom alpha values. You probably just need:



**store the x axis**
myAngle=((((normalize currMesh.transform[1])*[1,-1,1])+1)/2)*255 -- Branch x axis vector --make the value 0-1 in unreal -- unreal inverts vert color y. Basically, we are just constant bias scaling the values to a 0-1 range and then multiplying it by 255 for 3DS's vertex colors scale. 

polyop.setVertColor currMesh 0 #all myAngle -- feed the vector into the models vertex colors.


and

store the pivot point



pivotPos=currMesh.pos*255
polyop.setVertColor currMesh 3 #all pivotPos     --- this stores the X and Y values of the pivot point in R and G of uv Channel 3 (uv channel 2 in unreal. Unreals uvs are 0 based and max is 1 based)
polyop.setVertColor currMesh 4 #all [pivotPos[3],(random 0.0 255.0),0] -- just stores a random per element value in G


When testing to see if your values are being packed and read correctly in Unreal you can use the debug scalar or debug float 3 material functions. That will make the conversion process less confusing.

Btw improvements could be made to the way that pivot painter data is packed. Instead of using several channels to pack a rotation vector it could be done with just 1 uv channel. x(in the 0-1 range) + y(in the 0-.1) and z (in the .00-.01 range) added together into a single scalar value.

The current method for packing leaf rotation vectors is very poor as well. It kind of borders on random due to floating point accuracy. But this is the data format for the hierarchy painter if anyone is interested (note that the uv count that the script was initially written for was very limited):



fn convertWPtoUV Pos:[0,0,0] = (
	global temp=(Pos/shaderWSMultiplier)*[128,128,255]+[128,128,0]
	global tempx= clamp (temp[1]) 0 255
	global tempy= clamp (temp[2]) 0 255
	global tempz= clamp (temp[3]) 0 255
	global temp=[tempx,tempy,tempz]
)

fn paintLeaves = ( -- paints branches and leaves 
		try 
		with redraw off (
			global branchLocalBoundingBox=nodeLocalBoundingBox currBranchObj
			branchLocalBoundingBox = distance branchLocalBoundingBox[1] branchLocalBoundingBox[2]
			branchAngle=(normalize currBranchObj.transform[1])*[1.0,-1.0,1.0] -- Branch x axis vector (float 3) -- invert y for vert color 
			if branchAngle[3]<0 then (zSign=-1.0) else (zSign=1.0)
			branchAngle=((branchAngle+[1.0,1.0,1.0])/2.0)*255.0 -- Branch x axis vector (float 3) 
			branchAngle=[clamp branchAngle[1] 0 255,branchAngle[2],branchAngle[3]]
			global uv4Green=(branchAngle[2]*zSign)
			branchPos=convertWPtoUV pos:(currBranchObj.pos*[1,-1,1]) -- 0-1 range flip the y axis
			polyop.setVertColor currBranchObj -2  #all [branchAngle[1],0,0] -- set vert color for branch to branch position
			polyop.setVertColor currBranchObj 0  #all branchPos -- set vert color for branch to branch position
			polyop.setVertColor currBranchObj 3 #all [0,0,0] -- can be used for pixel shading if needed
			polyop.setVertColor currBranchObj 4 #all [0,uv4Green,0]
			fnpaintleavesMaxOp=leafArray.count  
		for i = 1 to leafArray.count do (
				currObj=leafArray*
				pivotPos=currObj.pos*255
				pivotPos=[ceil pivotPos[1],ceil pivotPos[2],ceil pivotPos[3]]
				xAxis=(((normalize currObj.transform[1])*.5)+.5)*255 -- leaf's x - axis
				xAxis=[clamp (xAxis[1]) 20 240, clamp (xAxis[2]) 20 240, clamp (xAxis[3]) 20 240] -- padding is added to avoid the lack of precision -- only works for near meshes
				if pivotpos[1]>0 then (pivotpos[1]+=xAxis[1]) else (pivotpos[1]-=xAxis[1])
				if pivotpos[2]>0 then (pivotpos[2]+=xAxis.y) else (pivotpos[2]-=xAxis.y)
				if pivotpos[3]>0 then (pivotpos[3]+=xAxis.z) else (pivotpos[3]-=xAxis.z)
				polyop.setVertColor currObj -2 #all [branchAngle[1],0,0]--branch - y axis
				polyop.setVertColor currObj 0 #all branchPos--branch position
				polyop.setVertColor currObj 3 #all pivotPos -- + x transform in the remainder
				polyop.setVertColor currObj 4 #all [pivotPos[3],uv4Green,0]--leaf pivot (ws), random value or constant bias scaled X with Z sign. use absolute value then scale bias to find x. Derive z from x and y to find z. Apply z sign to z channel.
				updateProgBar maxOperations:fnpaintleavesMaxOp currentOperation:i bar:3
		)
		) catch(displayAutoErrorMessage())
	)


so basically you constant bias scale the branch x axis vector. the find the sign of z and apply that as the sign of one of the other channels (y). so if Z was negative then we would multiply the y channel by -1. (In the shader we derive z from x and y but the returned z value is always positive so we need to store and reapply the sign after we use derive z in the shader)

you can probably read through the rest but if there are any specific questions i would be happy to help.

by the way, polyop.setVertColor currBranchObj -2 refers to vertex alpha. polyop.setVertColor currObj 0 #all branchPos is vertex color