def qdome2d(vertices, base, normal, precision=0.0001): """Build a convex dome from C{vertices} on top of the two C{base} vertices, in the plane with normal C{normal}. This is a helper function for L{qhull2d}, and should usually not be called directly. :param vertices: The vertices to construct the dome from. :param base: Two vertices that serve as a base for the dome. :param normal: Orientation of the projection plane used for calculating distances. :param precision: Distance used to decide whether points lie outside of the hull or not. :return: A list of vertices that make up a fan of the dome.""" vert0, vert1 = base outer = [(dist, vert) for dist, vert in zip((mathutils.vecDotProduct( mathutils.vecCrossProduct(normal, mathutils.vecSub(vert1, vert0)), mathutils.vecSub(vert, vert0)) for vert in vertices), vertices) if dist > precision] if outer: pivot = max(outer)[1] outer_verts = list(map(operator.itemgetter(1), outer)) return qdome2d(outer_verts, [vert0, pivot], normal, precision) + qdome2d( outer_verts, [pivot, vert1], normal, precision)[1:] else: return base
def ComputeCost(self, v): edgelength = 1.0 if self.parent.Settings.UseEdgelength: length = vecSub(v.Vert.Position, self.Vert.Position) edgelength = vecNorm(length) if (len(self.Neighbors) == len(v.Neighbors)): same_neighbors = True for neighbor in self.Neighbors: if neighbor == v: continue if not v.IsNeighbor(neighbor): same_neighbors = False break if same_neighbors: # raw_input("ERROR: ComputeCost() same neighbors detected.") return 999999.9 curvature = 0.001 sides = list() for f in self.Faces: if v.IsFace(f): sides.append(f) if self.parent.Settings.UseCurvature: for f in self.Faces: mincurv = 1.0 for s in sides: dotproduct = vecDotProduct(f.normal, s.normal) mincurv = min([mincurv, (1.002 - dotproduct) / 2.0]) curvature = max([curvature, mincurv]) if self.IsBorder(): WEIGHT_BORDER = 100 curvature = curvature * WEIGHT_BORDER if self.parent.Settings.ProtectTexture: if not self.IsSameUV(v): WEIGHT_UV = 1.5 curvature = curvature * WEIGHT_UV if self.parent.Settings.KeepBorder and self.IsBorder(): # raw_input("KEEP BORDER activated, Press ENTER to Continue.") curvature = 999999.9 cost = edgelength * curvature # print "DEBUG: ComputeCost() v[%d] to v[%d], c=%f" % (self.ID, v.ID, cost) return cost
def ComputeNormal(self): # v = [[], [], []] v0 = self.vertex[0].Vert.Position v1 = self.vertex[1].Vert.Position v2 = self.vertex[2].Vert.Position # v.append(self.vertex[0].Vert.Position) # v.append(self.vertex[1].Vert.Position) # v.append(self.vertex[2].Vert.Position) # a = vecSub(v[1], v[0]) # b = vecSub(v[2], v[0]) a = vecSub(v1, v0) b = vecSub(v2, v0) _normal = self.normal self.normal = vecCrossProduct(a, b) if vecNorm(self.normal) < 0.001: return self.normal = vecNormalized(self.normal) length = vecDotProduct(self.normal, _normal) if length < 0: self.normal = vecscalarMul(self.normal, -1) return
def getTangentSpace(vertices=None, normals=None, uvs=None, triangles=None, orientation=False, orthogonal=True): """Calculate tangent space data. >>> vertices = [(0,0,0), (0,1,0), (1,0,0)] >>> normals = [(0,0,1), (0,0,1), (0,0,1)] >>> uvs = [(0,0), (0,1), (1,0)] >>> triangles = [(0,1,2)] >>> getTangentSpace(vertices = vertices, normals = normals, uvs = uvs, triangles = triangles) ([(0.0, 1.0, 0.0), (0.0, 1.0, 0.0), (0.0, 1.0, 0.0)], [(1.0, 0.0, 0.0), (1.0, 0.0, 0.0), (1.0, 0.0, 0.0)]) :param vertices: A list of vertices (triples of floats/ints). :param normals: A list of normals (triples of floats/ints). :param uvs: A list of uvs (pairs of floats/ints). :param triangles: A list of triangle indices (triples of ints). :param orientation: Set to ``True`` to return orientation (this is used by for instance Crysis). :return: Two lists of vectors, tangents and binormals. If C{orientation} is ``True``, then returns an extra list with orientations (containing floats which describe the total signed surface of all faces sharing the particular vertex). """ # validate input if len(vertices) != len(normals) or len(vertices) != len(uvs): raise ValueError( "lists of vertices, normals, and uvs must have the same length") bin_norm = [(0, 0, 0) for i in range(len(vertices))] tan_norm = [(0, 0, 0) for i in range(len(vertices))] orientations = [0 for i in range(len(vertices))] # calculate tangents and binormals from vertex and texture coordinates for t1, t2, t3 in triangles: # skip degenerate triangles if t1 == t2 or t2 == t3 or t3 == t1: continue # get vertices, uvs, and directions of the triangle v1 = vertices[t1] v2 = vertices[t2] v3 = vertices[t3] w1 = uvs[t1] w2 = uvs[t2] w3 = uvs[t3] v2v1 = mathutils.vecSub(v2, v1) v3v1 = mathutils.vecSub(v3, v1) w2w1 = mathutils.vecSub(w2, w1) w3w1 = mathutils.vecSub(w3, w1) # surface of triangle in texture space r = w2w1[0] * w3w1[1] - w3w1[0] * w2w1[1] # sign of surface r_sign = (1 if r >= 0 else -1) # contribution of this triangle to tangents and binormals sdir = (r_sign * (w3w1[1] * v2v1[0] - w2w1[1] * v3v1[0]), r_sign * (w3w1[1] * v2v1[1] - w2w1[1] * v3v1[1]), r_sign * (w3w1[1] * v2v1[2] - w2w1[1] * v3v1[2])) try: sdir = mathutils.vecNormalized(sdir) except ZeroDivisionError: # catches zero vector continue # skip triangle except ValueError: # catches invalid data continue # skip triangle tdir = (r_sign * (w2w1[0] * v3v1[0] - w3w1[0] * v2v1[0]), r_sign * (w2w1[0] * v3v1[1] - w3w1[0] * v2v1[1]), r_sign * (w2w1[0] * v3v1[2] - w3w1[0] * v2v1[2])) try: tdir = mathutils.vecNormalized(tdir) except ZeroDivisionError: # catches zero vector continue # skip triangle except ValueError: # catches invalid data continue # skip triangle # vector combination algorithm could possibly be improved for i in (t1, t2, t3): tan_norm[i] = mathutils.vecAdd(tan_norm[i], tdir) bin_norm[i] = mathutils.vecAdd(bin_norm[i], sdir) orientations[i] += r # convert into orthogonal space xvec = (1, 0, 0) yvec = (0, 1, 0) for i, norm in enumerate(normals): if abs(1 - mathutils.vecNorm(norm)) > 0.01: raise ValueError( "tangentspace: unnormalized normal in list of normals (%s, norm is %f)" % (norm, mathutils.vecNorm(norm))) try: # turn norm, bin_norm, tan_norm into a base via Gram-Schmidt bin_norm[i] = mathutils.vecSub( bin_norm[i], mathutils.vecscalarMul( norm, mathutils.vecDotProduct(norm, bin_norm[i]))) bin_norm[i] = mathutils.vecNormalized(bin_norm[i]) tan_norm[i] = mathutils.vecSub( tan_norm[i], mathutils.vecscalarMul( norm, mathutils.vecDotProduct(norm, tan_norm[i]))) tan_norm[i] = mathutils.vecSub( tan_norm[i], mathutils.vecscalarMul( bin_norm[i], mathutils.vecDotProduct(norm, bin_norm[i]))) tan_norm[i] = mathutils.vecNormalized(tan_norm[i]) except ZeroDivisionError: # insuffient data to set tangent space for this vertex # in that case pick a space bin_norm[i] = mathutils.vecCrossProduct(xvec, norm) try: bin_norm[i] = mathutils.vecNormalized(bin_norm[i]) except ZeroDivisionError: bin_norm[i] = mathutils.vecCrossProduct(yvec, norm) bin_norm[i] = mathutils.vecNormalized(bin_norm[i]) tan_norm[i] = mathutils.vecCrossProduct(norm, bin_norm[i]) # return result if orientation: return tan_norm, bin_norm, orientations else: return tan_norm, bin_norm