Notifications
Clear all

[Closed] Normal Transformation, Skinned Model

Hey Guys!
i am trying to figure out how i can transform my normals (for a skinned model) correctly so that when the bones move the normals are transformed accordingly here’s how i am doing it:


(
	theFrame = 45	
	theface = 1075
	leg = $_leg
	select leg

	vertexid = ((getface leg theface).x as integer)
	input = at time 0 ((meshop.getfacernormals leg theface)[1])	
	outputValue =  at time theFrame ((meshop.getfacernormals leg theface)[1])		
	computedValue = [0,0,0]
	numberOfBonesPerVertex = skinops.getvertexweightcount theskin vertexid
	for i = 1 to numberOfBonesPerVertex do(
		boneid = skinops.getvertexweightboneid theskin vertexid i
		bonename = skinops.getbonename theskin boneid 1 
		boneTMAt0 = at time 0 (execute ("$" + bonename +".transform"))
		boneTMAtFrame = at time theFrame (execute ("$" + bonename +".transform"))		
		boneTMAt0 = translate boneTMAt0 (- boneTMAt0.row4)
		boneTMAtFrame = translate boneTMAtFrame (- boneTMAtFrame.row4)		
		weight = skinops.getvertexweight theskin vertexid i
		tm = (inverse boneTMAt0) * boneTMAtFrame		
		weightedNormal = (input * tm) * weight
		computedvalue = normalize (computedValue + weightedNormal)
	)		
	format "Normal = %
Output = %
" computedValue outputValue
)

i am multiplying the skinned vertex’s normal (which is the normal for a particular face’s vertex, i.e output of the meshop.getfacernormals function) with the inverse tm of the bone (that influences the particular vertex) at frame 1 (normal is now in bone tm space)
next i am multiplying the normal with the animated transformation matrix of the same bone, finally i multiply it by the weight assigned to the vertex for that bone, I repeat this process for the same vertex for every bone that influences that vertex and then i normalize the sum to obtain the (incorrect) normal , its incorrect because it does not match the normal returned by the edit normal modifier (i am confused which normal is actually correct now!).

*Note: nothing in my scene is scaled (so i do not need to use the inverseTranspose matrix). Also the maxscript i posted above works perfectly if the vertex is rigid (i.e its influenced only by one bone, complications arise for vertices weighted across multiple bones) here is sample input / output (for a vertex weighted between 2 bones, just to show the difference in the result) :
Input = [-0.171326,-0.887662,-0.427439]
My Output = [-0.28916,-0.85693,0.426681]
EN Output = [-0.241229,-0.960267,0.140343] // EM = edit normal modifier same as meshop.getfacernormals

4 Replies
1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

honestly i don’t understand the idea. why do you want to correct normals after the skin deform?

Move the normalize outside of the loop?

computedvalue = [0,0,0]
for i = 1 to numberOfBonesPerVertex do(
	-- Calculate weighted normal
	computedvalue += weightedNormal
)		
computedvalue = normalize computedValue

thanks for the post
i have tried all permutations (i have placed it outside, placed it in both places, removed it completely lol) it just doesnt work for weighted vertices only for rigid ones !
but the thing is when i took these normals into my 3d engine the shading works kind of ok (i think the difference may not be that noticeable!, although the problem still remains as i have not tested it on a uber model yet!)

I need to correct the normals after the skin deform, in my 3d engine. I am using max to figure out the correct algorithm to do so (by comparing with the edit normal modifier and the meshop.getfacernormals).
As i will be exporting the normals per vertex per face only once but as the model animates in my engine i need to be able to calculate the normals correctly at every frame for my pixel shader to work properly (other wise i get animated lighting and artifacts). But the results i get from weighting normals are not the same as edit normal modifier or the meshop.getfacernormals, And still cannot figure out why ! i even checked it with an inverse transpose matrix, which strips of the scaling component, but there was no scaling so the results were the same . I am using the same algorithm in my engine to assign correct vertex position at every frame (based on the motion of the bone) but the algorithm is just not working for normals (what a bummer!!).