Пример #1
0
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
Пример #2
0
 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
Пример #3
0
 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
Пример #4
0
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