good results… i’m using as a test object the all parts Teapot with 32 segments (32898 verts, 4096 open edges).
your code gives me:
time:175 memory:5705960L
my code (which is almost identical to yours but better optimized) gives:
time:111 memory:5046656L
I noticed display statistics (shortcut 7) plays a BIG role in performance in max 2014. I tested with a teapot with 64segs + TS (~1 million polys), as expected viewport speed goes to a crawl, but as soon as I turn display statistics on I get ~60fps!
The same in max 2012 doesn’t work, performance is very poor but better than max 2014 with no statistics.
Is there a way to make the gw lines not appear on the backside of geo?
Denis its surprising to see you pleased with results after you quickly shot down my post idea from day one. :applause:
I made a script that uses gw, but the performance was…
My way to acheive this was to check if the edges are visible in the viewport and if they are not, then the redrawCallbacks fn did not draw gw lines for those edges.
Also, did anyone succeed using gw.Polygon?
I cannot get it working in any Max version, not even the examples provided in the help.
If there is a way to get gw.Polygon working, then I think backface culling could work.
I am using a custom model, which has 6000 uv open edges, 5000 shared and 1000 mesh open edges. Then I just turbosmooth it to get an average of low and high polygons.
For that teapot, I get 80ms, which means using your optimizations I should get around 51ms.
I get 48ms just before entering the loops. Even if I completely remove the first loop, I get 54ms, which is still slower than your code, so I suspect the optimization should be before the loops, but I really can see where or how.
In the latest code, the lines append foundEdges
in the second loop shouldnt be there, but taking them away dont make any big difference in the teapot test.
Denis,
I cant share the models I am using because they are copyrighted and I am not the owner, althought I created them, but I have created a similar object for you to test.
It is obviously not the same as the one I am testing, but it has barely the same amount of uv edges and mesh open edges, so the results should be similar.
I test it as it is, the with 1, 2 and 3 turbosmooth iterations.
Its an .obj, so others can open it too.
These are the results I got using the model I’ve uploaded.
Previous version
Base Model
Found 3920 UV Open Edges in 92ms
Used Memory 3048248L
TurboSmooth 1 iteration
Found 7840 UV Open Edges in 291ms
Used Memory 7275320L
TurboSmooth 2 iterations
Found 15680 UV Open Edges in 990ms
Used Memory 19341568L
Latest version
Base Model
Found 3920 UV Open Edges in 49ms
Used Memory 2769144L
TurboSmooth 1 iteration
Found 7840 UV Open Edges in 107ms
Used Memory 6082848L
TurboSmooth 2 iterations
Found 15680 UV Open Edges in 246ms
Used Memory 14535560L
i have absolutelly different numbers for your code…
that’s what i actually use:
(
unRegisterRedrawViewsCallback cbDrawOpenEdges
global RO_DISPLAY_UV_OE
global cbDrawOpenEdges
global cbSelectionChanged
local vertexPos = #()
local uvChannel = 1
local edgesColor = [0,255,0]
local edgeOffset = 0.03
local forceRedraw = false
local polyLine = gw.polyLine
fn cbDrawOpenEdges = (
gw.setTransform (Matrix3 1)
gw.setColor #line edgesColor
for j in vertexPos do polyLine j true
-- Needed in some Max versions or used dirvers
if forceRedraw do (
gw.enlargeUpdateRect #whole
gw.updateScreen()
)
)
fn cbSelectionChanged mForce:false = (
unRegisterRedrawViewsCallback cbDrawOpenEdges
if ($ != undefined) do (
setwaitcursor()
t1 = timeStamp()
m1 = heapfree
cGetMapFace = meshop.getMapFace
obj = snapshotasmesh selection[1]
allChannels = for j = 1 to meshop.getNumMaps obj where (meshop.getMapSupport obj j) collect j
RO_DISPLAY_UV_OE.ddl_channel.items = for j in allChannels collect j as string
if (mForce == false) do (
uvChannel = allChannels[1]
RO_DISPLAY_UV_OE.ddl_channel.selection = 1
)
numTFaces = meshop.getNumMapFaces obj uvChannel
numTVerts = meshop.getNumMapVerts obj uvChannel
emesh = trimesh()
setMesh emesh numverts:numTVerts numfaces:numTFaces
setMesh emesh faces:(for j = 1 to numTFaces collect (cGetMapFace obj uvChannel j))
objOpenEdges = meshop.getOpenEdges obj
meshOpenEdges = meshop.getOpenEdges emesh
delete emesh
sharedFaces = meshop.getFacesUsingEdge obj meshOpenEdges
foundEdges = #()
vertexPos = #()
for j in sharedFaces do (
objFaceVerts = getFace obj j
edge1 = j*3 - 2
edge2 = j*3 - 1
edge3 = j*3
v1Idx = objFaceVerts.x
v2Idx = objFaceVerts.y
v3Idx = objFaceVerts.z
v1 = getVert obj v1Idx
v2 = getVert obj v2Idx
v3 = getVert obj v3Idx
if meshOpenEdges[edge1] do (
found = findItem foundEdges [v1Idx, v2Idx]
if (found == 0) then (
append vertexPos #(v1,v2)
append foundEdges [v2Idx, v1Idx]
)else(
deleteitem foundEdges found
)
)
if meshOpenEdges[edge2] do (
found = findItem foundEdges [v2Idx, v3Idx]
if (found == 0) then (
append vertexPos #(v2,v3)
append foundEdges [v3Idx, v2Idx]
)else(
deleteitem foundEdges found
)
)
if meshOpenEdges[edge3] do (
found = findItem foundEdges [v3Idx, v1Idx]
if (found == 0) then (
append vertexPos #(v3,v1)
append foundEdges [v1Idx, v3Idx]
)else(
deleteitem foundEdges found
)
)
)
format "mesh >> open edges:% time:% memory:%
" vertexPos.count (timestamp() - t1) (m1 - heapfree)
registerRedrawViewsCallback cbDrawOpenEdges
delete obj
gc light:true
setArrowCursor()
)
forceCompleteRedraw()
)
try(destroyDialog RO_DISPLAY_UV_OE) catch()
rollout RO_DISPLAY_UV_OE "UV Open Edges" width:160 height:198
(
checkbutton bt_enable "Display UV Open Edges" pos:[8,8] width:144 height:32
dropdownList ddl_channel "UV Channel:" pos:[8,72] width:120 height:40 enabled:false
colorPicker cp1 "" pos:[131,90] width:21 height:21 enabled:true color:edgesColor modal:false
checkbox chk_redraw "Force Redraw" pos:[8,46] width:100 height:16 enabled:false
spinner spn_width "Edge Width:" pos:[8,120] width:120 height:16 range:[1,100,4] type:#integer fieldwidth:50
button bt_update "Update" pos:[8,160] width:144 height:28 enabled:false
fn destroy = (
callbacks.removeScripts #selectionSetChanged
unRegisterRedrawViewsCallback cbDrawOpenEdges
forceCompleteRedraw()
)
on RO_DISPLAY_UV_OE close do destroy()
on bt_enable changed arg do
(
bt_update.enabled = arg
ddl_channel.enabled = arg
chk_redraw.enabled = arg
destroy()
if (arg == true) do (
callbacks.addscript #selectionSetChanged "cbSelectionChanged()"
cbSelectionChanged()
)
)
on bt_update pressed do cbSelectionChanged()
on ddl_channel selected arg do (
uvChannel = (ddl_channel.selected as integer)
cbSelectionChanged mForce:true
)
on cp1 changed arg do edgesColor = arg
on spn_width changed arg do edgeOffset = (arg-1)/100.0
on chk_redraw changed arg do forceRedraw = arg
)
createDialog RO_DISPLAY_UV_OE
)
for your sample object i have:
with no turbosmooth it’s
mesh >> open edges:3920 time:165 memory:1275784L
with 1 turbosmooth iteration it’s
mesh >> open edges:7840 time:600 memory:3171480L
With your code I get these results:
[b]Base Model[/b]
mesh >> open edges:3920 time:69 memory:1291032L
[b]Turbosmooth 1 iteration[/b]
mesh >> open edges:7840 time:243 memory:3211120L
[b]Turbosmooth 2 iterations[/b]
mesh >> open edges:15680 time:878 memory:8814776L
With my latest code I get these:
Base Model
mesh >> open edges:3920 time:50 memory:2754200L
Turbosmooth 1 iteration
mesh >> open edges:7840 time:108 memory:6075416L
Turbosmooth 2 iterations
mesh >> open edges:15680 time:245 memory:14534304L
From these results yours uses about half the memory and mine runs about 2.5 times faster.
ok. here is my code:
try(unregisterRedrawViewsCallback showOpenMapEdgesDialog.drawEdges; completeredraw()) catch()
try(destroydialog showOpenMapEdgesDialog) catch()
rollout showOpenMapEdgesDialog "Open Map Edges" width:200
(
fn getOpenMapEdges node channel:1 debug:on = if iskindof node GeometryClass and canconvertto node editable_mesh do
(
t1 = timestamp()
m1 = heapfree
local mesh = snapshotasmesh node
local edges = #()
if meshop.getmapsupport mesh channel do
(
numtverts = meshop.getnummapverts mesh channel
getmapface = meshop.getmapface
tfaces = for f=1 to mesh.numfaces collect (getmapface mesh channel f)
local emesh = TriMesh()
setmesh emesh numverts:numtverts numfaces:mesh.numfaces
setmesh emesh faces:tfaces
seamed = meshop.getopenedges emesh
opened = meshop.getopenedges mesh * seamed
faces = meshop.getfacesusingedge mesh seamed
for f in faces do
(
vv = getface mesh f
e = f*3 - 3
if seamed[e += 1] and (vv[1] < vv[2] or opened[e]) do append edges #(getvert mesh vv.x, getvert mesh vv.y)
if seamed[e += 1] and (vv[2] < vv[3] or opened[e]) do append edges #(getvert mesh vv.y, getvert mesh vv.z)
if seamed[e += 1] and (vv[3] < vv[1] or opened[e]) do append edges #(getvert mesh vv.x, getvert mesh vv.z)
)
if debug do format "mesh >> open edges:% time:% memory:%
" edges.count (timestamp() - t1) (m1 - heapfree)
free mesh
free emesh
)
edges
)
local edges
fn drawEdges = if edges != undefined do
(
polyLine = gw.polyLine
gw.setTransform (matrix3 1)
gw.setColor #line green
for e in edges do polyLine e off
gw.enlargeUpdateRect #whole
gw.updateScreen()
)
checkbutton draw_bt "Show" width:190
on draw_bt changed state do
(
unregisterRedrawViewsCallback drawEdges
if state do if (edges = getOpenMapEdges selection[1] debug:on) != undefined do registerRedrawViewsCallback drawEdges
gc light:on delayed:on
completeredraw()
)
)
createdialog showOpenMapEdgesDialog
what numbers does it make for your sample on your machine?
This approach runs faster and uses less memory than mine.
Base Model
mesh >> open edges:3920 time:20 memory:1137208L
Turbosmooth 1 iteration
mesh >> open edges:7840 time:51 memory:2799352L
Turbosmooth 2 iterations
mesh >> open edges:15680 time:137 memory:7984208L
If I remove the Edge Width from my code, yours still runs faster and uses a bit less memory
These are the numbers I get removing the Edge Width feature
Base Model
mesh >> open edges:3920 time:32 memory:1267368L
Turbosmooth 1 iteration
mesh >> open edges:7840 time:74 memory:3061984L
Turbosmooth 2 iterations
mesh >> open edges:15680 time:182 memory:8510272L