Create parts of an Object but keep normals

Hello everyone,

I'm trying to create a little Maxscript for splitting a character into parts for a game but have some trouble with the resulting normal borders and hope anyone here can help me. I've already searched the forum but couldn't find what I'm looking for.

What I'm doing right now:
- I create 3 copys of my character and delete all unwanted faces by material id. This way I get 3 new Objects (in the end this will be more but I'm just testing on a smaller object) This works and I'm doing it this way because I want to keep the skinning of the original object
- To fix the normal borders I'm trying to copy the normal of my original object onto the normal of my new one at the same position. This doesn't work because they always seem to be the same in code although they are different in max

Here's my script so far:

-- variables and declarations --------------------------------------------------
temp = copy $
counter = 1
partsToCreate = #("top", "middle", "bottom")
 
-- delete all modifiers of temp ------------------------------------------------
for i = 1 to temp.modifiers.count do deleteModifier temp 1
 
-- create parts ----------------------------------------------------------------
for partName in partsToCreate do (
 
	--create
	part = copy $ name:partName
 
	--crop by Material ID
	facesToDelete = #()
	for i = 1 to part.numfaces do (
		if polyop.getFaceMatID temp i != counter do append facesToDelete i
	)
	counter += 1
	polyop.deleteFaces part facesToDelete
 
	--adjust normals
 
	-- -- preparation whole
	addmodifier $ (Edit_Normals())
	whole_NormMod = $.modifiers[#Edit_Normals].EditNormalsMod
	whole_VertIDtoPos = #()
	for i = 1 to whole_NormMod.GetNumVertices() do (
		whole_VertIDtoPos[i] = (whole_NormMod.GetVertex i) * $.objecttransform
	)
 
	-- -- preparation part
	addmodifier part (Edit_Normals())
	part_NormMod = $.modifiers[#Edit_Normals].EditNormalsMod
	part_VertIDtoPos = #()
	for i = 1 to part_NormMod.GetNumVertices() do (
		part_VertIDtoPos[i] = (part_NormMod.GetVertex i) * part.objecttransform
	)
 
	-- -- compare and get normal
	for i=1 to part_NormMod.GetNumVertices() do (
		for j=1 to whole_NormMod.GetNumVertices() do (
			if length (whole_VertIDtoPos[j] - part_VertIDtoPos[i]) == 0.0 do (
				whole_Normal = whole_NormMod.getNormal j
				part_Normal = part_NormMod.getNormal i
				format " Body normal: % \n Part normal: % \n" whole_Normal part_Normal 
				part_NormMod.Setnormal i whole_Normal
				format " Body normal: % \n Part normal: % \n\n" whole_Normal part_Normal 
			)
		)
	)
 
	-- -- cleanup
	deletemodifier $ 1
)
 
-- cleanup ----------------------------------------------------------------------
delete temp

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Budi G's picture

Hi Jantaria Check this Vertex

Hi Jantaria
Check this Vertex Normals Stitcher
I made this after watching your topic.
may be useful in the next time

Budi G's picture

In my opinion...it's about

In my opinion...it's about the edit normal modifier.

when your script deleting the face, the number of vertex will be different between original object and part object.
maybe that's why your script doesn't works when matching the normal of part object to the normal of original object.

hmm.. another opinion,
a snipet from your script

-- -- preparation part
addmodifier part (Edit_Normals())
part_NormMod = $.modifiers[#Edit_Normals].EditNormalsMod

just wondering to '$.modifiers' , is it for part object or original object ?
are you sure ? did not write to 'part.modifiers' ...

I don't have a solution for right now but,
can you tell me how you do it by hand to the correct destination?

regards

draging's picture

have you tried this? Edge

have you tried this?
Edge Smooth

there may be something of a problem in the soft edge

Jantaria's picture

...

Thanks for your quick response.

For our engineexport I need seperate objects for each bodypart of my character (head, chest, arms, hands, hip, legs, feet) but i'm modelling all in one with skinning already assigned. If I would only detach faces from my original object instead of copying the whole object and removing faces the detached faces wouldn't have any skinning and I would have to restore it via skin data oder skin wrap which seems more complicated to me than copying and removing faces.

Besides I don't want anything to happen to my original object. I need the parts only for engineexport but for working in max I want my original object to stay whole.

My problem isn't getting my seperate parts but adjusting the normals at the borders. Like you see in the attached file (left: original, right: the parts that the script created) the normal borders are visible but I want them to be smooth. I thought I would get this by copying them from my original object and now I can't see why this isn't working in my actual script and why the normals at the border seem to be the same for the script.

AttachmentSize
example.png 51.56 KB
barigazy's picture

...

Hmmmm...
Using Smooth modifier as instance not solve the problem.
I do not know if it's possible at all to smooth faces in your example

bga

Jantaria's picture

...

no, a smooth modifier would change my mesh, but I only want to fix the normals at the border of my cut part as I could do it by hand with an edit_normals modifier.

This should demonstrate what I want:

AttachmentSize
example2.png 95.58 KB
barigazy's picture

...

You are right. The only solution is Edit Normals modifiers. But if you want to all do automaticaly for let say 100 parts calculation will kill max for sure. I can write a simple tool to correct normals of open edges ei. verts of two object.(specified edges).Are you interested or you already know how to do that?

bga

Jantaria's picture

...

That's what I was trying to do at the bottom part of my script. If you can see where I am going wrong there this would be a great help.

I'm not worried about max breaking. I only create 7 parts and there will be less then 100 vertex normals to fix but at the moment I'm fixing them by hand every time I want to test my character in the engine and this is very timeconsuming and frustrating

barigazy's picture

...

Can you post example file or screenshots.
For now I can tell that you need only one copy of main object, and you can easely detach (not delete) faces by MtlID.
For deleting modifiers better use this line (from behind)

if obj.modifiers.count != 0 do (with redraw off (for m = obj.modifiers.count to 1 by-1 do deleteModifier obj m))

bga

barigazy's picture

...

For detaching faces by mtlID you need this

(
	local poDetach = polyOp.detachFaces
	local poFMatID = polyop.getFaceMatID
	local idArr = #()
	fn getFacesIDs obj &idArr = 
	(
		for f in obj.faces as bitarray do 
		(
			id = poFMatID obj f
			if finditem idArr id == 0 do append idArr id
		)
		if idArr.count == 1 then idArr = #() else idArr
	)
	fn detachByFacesID obj partname: pivotatcenter: wirecol: = if (getFacesIDs obj &idArr).count != 0 do
	(
		lastID = idArr[idArr.count] as string
		obj.name = partname+"_"+"facesID"+lastID
		tempArr = #(obj)
		while idArr.count != 1 do
		(
			faces = #{}
			for f in obj.faces as bitarray where (poFMatID obj f) == idArr[1] do append faces f
			poDetach obj faces delete:on asnode:on name:((trimright obj.name lastID)+(idArr[1] as string))
			append tempArr objects[objects.count] ; deleteitem idArr 1
		)
		free faces
		if pivotatcenter == true do (centerPivot tempArr)
		if wirecol == true do (for p in tempArr do p.wirecolor = random [0,0,0] [255,255,255])
		tempArr
	)
)

bga

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.