PDA

View Full Version : trimesh and editable_polys.


reForm
01-05-2009, 04:34 PM
I'm trying to improve my script by having all operations applied to a snapshotasmesh, rather than a copy of the node as editable_poly/mesh. (the idea being to improve the speed of the script, as snaphotasmesh doesn't seem to refresh the modify-panel, and as far as I'm aware its alot faster than copying the mesh anyway)

The problem is that I need to retain the topology of the original mesh. Something that is lost when snapshotted. ie a plane with one segment has 1 face in editable poly, but 2 if its a trimesh.

Are there simple methods to be able to work with a trimesh as though it was an editable poly such that I'm working with 4-sided polygons rather than just tri's? or do I need to make an array containing the pairs of tri's that make up each polygon on the source mesh?

Any suggestions?

reForm
01-05-2009, 07:12 PM
Ok, I've made some progress... but its a bit slow. I've gone down the route of making an array with items for each polygon containing the face-IDs. Here's the function:


fn areEqual arr1 arr2 =
(
local equal = true
if arr1.count == arr2.count then
(
for i = 1 to arr1.count where equal do --break out if inequality found
(
equal = (arr1[i] == arr2[i])
)
)
else equal = false

equal
)

fn getObjPolys obj = (
local polys = #()
local numfaces = meshop.getnumfaces obj
local Faces = #{1..numFaces} as array
polys[1]=(meshop.getPolysUsingFace obj faces[1]) as array
while Faces.count > 0 do
(
thepolybitarray = (meshop.getPolysUsingFace obj faces[1]) as array
if (areEqual thepolybitarray polys[polys.count])!= true do
append polys thepolybitarray
deleteitem faces 1
if pbar==1 do this.prog.pbar.value = 100*Faces.count/numFaces
)
polys
)


Is there a quicker way of getting the polygons of a trimesh into an array?

JHN
01-05-2009, 07:36 PM
Maybe you can explain what exactly it is you cannot do on a trimesh, you could always build an array with for example invisible edges or triface pairs of the epoly and use that to work on the trimesh. If it's the best way I don't know, you can also stop the sceneredrawing with disable and enablesceneredraw()

Maybe that will give you some more millage.

-Johan

reForm
01-05-2009, 07:57 PM
Ah, thanks, that is a good suggestion. Going through the invisible edges will be quicker and not require culling of duplicate faces.

I'm wanting to do it in trimesh to avoid the modify panel refresh that occurs when I create a copy of a node... and I don't want to go to max create mode to avoid this problem.

reForm
01-06-2009, 11:20 AM
Hmm, well what seemed to be a good approach turns out to be not so.
For some reason, there are two invisible edges for every polygon where I thought there would only be one. As a result, I still have to check the array for a face reference before I add a new one... which is the main time killer.

Here's the code for getting an array of faces that make up the polys.


fn getObjPolys obj = (
-- DECLARE VARIABLES
local polys = #()
local edgeSelSet = #()
local faces = #()
local numfaces = meshop.getnumfaces obj
-- GET THE INVISIBLE EDGES
edgeselset = for face = 1 to numfaces collect for medge = 1 to 3 where (getedgevis obj face medge)==false collect (((face-1)*3)+medge)
-- GET THE FACES FROM THE INVISIBLE EDGES
faces = for i = 1 to edgeSelSet.count collect (meshop.getFacesUsingEdge obj edgeSelSet[i])
-- GET THE FIRST POLYS
polys[1]=(meshop.getPolysUsingFace obj faces[1]) as array
-- LOOP THROUGH THE FACES AND ONLY ADD FACES THAT HAVEN'T ALREADY BEEN ADDED
while faces.count > 0 do (
thepolybitarray= (meshop.getpolysusingface obj faces[1]) as array
if (areEqual thepolybitarray polys[polys.count])!= true do
append polys thepolybitarray
deleteitem faces 1
)
polys -- RETURN THE ARRAY OF POLYS
)

and here's the faster version that just finds the faces for each poly.


fn getObjPolys obj = (
-- DECLARE VARIABLES
local polys = #()
local numfaces = meshop.getnumfaces obj
local Faces = #{1..numFaces} as array
-- GET THE FIRST POLYS
polys[1]=(meshop.getPolysUsingFace obj faces[1]) as array
-- LOOP THROUGH THE FACES AND ONLY ADD FACES THAT HAVEN'T ALREADY BEEN ADDED
while Faces.count > 0 do
(
thepolybitarray = (meshop.getPolysUsingFace obj faces[1]) as array
if (areEqual thepolybitarray polys[polys.count])!= true do
append polys thepolybitarray
deleteitem faces 1
)
polys
)



with an object of 3200 faces its taking 5.6s for the first code version, and 5.4s for the second version.

Is there a faster method for building an array of arrays containing the faces of each poly in an object?

j-man
01-06-2009, 12:13 PM
Hi Reform,

maybe you already know this but just in case:

In 3ds Max 7 and higher, you can also completely disable Modify Panel updates using the new suspendEditing() and resumeEditing() methods:

also, in answer to your question regarding the speed of arrays, bitarrays are much faster.

As far as a tri-mesh being able to handle four sided polygons, I think the answer is no. A tri-mesh is exactly that, a mesh made from faces with three sides. A four sided poly is actually made from two three sided polys when you undo the bolts holding it together, even an EPoly.

I hope this is useful,

Regards,

Josh.

reForm
01-06-2009, 12:40 PM
maybe you already know this but just in case:

Yep, I'm trying to avoid that workaround, as I'd prefer the modify panel to remain active( my intention is to have live feedback from the script, which is impossible when you switch to max edit mode)


As far as a tri-mesh being able to handle four sided polygons, I think the answer is no. A tri-mesh is exactly that, a mesh made from faces with three sides. A four sided poly is actually made from two three sided polys when you undo the bolts holding it together, even an EPoly.
I am aware of this, but with each invisible edge, you can identify that there is an n-gon, so it isn't hard to work on a trimesh in the same way as you would an editable_poly.

To be more specific, I need to obtain from the trimesh the following things.

The polygon count (not face count)
The number of 4 sided polygons
The area of each 4-sided polygon
The normal of each 4-sided polygon
The tris that constitute each 4-sided polygon
This is no problem to achieve, the only problem I have at the moment is getting an array of the tris that constitute each polygon in a reasonable amount of time...

Ofcourse doing this in trimesh may turn out to be far less efficient that just taking a copy of the object and operating on it as a e-poly rather than a trimesh.... but I would like to be sure that this is the case before I revert to working with a copy of the object as editable poly.

Thanks for the suggestions anyway!

SyncViewS
01-09-2009, 01:01 AM
Hi Patrick,
Here is a function to get all the data you requested from a Mesh Object. The returning array is a pack of other arrays, just to avoid defining structs.

aaiQuadsIndex, afQuadsArea, ap3QuadsNormal got the same array index for the same Quad, that means i.e. that:

aaiQuadsIndex[3] stores the array of mesh faces indexes forming a quad
afQuadsArea[3] stores the floating point value of same quad area
ap3QuadsNormal[3] stores the Point3 of the same quad average normal

I cannot tell if it's faster than your, on my now old Athlon 5000, it requires about 5.5 seconds for a 3200 quads (6400 mesh faces) plane. Just give it a try.


function getMeshFaceData oMesh =
(
local baMeshFaces = #{1..(meshOp.getNumFaces oMesh)}
local aaiFaceGroups = #()

local i = baMeshFaces.numberSet
while (i > 0) do
(
baMeshFacesInGroup = meshOp.getPolysUsingFace oMesh (baMeshFaces as Array)[1] ignoreVisEdges:false threshhold:120
append aaiFaceGroups (baMeshFacesInGroup as Array)
baMeshFaces -= baMeshFacesInGroup
i = baMeshFaces.numberSet
)

local aaiQuadsIndex = #()
local afQuadsArea = #()
local ap3QuadsNormal = #()

local p3TempNormal = [0,0,0]

for aiGroup in aaiFaceGroups do
(
if (aiGroup.count == 2) then
(
append aaiQuadsIndex aiGroup
append afQuadsArea (meshOp.getFaceArea oMesh aiGroup)

for iFace in aiGroup do
(
p3TempNormal += getFaceNormal oMesh iFace
)
append ap3QuadsNormal (normalize(p3TempNormal))
p3TempNormal = [0,0,0]
)
)
return #(aaiFaceGroups, aaiQuadsIndex, afQuadsArea, ap3QuadsNormal)
)

-- sample code
oCylinder = cylinder()
oCylinderMesh = convertToMesh oCylinder
meshData = getMeshFaceData oCylinderMesh

format "Polygon count -> %\n" meshData[1].count
format "Quads count -> %\n" meshData[2].count
format "Quads indexes -> %\n" meshData[2]
format "Quads areas -> %\n" meshData[3]
format "Quads normals -> %\n" meshData[4]

The code isn't commented. I'm sorry, it's a bit late (2 am), feel free to ask for explanations.

I don't know what's the purpose of this, but if you explain what you're trying to achieve, maybe there are better ways to walk.

- Enrico

CGTalk Moderation
01-09-2009, 01:01 AM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.