Shrinkwrap (almost)

I wanted to make a script to shrinkwrap one mesh around another … but I need to try to do it another way, because this method causes some of the vertices to not move.

Basically, a ray is cast from a vertices in the inverse direction of the normal, and then the vertices is moved to the closest point where the ray intersects one of the triangles. A better way would be to find the shortest distance from a point to a triangle, and then move the vertice onto the triangle. I don’t think I am explaining it very well … oh well.

To use this, first select the mesh to shrink around, then also select the mesh that would be doing the shrinking. Then run the script. A Better version may come about later.

The idea was to allow people to focus on shapes and proportions, without having to worry about vertice placement, then afterwards work on better verice placement. I found that this was rather hard to do with this script, because rays cast from some of the vertices do not intersect with any triangles (the inverse of the normal points slightly off). Maybe somebody might find it interesting though.

# shrink-wrap     - Nov. 7, 2004
# Created by: Nathan Moore
# Ray Triangle Intersection found at: http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf

import Blender

print "
########## Shrink-Wrap ##########"

shrinkObj = Blender.Object.GetSelected()[0]
wrapObj = Blender.Object.GetSelected()[1]

shrinkMesh = Blender.NMesh.GetRaw(shrinkObj.data.name)

epsilon = 0.000001

def cross(v1,v2):
	dest = []
	dest.append(v1[1]*v2[2]-v1[2]*v2[1])
	dest.append(v1[2]*v2[0]-v1[0]*v2[2])
	dest.append(v1[0]*v2[1]-v1[1]*v2[0])
	return dest

def dot(v1,v2):
	return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]

def sub(v1,v2):
	dest = []
	dest.append(v1[0]-v2[0])
	dest.append(v1[1]-v2[1])
	dest.append(v1[2]-v2[2])
	return dest

def intersectTriangle(orig, dir, v0, v1, v2):
	edge1 = []
	edge2 = []
	tvec = []
	qvec = []

	edge1 = sub(v1,v0)
	edge2 = sub(v2,v0)

	pvec = cross(dir, edge2)

	det = dot(edge1, pvec)

	if det<epsilon:
		return 0

	tvec = sub(orig, v0)

	u = dot(tvec, pvec)
	if (u<0.0 or u>det):
		return 0

	qvec = cross(tvec, edge1)
	v = dot(dir, qvec)
	if(v<0.0 or u+v>det):
		return 0

	t = dot(edge2, qvec)
	inv_det = 1.0/det
	t = t * inv_det
	u = u * inv_det
	v = v * inv_det

	r = []
	r.append(t)
	r.append(u)
	r.append(v)
	return r

def shrinkwrap():
	global shrinkMesh, wrapObj, shrinkObj
	c=0	
	for v in shrinkMesh.verts:
		d = 500000.0
		ntmp = [-v.no[0], -v.no[1], -v.no[2]]

		for f in wrapObj.getData().faces:
			tmp = intersectTriangle(v.co, ntmp, f.v[0], f.v[1], f.v[2])
			if tmp != 0:
				if tmp[0]<d:
					d = tmp[0]
			if len(f.v) > 3:
				tmp = intersectTriangle(v.co, ntmp, f.v[0], f.v[2], f.v[3])
				if tmp != 0:
					if tmp[0]<d:
						d = tmp[0]
		if d != 500000.0:
			shrinkMesh.verts[v.index].co[0] = v.co[0]+ntmp[0]*d
			shrinkMesh.verts[v.index].co[1] = v.co[1]+ntmp[1]*d
			shrinkMesh.verts[v.index].co[2] = v.co[2]+ntmp[2]*d
		c = c+1
		print c,"/",len(shrinkMesh.verts)
	shrinkMesh.update(1)

shrinkwrap()

print "done"

Not sure if this is in the right section, but oh well.

Could we see some screens of the script in action?

works in theory, but the newly created mexh is rotated incorrectly to match the original inner mesh.

nice idea though

Oops. I thought I was in the Python scripting forum!

As for the rotation, the object orientation is not taken into account when moving the vertices. If the rotation, size, and location of both meshes are set to 0 rotation on all axises, 1 size on all axises, and 0 location on all axises, then the finished result would somewhat wrap. The best looking example I the script in action is to wrap a high poly count sphere around a cube.

I am trying to come up with a better way of shrinkwrapping objects, but I keep running into problems with each of my ideas. I don’t have the time to try to explain some of my ideas, and the problems that result from these ideas, at the moment, though.

Hmmm interesting idea, I’ve been thinking of doing the same thing but just for parts of the mesh not using two complete meshs.

basically I want to do morph targets, but mold the target on a seperate mesh.(Ie turn part of makehuman into horse or dog form by using animal meshes…).

I’ll have a look at your code later…

LetterRip

What I was planning to do, was calculate the spherical coordinates of the verts of the first mesh, then calculate the spehrical coordinates of the second mesh (absed on the first meshes center) and use that for determining vertice correspondence.

LetterRip

Here is an example of a sphere shrinkwrapped around a cube:
http://www.geocities.com/cheesesquid/shrinkwrap.gif

Spent a few hours with it and it’s a gas! Even works with 3 objects. But like you say… almost.

Could you use this code to somehow have an object, a part of an object or a vert group conform to the shape of a second object? Many people have asked for this and I must admit it would be cool.

%<