[Addon] Mesh curvature to vertex colors

Hey Ambi,

Thanks for posting the revised version. I finally got around to trying it out and got some interesting results.


I have to be missing a step here LOL!

  1. After I open Blender, I create a mesh Shift+A -> Mesh -> Add Monkey

  2. Then I apply a Subdivide modifier (level 4) and apply

  3. Then I run the add-on from the spacebar menu and I see the Curvature to vertex colors menu and can change values etc.

  4. Then, when I switch the view from solid object mode to vertex paint mode, I get the above image, which I suppose, is not right.

What could possibly be the problem?

thanks

@2tancommon: Yes, you’re still using the old version. That’s the exact behavior that it had. Go to addons, remove the “Curvature to vertex colors” then download https://raw.githubusercontent.com/amb/blender-scripts/master/mesh_curves.py and install it.

Also how to use the “Curvature” vertex color data with Cycles, just add an “Attribute” node with the name “Curvature”.

edit: Looks like the alpha is actually working, setting it to zero makes the whole object disappear! :spin:
So that’s something I need to fix.
edit2: Should be ok now.

Thanks!

It’s a little better but I am still getting this:


I’ve removed the older version and downloaded the 2nd edit and tried the steps again.

the addon menu shows up but every time I switch to vertex paint mode, I get this tiling

Ok, thank you for informing me. I got to test it on another machine with a fresh install of Blender. Can’t figure out what’s going wrong there.

edit: Ok, I reproduced your problem. Seems I’m using a Github version that has the 4 element RGBA. Even the newest Blender 2.79 is still using just 3 element RGB.

So your version on your machine is working without any errors?

I was testing on a custom build that was causing the confusion. I’m now using the latest 2.79 from blender.org and I’m having the exact same problem as you. It’s because the data structures for vertex colors have changed in some builds. The old script (for current 2.79) is available at https://raw.githubusercontent.com/amb/blender-scripts/64a960c9b5fc4a960879eff411379d9dc7a696ac/mesh_curves.py which seems to work right.

It works for me also!!

Thanks again!!

I should have specified that I was using the latest official 2.79 build from blender.org.

Added smoothing functionality. Currently developing on the dev branch, don’t know if the vertex color update from RGB to RGBA has yet been implemented in 2.79a. So might have to download a dev build to test out this.

It’s really necessary for big and/or jagged meshes. Here’s a 500k face object with 0 smoothing, and then with 20 smoothing.


1 Like

If you’re getting all black vertex colors from the script do the following: 1. Remove doubles, 2. Delete loose

Spent way too much time in trying to debug what was in the end just a broken mesh. :spin:

Nice work man !

thanks for sharing we’d like to work on Curvature too in scatter but with weight painting we’d definitely looking to convert your script but for weight paint

in the meanwhile we did some really simple fct that may interest some of the readers
it simply reads edge sharpness value with a multiplier

def create_sharpness_data(vg_name, factor=1):
    """simple sharpness"""
    o = bpy.context.object
    ob = o.data

    bm = bmesh.new()
    bm.from_mesh(ob)
    bm.verts.ensure_lookup_table()

    values=[v.calc_shell_factor()-1 for v in bm.verts]
    bm.free()

    if vg_name not in o.vertex_groups:
          vg = o.vertex_groups.new(name=vg_name)
    else: vg = o.vertex_groups[vg_name]

    for i,v in enumerate(values):
        vg.add([i], v*factor, 'REPLACE')

If you don’t care about cotan weights and just want something simple, doing somthing like this is feasible:https://github.com/amb/bpy_amb/blob/7f29bcbcce9c6c6a5eecaedf1d10219272ce9172/fastmesh.py#L296

It can process any vertex bound data and you just need to input the edges https://github.com/amb/bpy_amb/blob/7f29bcbcce9c6c6a5eecaedf1d10219272ce9172/fastmesh.py#L90 and your data indexed by vertices.

I also have a plug-and-play function that takes some data and smoothes it over the mesh https://github.com/amb/bpy_amb/blob/7f29bcbcce9c6c6a5eecaedf1d10219272ce9172/fastmesh.py#L230

You can find examples how to use those here.

The stuff in this thread is pretty old (IIRC)

edit: looks like you want the curvature, it’s here: https://github.com/amb/bpy_amb/blob/7f29bcbcce9c6c6a5eecaedf1d10219272ce9172/fastmesh.py#L168 it doesn’t save vertex colors but gives vertex index matched values in a numpy array, so you can just directly save it to weight data.

1 Like

thanks @ambi , I’ll look at your library asap ! amazing work btw
curious to compare performance, i already got some great results with numpy before

in the meanwhile i did my own (more simple) fct, it just loop over bmesh edges look for angle and loop over verts again :zipper_mouth_face:

wanted to optimize it with numpy but it seem that bmesh don’t get foreach_get API (still learning)


def eval_percentage(maxi, mini, nbr):
    """get weight value proportional to min and max"""
    zone = (maxi-mini)
    if zone==0:
        return 1.0
    r = (nbr-mini)/zone
    return r

def create_curvature_data(vg_name, crop_max=1.0, mode='concave'):
    """create curvature data weight group, mode arg in ( 'concave','convex','both','curvature')"""
    o = bpy.context.object
    bm = bmesh.new()
    bm.from_mesh(o.data)
    bm.edges.ensure_lookup_table()
    bm.verts.ensure_lookup_table()

    #get all angle (and index by order)
    angl = [e.calc_face_angle_signed(0.0) for e in bm.edges]
        
    #find min and max values
    mini = min(angl)/crop_max
    maxi = max(angl)/crop_max

    #curvature mode need 0.5 as flat, cannot take raw min/max
    if mode=='curvature': 
        maxv = abs(mini) if (abs(mini)>abs(maxi)) else abs(maxi)

    v_dict={}
    #loop over dict, don't calculate all over angle again...
    for i,v in enumerate(angl):
        
        #evaluate values from min and max
        if mode=='curvature':
            val = eval_percentage( maxv, -maxv, v)
        elif mode=='convex':
            val = eval_percentage( maxi, 0, v)
        elif mode=='concave':
            val = 1-eval_percentage( 0, mini, v)
        elif mode=='both':
            val = eval_percentage( maxi, 0, abs(v))

        for v in bm.edges[i].verts:
            #if value already exist in dict, round both
            if v.index in v_dict:
                #if curvature, do average
                if mode=='curvature':
                    old_val=v_dict[v.index]
                    del v_dict[v.index]
                    v_dict[v.index]= (val+old_val)/2  #average = create weird artifact ???
                    continue
                #else only take max value
                else:
                    if v_dict[v.index]<val:
                        del v_dict[v.index]
                    else:
                        continue
            v_dict[v.index]=val

    bm.free()

    if vg_name not in o.vertex_groups:
          vg = o.vertex_groups.new(name=vg_name)
    else: vg = o.vertex_groups[vg_name]

    for i,v in v_dict.items():
        vg.add([i], v, 'REPLACE')

    return 

Reading the Bmesh data to Numpy array is probably fast enough for pretty much anything. The algorithm itself can then be 100% done with Numpy, which makes that part a lot faster. https://github.com/amb/bpy_amb/blob/7f29bcbcce9c6c6a5eecaedf1d10219272ce9172/fastmesh.py#L83

The smoothing function is probably what would give you the most value, as with angle calculation you will only get a very rough approximation of the surface curvature. With smoothing you can have many different types of appearances.

1 Like