diff options
author | Campbell Barton <ideasman42@gmail.com> | 2006-08-02 08:40:50 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2006-08-02 08:40:50 +0400 |
commit | 7ec55d7a62efd4b9d6de24b21b6db766d0099d7f (patch) | |
tree | 1e2a332c6f2c379c2dd1477675e8457a8dc70cfc /release | |
parent | 70853bbcc7f34069abf6f12d1199394cc2e67cd6 (diff) |
Made this script test 4 different collapse locations and use the one that results in the least error.
locations are: smart, middle, v1, and v2
where smart is an attempt to generate a loc that will collapse without loosing volume.
This can now collapse a subdivided cube properly.
Diffstat (limited to 'release')
-rw-r--r-- | release/scripts/bpymodules/BPyMesh.py | 4 | ||||
-rw-r--r-- | release/scripts/bpymodules/BPyMesh_redux.py | 234 | ||||
-rw-r--r-- | release/scripts/mesh_poly_reduce.py | 1 |
3 files changed, 133 insertions, 106 deletions
diff --git a/release/scripts/bpymodules/BPyMesh.py b/release/scripts/bpymodules/BPyMesh.py index fc4f517879f..883ec92ce77 100644 --- a/release/scripts/bpymodules/BPyMesh.py +++ b/release/scripts/bpymodules/BPyMesh.py @@ -19,7 +19,9 @@ import Blender -from BPyMesh_redux import redux # seperated because of its size. +import BPyMesh_redux # seperated because of its size. +reload(BPyMesh_redux) +redux= BPyMesh_redux.redux # python 2.3 has no reversed() iterator. this will only work on lists and tuples try: diff --git a/release/scripts/bpymodules/BPyMesh_redux.py b/release/scripts/bpymodules/BPyMesh_redux.py index 0f3177ae651..e68c2c617ae 100644 --- a/release/scripts/bpymodules/BPyMesh_redux.py +++ b/release/scripts/bpymodules/BPyMesh_redux.py @@ -165,6 +165,68 @@ def redux(ob, REDUX=0.5, BOUNDRY_WEIGHT=2.0, REMOVE_DOUBLES=False, FACE_AREA_WEI # Basic weighting. #self.collapse_weight= self.length * (1+ ((ed.v1.no-ed.v2.no).length**2)) self.collapse_weight= 1.0 + + def collapse_locations(self, w1, w2): + ''' + Generate a smart location for this edge to collapse to + w1 and w2 are vertex location bias + ''' + + v1co= self.v1.co + v2co= self.v2.co + v1no= self.v1.no + v2no= self.v2.no + + # Basic operation, works fine but not as good as predicting the best place. + #between= ((v1co*w1) + (v2co*w2)) + #self.collapse_loc= between + + # normalize the weights of each vert - se we can use them as scalers. + wscale= w1+w2 + if not wscale: # no scale? + w1=w2= 0.5 + else: + w1/=wscale + w2/=wscale + + length= self.length + between= (v1co+v2co) * 0.5 + + # Collapse + # new_location = between # Replace tricky code below. this code predicts the best collapse location. + + # Make lines at right angles to the normals- these 2 lines will intersect and be + # the point of collapsing. + + # Enlarge so we know they intersect: self.length*2 + cv1= CrossVecs(v1no, CrossVecs(v1no, v1co-v2co)) + cv2= CrossVecs(v2no, CrossVecs(v2no, v2co-v1co)) + + # Scale to be less then the edge lengths. + cv1.normalize() + cv2.normalize() + cv1 = cv1 * (length* 0.4) + cv2 = cv2 * (length* 0.4) + + smart_offset_loc= between + (cv1 + cv2) + + # Now we need to blend between smart_offset_loc and w1/w2 + # you see were blending between a vert and the edges midpoint, so we cant use a normal weighted blend. + if w1 > 0.5: # between v1 and smart_offset_loc + #self.collapse_loc= v1co*(w2+0.5) + smart_offset_loc*(w1-0.5) + w2*=2 + w1= 1-w2 + new_loc_smart= v1co*w1 + smart_offset_loc*w2 + else: # w between v2 and smart_offset_loc + w1*=2 + w2= 1-w1 + new_loc_smart= v2co*w2 + smart_offset_loc*w1 + + if new_loc_smart.x != new_loc_smart.x: # NAN LOCATION, revert to between + new_loc_smart= None + + return new_loc_smart, between, v1co*0.99999 + v2co*0.00001, v1co*0.00001 + v2co*0.99999 + class collapseFace(object): __slots__ = 'verts', 'normal', 'area', 'index', 'orig_uv', 'orig_col', 'uv', 'col' # , 'collapse_edge_count' @@ -329,144 +391,106 @@ def redux(ob, REDUX=0.5, BOUNDRY_WEIGHT=2.0, REMOVE_DOUBLES=False, FACE_AREA_WEI vert_collapsed= [1] * len(verts) - def ed_set_collapse_loc(ced): - v1co= ced.v1.co - v2co= ced.v2.co - v1no= ced.v1.no - v2no= ced.v2.no - - # Basic operation, works fine but not as good as predicting the best place. - #between= ((v1co*w1) + (v2co*w2)) - #ced.collapse_loc= between - - # Use the vertex weights to bias the new location. - w1= vert_weights[ced.key[0]] - w2= vert_weights[ced.key[1]] - - # normalize the weights of each vert - se we can use them as scalers. - wscale= w1+w2 - if not wscale: # no scale? - w1=w2= 0.5 - else: - w1/=wscale - w2/=wscale - - length= ced.length - between= (v1co+v2co) * 0.5 - - # Collapse - # new_location = between # Replace tricky code below. this code predicts the best collapse location. - - # Make lines at right angles to the normals- these 2 lines will intersect and be - # the point of collapsing. - - # Enlarge so we know they intersect: ced.length*2 - cv1= CrossVecs(v1no, CrossVecs(v1no, v1co-v2co)) - cv2= CrossVecs(v2no, CrossVecs(v2no, v2co-v1co)) - - # Scale to be less then the edge lengths. - cv1.normalize() - cv2.normalize() - cv1 = cv1 * (length* 0.4) - cv2 = cv2 * (length* 0.4) - - smart_offset_loc= between + (cv1 + cv2) - - - if (smart_offset_loc-between).length > length/2: - # New collapse loc is way out, just use midpoint. - ced.collapse_loc= between - else: - # Now we need to blend between smart_offset_loc and w1/w2 - # you see were blending between a vert and the edges midpoint, so we cant use a normal weighted blend. - if w1 > 0.5: # between v1 and smart_offset_loc - #ced.collapse_loc= v1co*(w2+0.5) + smart_offset_loc*(w1-0.5) - w2*=2 - w1= 1-w2 - - - ced.collapse_loc= v1co*w1 + smart_offset_loc*w2 - else: # w between v2 and smart_offset_loc - w1*=2 - w2= 1-w1 - ced.collapse_loc= v2co*w2 + smart_offset_loc*w1 - - if ced.collapse_loc.x != ced.collapse_loc.x: # NAN LOCATION, revert to between - ced.collapse_loc= between # Best method, no quick hacks here, Correction. Should be the best but needs tweaks. def ed_set_collapse_error(ced): - i1, i2= ced.key + # Use the vertex weights to bias the new location. + new_locs= ced.collapse_locations(vert_weights[ced.key[0]], vert_weights[ced.key[1]]) + + # Find the connecting faces of the 2 verts. + i1, i2= ced.key test_faces= set() for i in (i1,i2): # faster then LC's for f in vert_face_users[i]: test_faces.add(f[1].index) - for f in ced.faces: test_faces.remove(f.index) - # test_faces= tuple(test_faces) # keep order v1_orig= Vector(ced.v1.co) v2_orig= Vector(ced.v2.co) - ced.v1.co= ced.v2.co= ced.collapse_loc - - new_nos= [faces[i].no for i in test_faces] - - ced.v1.co= v1_orig - ced.v2.co= v2_orig + def test_loc(new_loc): + ''' + Takes a location and tests the error without changing anything + ''' + new_weight= ced.collapse_weight + ced.v1.co= ced.v2.co= new_loc + + new_nos= [faces[i].no for i in test_faces] + + # So we can compare the befire and after normals + ced.v1.co= v1_orig + ced.v2.co= v2_orig + + # now see how bad the normals are effected + angle_diff= 1.0 + + for ii, i in enumerate(test_faces): # local face index, global face index + cfa= collapse_faces[i] # this collapse face + try: + # can use perim, but area looks better. + if FACE_AREA_WEIGHT: + # Psudo code for wrighting + # angle_diff= The before and after angle difference between the collapsed and un-collapsed face. + # ... devide by 180 so the value will be between 0 and 1.0 + # ... add 1 so we can use it as a multiplyer and not make the area have no eefect (below) + # area_weight= The faces original area * the area weight + # ... add 1.0 so a small area face dosent make the angle_diff have no effect. + # + # Now multiply - (angle_diff * area_weight) + # ... The weight will be a minimum of 1.0 - we need to subtract this so more faces done give the collapse an uneven weighting. + + angle_diff+= ((1+(Ang(cfa.normal, new_nos[ii])/180)) * (1+(cfa.area * FACE_AREA_WEIGHT))) -1 # 4 is how much to influence area + else: + angle_diff+= (Ang(cfa.normal), new_nos[ii])/180 + + except: + pass + + + # This is very arbirary, feel free to modify + try: no_ang= (Ang(ced.v1.no, ced.v2.no)/180) + 1 + except: no_ang= 2.0 + + # do *= because we face the boundry weight to initialize the weight. 1.0 default. + new_weight *= ((no_ang * ced.length) * (1-(1/angle_diff)))# / max(len(test_faces), 1) + return new_weight + # End testloc - # now see how bad the normals are effected - angle_diff= 1.0 - for ii, i in enumerate(test_faces): # local face index, global face index - cfa= collapse_faces[i] # this collapse face - try: - # can use perim, but area looks better. - if FACE_AREA_WEIGHT: - # Psudo code for wrighting - # angle_diff= The before and after angle difference between the collapsed and un-collapsed face. - # ... devide by 180 so the value will be between 0 and 1.0 - # ... add 1 so we can use it as a multiplyer and not make the area have no eefect (below) - # area_weight= The faces original area * the area weight - # ... add 1.0 so a small area face dosent make the angle_diff have no effect. - # - # Now multiply - (angle_diff * area_weight) - # ... The weight will be a minimum of 1.0 - we need to subtract this so more faces done give the collapse an uneven weighting. - - angle_diff+= ((1+(Ang(cfa.normal, new_nos[ii])/180)) * (1+(cfa.area * FACE_AREA_WEIGHT))) -1 # 4 is how much to influence area - else: - angle_diff+= (Ang(cfa.normal), new_nos[ii])/180 - - except: - pass + # Test the collapse locatons + collapse_loc_best= None + collapse_weight_best= 1000000000 + ii= 0 + for collapse_loc in new_locs: + if collapse_loc: # will only ever fail if smart loc is NAN + test_weight= test_loc(collapse_loc) + if test_weight < collapse_weight_best: + iii= ii + collapse_weight_best = test_weight + collapse_loc_best= collapse_loc + ii+=1 - # This is very arbirary, feel free to modify - try: no_ang= (Ang(ced.v1.no, ced.v2.no)/180) + 1 - except: no_ang= 2.0 - - # do *= because we face the boundry weight to initialize the weight. 1.0 default. - ced.collapse_weight*= ((no_ang * ced.length) * (1-(1/angle_diff)))# / max(len(test_faces), 1) + ced.collapse_loc= collapse_loc_best + ced.collapse_weight= collapse_weight_best # are we using a weight map if VGROUP_INF_REDUX: v= vert_weights_map[i1]+vert_weights_map[i2] ced.collapse_weight*= v - + # End collapse Error # We can calculate the weights on __init__ but this is higher qualuity. for ced in collapse_edges: if ced.faces: # dont collapse faceless edges. - ed_set_collapse_loc(ced) ed_set_collapse_error(ced) # Wont use the function again. del ed_set_collapse_error - del ed_set_collapse_loc # END BOUNDRY. Can remove # sort by collapse weight diff --git a/release/scripts/mesh_poly_reduce.py b/release/scripts/mesh_poly_reduce.py index af965f4b6a5..de84ec6b300 100644 --- a/release/scripts/mesh_poly_reduce.py +++ b/release/scripts/mesh_poly_reduce.py @@ -16,6 +16,7 @@ This script simplifies the mesh by removing faces, keeping the overall shape of from Blender import Draw, Window, Scene, Mesh, Mathutils, sys, Object import BPyMesh +reload(BPyMesh) # ***** BEGIN GPL LICENSE BLOCK ***** # |