Remove doubles selectively

Scripting in Blender with Python, and working on the API

Moderators: jesterKing, stiv

Post Reply
Mirkosahedron
Posts: 0
Joined: Tue Jun 18, 2013 8:44 am

Remove doubles selectively

Post by Mirkosahedron » Tue Jun 18, 2013 9:06 am

Hi there!

I am new to both Blender and Python but it shows great potential to become my new favourite mesh scripting tool after having tried MATLAB and c++.

I have created a mesh like described here:
http://wiki.blender.org/index.php/Doc:2 ... n/Geometry

Except my mesh is created algorithmically by nested for loops. Because I am too lazy to wrack my brain over shared vertices, I create 3 vertices per triangle and afterwards I want to let Blender do the work.

I have found different solutions on the internet using remove_doubles(threshold), but they didn't work for me so far. Mainly because of my noobness in Python I assume. I am using blender 2.66a. It would be great if someone could provide an example on how to integrate such thing into the pyramid example from the link above, although it wouldn't have any effect there.

Also, it would be great if not all doubles were removed but only those that are not part of an edge with an edge angle below a limit that I can specify. That way, I can prevent sharp edges (that should remain sharp) from being smoothened by goraud shading.

Kind regards,
Mirko

CoDEmanX
Posts: 0
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Post by CoDEmanX » Tue Jun 18, 2013 10:21 am

add this to the bottom of the script:

Code: Select all

# Make the new object active / the only selected
bpy.ops.object.select_all(action='DESELECT')
ob.select = True
bpy.context.scene.objects.active = ob

# go to editmode and apply remove doubles
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.remove_doubles(threshold=0.01, use_unselected=False)
you can use the use_unselected option if you want. And keep in mind that remove doubles is a mesh operator, it works with the active mesh in editmode. It takes selection into account!

If you don't want a smooth shading, add this to the bottom of the script:

Code: Select all

# go back to object mode and change shading
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.shade_flat()
I'm sitting, waiting, wishing, building Blender in superstition...

Mirkosahedron
Posts: 0
Joined: Tue Jun 18, 2013 8:44 am

Post by Mirkosahedron » Tue Jun 18, 2013 10:58 am

Hi!

Thanks for your answer, I will try that when I am at home.

In general I want smooth shading, exept at sharp edges. Imagine a cylinder. It should look like the left one in this image:

Image

The curved part looks smooth but the edges around the caps are smooth. If I remove all doubles and apply gouraud shading, the sharp edges will look like the ones in this image:

http://www.cs.berkeley.edu/~ug/slide/do ... ouraud.gif

which is not what I want.

So, depending on the edge angle I either want to keep double vertices (for edges) or I want to join them (for smooth parts). It would be cool if this can be done by blender, otherwise I will do it manually.

Mirkosahedron
Posts: 0
Joined: Tue Jun 18, 2013 8:44 am

Post by Mirkosahedron » Tue Jun 18, 2013 11:01 am

Sorry!

Here the link to the first image:

https://encrypted-tbn3.gstatic.com/imag ... 3jYQI8Ffur

And of course I wanted to say
The curved part looks smooth but the edges around the caps are sharp.

Mirkosahedron
Posts: 0
Joined: Tue Jun 18, 2013 8:44 am

Post by Mirkosahedron » Tue Jun 18, 2013 9:33 pm

Hi!

So it worked in the pyramid case. But with a more complicated model, blender just crashed.

Code: Select all

import bpy
import math
from math import pow,sin,cos

PI=3.141592654

N_OUTER=24
N_INNER=24
R_OUTER=1.0
R_INNER=0.275

t=0.0
p=0.0
dt=2.0*PI/N_OUTER
dp=2.0*PI/N_INNER
nv=0

vertices=[]
faces=[]

for ip in range(N_INNER):
	p=ip*dp;

	for it in range(N_OUTER):
		t=it*dt + 0.5*ip*dt

		vt=[t, t+dt, t+0.5*dt, t+dt+0.5*dt]
		vp=[p, p, p+dp, p+dp]

		for iv in range(4):
		
			x = (R_OUTER + R_INNER*cos(vp[iv]))*cos(vt[iv]);
			y =            R_INNER*sin(vp[iv]);
			z = (R_OUTER + R_INNER*cos(vp[iv]))*sin(vt[iv]);

			# Define the coordinates of the vertices. Each vertex is defined by 3 consecutive floats.
			vertices.append((x,y,z))
			
		# Define the faces by index numbers. Each faces is defined by 4 consecutive integers.
		# For triangles you need to repeat the first vertex also in the fourth position.			
		faces.append((nv,nv+2,nv+1,nv))
		faces.append((nv+1,nv+2,nv+3,nv+1))
		nv=nv+4


me = bpy.data.meshes.new("torusMesh")   # create a new mesh  

ob = bpy.data.objects.new("torus", me)          # create an object with that mesh
bpy.context.scene.objects.link(ob)                # Link object to scene

# Fill the mesh with verts, edges, faces 
me.from_pydata(vertices,[],faces)   # edges or faces should be [], or you ask for problems
me.update(calc_edges=True)    # Update mesh with new data


# Make the new object active / the only selected
bpy.ops.object.select_all(action='DESELECT')
ob.select = True
bpy.context.scene.objects.active = ob

# go to editmode and apply remove doubles
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.remove_doubles(threshold=0.01, use_unselected=False)

Everything works as expected if I comment the last line. Before, it also worked with N_INNER and N_OUTER being set to 6. Now it always crashes although I didn't change a thing.

CoDEmanX
Posts: 0
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Post by CoDEmanX » Fri Jun 21, 2013 12:53 am

above me.update(...), add

me.validate()

that should help...
I'm sitting, waiting, wishing, building Blender in superstition...

Mirkosahedron
Posts: 0
Joined: Tue Jun 18, 2013 8:44 am

Post by Mirkosahedron » Fri Jun 21, 2013 9:21 pm

Thanks! Now it does no longer crash.
Also, the redundant vertices are merged (because all adjacent edges move when I move a vertex).
However, the faces are gone and an empty skeleton remains...

CoDEmanX
Posts: 0
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Post by CoDEmanX » Fri Jun 21, 2013 10:05 pm

validate() probably removes verts in identical locations... that is a problem.

you should try the bmesh module to create the geometry, it seems to handle this nicer.

http://www.blender.org/documentation/bl ... bmesh.html

basic example:

Code: Select all

import bpy
import bmesh

bm = bmesh.new()

bm.verts.new((1,2,3)) # co
bm.verts.new((1,2,3))
bm.verts.new((1,2,2))
bm.verts.new((-1,2,3))
bm.verts.new((-1,2,3))

bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.1)

bm.faces.new(bm.verts) # create a single face from all remaining verts

me = bpy.data.meshes.new("")
bm.to_mesh(me)

ob = bpy.data.objects.new("", me)
bpy.context.scene.objects.link(ob)
bpy.context.scene.update()
I'm sitting, waiting, wishing, building Blender in superstition...

Post Reply