Пример #1
0
    def __init__(self, location, normal, face_index, distance, field):
        self.co = location
        face = field.bm.faces[face_index]
        verts = [vert.co for vert in face.verts]
        mask = [
            Vector((0, 0, field.mask.get(vert.index, 0)))
            for vert in field.bm.faces[face_index].verts
        ]
        normals = [vert.normal for vert in field.bm.faces[face_index].verts]
        self.normal = geometry.barycentric_transform(location, *verts,
                                                     *normals)
        self.mask = geometry.barycentric_transform(location, *verts, *mask).z
        try:
            co = face.verts[0]
            vec = field.vert_field[co.index].u
            vecs = [
                field.vert_field[vert.index].get_nearest_vec(vec)
                for vert in face.verts
            ]
            vec = geometry.barycentric_transform(location, *verts, *vecs)
        except KeyError:
            vec = Vector((random(), random(),
                          random())).cross(self.normal).normalized()
        self.frame = CrossFrame(vec, self.normal)

        self.face = face_index
Пример #2
0
    def sample_point(self, point, ref_dir=None):
        location, normal, index, distance = self.bvh.find_nearest(point)
        if location:
            face = self.bm.faces[index]
            face_verts_co = [vert.co for vert in face.verts]
            if not ref_dir:
                ref_dir = self.field[face.verts[0].index]

            field = [
                nmv.physics.best_matching_vector(
                    nmv.physics.symmetry_space(self.field[vert.index],
                                               vert.normal)
                    if not self.hex_mode else nmv.physics.hex_symmetry_space(
                        self.field[vert.index], vert.normal),
                    reference=ref_dir) for vert in face.verts
            ]

            dir = barycentric_transform(point, *face_verts_co, *field)
            scale_curv = [
                Vector((self.scale[vert.index], self.curvature[vert.index], 0))
                for vert in face.verts
            ]
            scale_curv = barycentric_transform(point, *face_verts_co,
                                               *scale_curv)
            scale = scale_curv[0]
            curv = scale_curv[1]
            dir -= normal * normal.dot(dir)
            dir.normalize()
            return location, normal, dir, scale, curv
        else:
            return None, None, None, None
Пример #3
0
def compute_intersect_circle_circle(params, result, gates):
    '''Compute two circles intersection(s)
    Result has to be [[],[],[]] to host the solutions
    Gates are as follow:
    0: Is there a intersection?
    1: First Intersection
    2: Second intersection
    3: The working plane is defined by its normal (True) or by a third point (False)'''
    center_a, radius_a, center_b, radius_b, plane_pt, plane_normal = params
    local_result = []
    sphere_loc_a = V(center_a)
    sphere_loc_b = V(center_b)
    if gates[3]:
        norm = V(plane_normal).normalized()
    else:
        v_in_plane = V(plane_pt)
        norm = normal([sphere_loc_a, sphere_loc_b, v_in_plane])
    if norm.length == 0:
        if gates[3]:
            print("Circle Intersection Error: the Normal can't be (0,0,0)")
        else:
            print("Circle Intersection Error: the point in plane is aligned with origins")

    is_2d = norm.x == 0 and norm.y == 0

    if is_2d and False:
        z_coord = sphere_loc_a.z
        inter_p = intersect_sphere_sphere_2d(sphere_loc_a.to_2d(), radius_a, sphere_loc_b.to_2d(), radius_b)
        if inter_p[0]:
            intersect = True
            vec1 = list(inter_p[1]) + [z_coord]
            vec0 = list(inter_p[0]) + [z_coord]
            local_result = [intersect, vec0, vec1]

    else:
        dist = (sphere_loc_a - sphere_loc_b).length
        new_a = V([0, 0, 0])
        new_b = V([dist, 0, 0])
        inter_p = intersect_sphere_sphere_2d(new_a.to_2d(), radius_a, new_b.to_2d(), radius_b)
        if inter_p[0]:
            intersect_num = True
            trird_point = sphere_loc_a + norm
            new_c = V([0, 0, 1])
            vec0 = barycentric_transform(inter_p[0].to_3d(), new_a, new_b, new_c, sphere_loc_a, sphere_loc_b, trird_point)
            vec1 = barycentric_transform(inter_p[1].to_3d(), new_a, new_b, new_c, sphere_loc_a, sphere_loc_b, trird_point)
            local_result = [intersect_num, list(vec0), list(vec1)]

    if not local_result:
        direc = (sphere_loc_b - sphere_loc_a).normalized()
        intersect_num = False
        vec0 = sphere_loc_a + direc * radius_a
        vec1 = sphere_loc_b - direc * radius_b
        local_result = [intersect_num, list(vec0), list(vec1)]

    for i, res in enumerate(result):
        if gates[i]:
            res.append(local_result[i])
Пример #4
0
 def process(self):
     Points = self.inputs[1]
     Colors = self.outputs[0]
     if Colors.is_linked:
         dps = get_sv_depsgraph()
         obj = self.inputs[0].sv_get()[0]  # triangulate faces
         bvh = BVHTree.FromObject(obj, dps)
         point = Points.sv_get()[0]
         outc = []
         ran = range(3)
         image = bpy.data.images[self.image]
         width, height = image.size  # Must be exactly the same vertically and horizontally, square image.
         pixels = np.array(image.pixels[:]).reshape(width, height, 4)
         uvMap = obj.data.uv_layers[0].data
         for P in point:
             loc, norm, ind, dist = bvh.find_nearest(P)
             found_poly = obj.data.polygons[ind]
             verticesIndices = found_poly.vertices
             p1, p2, p3 = [
                 obj.data.vertices[verticesIndices[i]].co for i in ran
             ]
             uvMapIndices = found_poly.loop_indices
             uv1, uv2, uv3 = [
                 uvMap[uvMapIndices[i]].uv.to_3d() for i in ran
             ]
             V = barycentric_transform(loc, p1, p2, p3, uv1, uv2, uv3)
             outc.append(pixels[int(V.y * (width - 1)),
                                int(V.x * (height - 1))].tolist())
         Colors.sv_set([outc])
Пример #5
0
 def process(self):
     Points = self.inputs[0]
     Colors = self.outputs[0]
     if Colors.is_linked:
         obj = bpy.data.objects[self.object_ref]  # triangulate faces
         bvh = BVHTree.FromObject(obj,
                                  bpy.context.scene,
                                  deform=True,
                                  render=False,
                                  cage=False,
                                  epsilon=0.0)
         point = Points.sv_get()[0]
         outc = []
         ran = range(3)
         image = bpy.data.images[self.image]
         width, height = image.size
         pixels = np.array(image.pixels[:]).reshape(width, height, 4)
         uvMap = obj.data.uv_layers[0].data
         for P in point:
             loc, norm, ind, dist = bvh.find_nearest(P)
             found_poly = obj.data.polygons[ind]
             verticesIndices = found_poly.vertices
             p1, p2, p3 = [
                 obj.data.vertices[verticesIndices[i]].co for i in ran
             ]
             uvMapIndices = found_poly.loop_indices
             uv1, uv2, uv3 = [
                 uvMap[uvMapIndices[i]].uv.to_3d() for i in ran
             ]
             V = barycentric_transform(loc, p1, p2, p3, uv1, uv2, uv3)
             outc.append(pixels[int(V.x * (width - 1)),
                                int(V.y * (height - 1))].tolist())
         Colors.sv_set([outc])
Пример #6
0
 def process(self):
     Object, PointsUV = self.inputs
     Pom, uvV, uvP = self.outputs
     obj = Object.sv_get()[0]  # triangulate faces
     UVMAPV, UVMAPP = UV(self, obj)
     if Pom.is_linked:
         pointuv = PointsUV.sv_get()[0]
         bvh = BVHTree.FromPolygons(UVMAPV,
                                    UVMAPP,
                                    all_triangles=False,
                                    epsilon=0.0)
         ran = range(3)
         out = []
         uvMap = obj.data.uv_layers[0].data
         for Puv in pointuv:
             loc, norm, ind, dist = bvh.find_nearest(Puv)
             found_poly = obj.data.polygons[ind]
             verticesIndices = found_poly.vertices
             p1, p2, p3 = [
                 obj.data.vertices[verticesIndices[i]].co for i in ran
             ]
             uvMapIndices = found_poly.loop_indices
             uv1, uv2, uv3 = [
                 uvMap[uvMapIndices[i]].uv.to_3d() for i in ran
             ]
             V = barycentric_transform(Puv, uv1, uv2, uv3, p1, p2, p3)
             out.append(V[:])
         Pom.sv_set([out])
     if uvV.is_linked:
         uvV.sv_set([UVMAPV])
         uvP.sv_set([UVMAPP])
Пример #7
0
 def process(self):
     Points, Colors = self.inputs
     obj = bpy.data.objects[self.object_ref]  # triangulate faces
     bvh = BVHTree.FromObject(obj,
                              bpy.context.scene,
                              deform=True,
                              render=False,
                              cage=False,
                              epsilon=0.0)
     point = Points.sv_get()[0]
     color = Colors.sv_get()[0]
     ran = range(3)
     image = bpy.data.images[self.image]
     width, height = image.size
     uvMap = obj.data.uv_layers[0].data
     pixels = np.array(image.pixels[:]).reshape(width, height, 4)
     for P, C in zip(point, safc(point, color)):
         loc, norm, ind, dist = bvh.find_nearest(P)
         found_poly = obj.data.polygons[ind]
         verticesIndices = found_poly.vertices
         p1, p2, p3 = [
             obj.data.vertices[verticesIndices[i]].co for i in ran
         ]
         uvMapIndices = found_poly.loop_indices
         uv1, uv2, uv3 = [uvMap[uvMapIndices[i]].uv.to_3d() for i in ran]
         V = barycentric_transform(loc, p1, p2, p3, uv1, uv2, uv3)
         Vx, Vy = int(V.x * (width - 1)), int(V.y * (height - 1))
         pixels[Vy, Vx] = C
     image.pixels = pixels.flatten().tolist()
Пример #8
0
    def __init__(self, location, normal, face_index, distance, field):
        self.co = location
        face = field.bm.faces[face_index]
        verts = [vert.co for vert in face.verts]
        normals = [vert.normal for vert in field.bm.faces[face_index].verts]
        curvature = [Vector((0, 0, field.mesh_curvature[vert.index])) for vert in field.bm.faces[face_index].verts]

        self.normal = geometry.barycentric_transform(location, *verts, *normals).normalized()
        self.curvature = geometry.barycentric_transform(location, *verts, *curvature).z

        co = face.verts[0]
        vec = field.vert_field[co.index].u
        vecs = [field.vert_field[vert.index].get_nearest_vec(vec) for vert in face.verts]
        vec = geometry.barycentric_transform(location, *verts, *vecs)
        self.frame = CrossFrame(vec, self.normal)

        self.face = face_index
Пример #9
0
    def __init__(self, location, normal, face_index, distance, field):
        self.co = location
        face = field.bm.faces[face_index]
        verts = [vert.co for vert in face.verts]
        curvature = [Vector((0, 0, field.mesh_curvature[vert.index])) for vert in field.bm.faces[face_index].verts]
        self.curvature_signed = geometry.barycentric_transform(location, *verts, *curvature).z
        self.curvature = max(self.curvature_signed, -self.curvature_signed)
        self.normal = normal
        try:
            co = face.verts[0]
            vec = field.vert_field[co.index].u
            vecs = [field.vert_field[vert.index].get_nearest_vec(vec) for vert in face.verts]
            vec = geometry.barycentric_transform(location, *verts, *vecs)
        except KeyError:
            vec = Vector((random(), random(), random())).cross(normal).normalized()
        self.frame = CrossFrame(vec, self.normal)

        self.face = face_index
Пример #10
0
 def interpolate_tri_2d(self, dst_vert_1, dst_vert_2, dst_vert_3, src_vert_1, src_vert_2, src_vert_3, v):
     """
     Map the provided `v` vertex, considering only two of it's coordinates,
     from the source triangle (defined by `src_vert_n` vertices) to the face defined by
     three `dst_vert_n` vertices.
     """
     X, Y = self.get_other_axes()
     v = self.from2d(v[X], v[Y])
     return barycentric_transform(v, src_vert_1, src_vert_2, src_vert_3,
                                     dst_vert_1, dst_vert_2, dst_vert_3)
Пример #11
0
def compute_barycentric_transform_mu(params, result):
    '''Port to MathUtils barycentric transform function'''

    tri_src = [V(v) for v in params[2]]
    tri_dest = [V(v) for v in params[3]]
    sub_result = []
    for vert in params[0]:
        point = V(vert)
        new_vert = barycentric_transform(point, tri_src[0], tri_src[1], tri_src[2], tri_dest[0], tri_dest[1], tri_dest[2])
        sub_result.append(list(new_vert))
    result.append(sub_result)
Пример #12
0
def get_color_from_geometry(obj, ray_origin, ray_direction, orig_scene=None, location=None, polygon_index=-1):
	global image_tuples
	
	#raycast, or use polygon_index and location if already available
	if not location or polygon_index == -1:
		if not orig_scene:
			dg = bpy.context.evaluated_depsgraph_get()
			orig_scene = bpy.context.scene.evaluated_get(dg)
		success, location, normal, polygon_index, object, matrix = orig_scene.ray_cast(bpy.context.view_layer, ray_origin, ray_direction, distance=0.002)
		if not success:
			return None
	
	# Find the UV map part corresponding to polygon_index
	slots = obj.material_slots
	material_index = obj.data.polygons[polygon_index].material_index
	# if no material exists
	if material_index >= len(slots) or material_index == -1:
		return [0.8, 0.8, 0.8]
	material = slots[obj.data.polygons[polygon_index].material_index].material
	image = get_material_image(material)
	# if no texture exists
	if not image:
		color = get_material_color(material)
		return [color[0], color[1], color[2]]
	
	# get UV map vertices indices
	verticesIndices = obj.data.polygons[polygon_index].vertices
	p1, p2, p3 = [obj.data.vertices[verticesIndices[i]].co for i in range(3)]
	uvMap = obj.data.uv_layers[obj.data.uv_layers.keys()[0]]
	uv1, uv2, uv3 = [uvMap.data[obj.data.polygons[polygon_index].loop_indices[i]].uv for i in range(3)]
	uv1 = Vector((uv1[0], uv1[1], 0))
	uv2 = Vector((uv2[0], uv2[1], 0))
	uv3 = Vector((uv3[0], uv3[1], 0))
	transformed_point = barycentric_transform( location, p1, p2, p3, uv1, uv2, uv3 )
	
	width = image.size[0]
	height = image.size[1]
	
	uv = Vector((transformed_point.x % 1.0, transformed_point.y % 1.0))
	
	coord = (
		round((uv[0] % 1.0) * width-1),
		round((uv[1] % 1.0) * height-1),
	)
	pindex = int(((width * int(coord[1])) + int(coord[0])) * 4)
	
	# store images as tuples to avoid recreating the object each loop
	if image.name not in image_tuples:
		print('Adding image', image.name)
		image_tuples[image.name] = tuple(image.pixels)
	color = image_tuples[image.name][pindex:pindex+4]

	return [color[0], color[1], color[2]]
Пример #13
0
def point_to_uv(obj, triangle_index, point, map_name, texture_size):
    uv_map = obj.data.uv_layers[map_name]

    vertices_indices = obj.data.polygons[triangle_index].vertices

    uv_map_indices = obj.data.polygons[triangle_index].loop_indices

    p1, p2, p3 = [obj.data.vertices[vertices_indices[i]].co for i in range(3)]

    uv1, uv2, uv3 = [uv_map.data[uv_map_indices[i]].uv for i in range(3)]
    uv_point = barycentric_transform(point, p1, p2, p3, uv1.to_3d(),
                                     uv2.to_3d(), uv3.to_3d())

    return uv_point.to_2d() * texture_size
Пример #14
0
 def process(self):
     Points, Colors = self.inputs
     obj = bpy.data.objects[self.object_ref]  # triangulate faces
     bvh = BVHTree.FromObject(obj, bpy.context.scene, deform=True, render=False, cage=False, epsilon=0.0)
     point = Points.sv_get()[0]
     color = Colors.sv_get()[0]
     ran = range(3)
     image = bpy.data.images[self.image]
     width, height = image.size
     uvMap = obj.data.uv_layers[0].data
     pixels = np.array(image.pixels[:]).reshape(width,height,4)
     for P, C in zip(point, safc(point, color)):
         loc, norm, ind, dist = bvh.find_nearest(P)
         found_poly = obj.data.polygons[ind]
         verticesIndices = found_poly.vertices
         p1, p2, p3 = [obj.data.vertices[verticesIndices[i]].co for i in ran]
         uvMapIndices = found_poly.loop_indices
         uv1, uv2, uv3 = [uvMap[uvMapIndices[i]].uv.to_3d() for i in ran]
         V = barycentric_transform(loc, p1, p2, p3, uv1, uv2, uv3)
         Vx, Vy = int(V.x*(width-1)), int(V.y*(height-1))
         pixels[Vy, Vx] = C
     image.pixels = pixels.flatten().tolist()
Пример #15
0
 def process(self):
     Points = self.inputs[0]
     Colors = self.outputs[0]
     if Colors.is_linked:
         obj = bpy.data.objects[self.object_ref]  # triangulate faces
         bvh = BVHTree.FromObject(obj, bpy.context.scene, deform=True, render=False, cage=False, epsilon=0.0)
         point = Points.sv_get()[0]
         outc = []
         ran = range(3)
         image = bpy.data.images[self.image]
         width, height = image.size
         pixels = np.array(image.pixels[:]).reshape(width, height, 4)
         uvMap = obj.data.uv_layers[0].data
         for P in point:
             loc, norm, ind, dist = bvh.find_nearest(P)
             found_poly = obj.data.polygons[ind]
             verticesIndices = found_poly.vertices
             p1, p2, p3 = [obj.data.vertices[verticesIndices[i]].co for i in ran]
             uvMapIndices = found_poly.loop_indices
             uv1, uv2, uv3 = [uvMap[uvMapIndices[i]].uv.to_3d() for i in ran]
             V = barycentric_transform(loc, p1, p2, p3, uv1, uv2, uv3)
             outc.append(pixels[int(V.x*(width-1)), int(V.y*(height-1))].tolist())
         Colors.sv_set([outc])
Пример #16
0
 def process(self):
     PointsUV = self.inputs[0]
     Pom, uvV, uvP = self.outputs
     obj = bpy.data.objects[self.object_ref]  # triangulate faces
     UVMAPV, UVMAPP = UV(self,obj)
     if Pom.is_linked:
         pointuv = PointsUV.sv_get()[0]
         bvh = BVHTree.FromPolygons(UVMAPV, UVMAPP, all_triangles=False, epsilon=0.0)
         ran = range(3)
         out = []
         uvMap = obj.data.uv_layers[0].data
         for Puv in pointuv:
             loc, norm, ind, dist = bvh.find_nearest(Puv)
             found_poly = obj.data.polygons[ind]
             verticesIndices = found_poly.vertices
             p1, p2, p3 = [obj.data.vertices[verticesIndices[i]].co for i in ran]
             uvMapIndices = found_poly.loop_indices
             uv1, uv2, uv3 = [uvMap[uvMapIndices[i]].uv.to_3d() for i in ran]
             V = barycentric_transform(Puv, uv1, uv2, uv3, p1, p2, p3)
             out.append(V[:])
         Pom.sv_set([out])
     if uvV.is_linked:
         uvV.sv_set([UVMAPV])
         uvP.sv_set([UVMAPP])
Пример #17
0
    def __stroke_apply(self, context, _):
        sc = context.scene
        objs = common.get_uv_editable_objects(context)

        for obj in objs:
            world_mat = obj.matrix_world
            bm = bmesh.from_edit_mesh(obj.data)
            uv_layer = bm.loops.layers.uv.verify()
            mco = self.current_mco

            if sc.muv_uv_sculpt_tools == 'GRAB':
                for info in self.__loop_info[obj]:
                    diff_uv = (mco - self.__initial_mco) * info["strength"]
                    l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
                    l[uv_layer].uv = info["initial_uv"] + diff_uv / 100.0

            elif sc.muv_uv_sculpt_tools == 'PINCH':
                _, region, space = common.get_space('VIEW_3D', 'WINDOW',
                                                    'VIEW_3D')
                loop_info = []
                for f in bm.faces:
                    if not f.select:
                        continue
                    for i, l in enumerate(f.loops):
                        loc_2d = location_3d_to_region_2d_extra(
                            region, space.region_3d,
                            compat.matmul(world_mat, l.vert.co))
                        diff = loc_2d - self.__initial_mco
                        if diff.length < sc.muv_uv_sculpt_radius:
                            info = {
                                "face_idx":
                                f.index,
                                "loop_idx":
                                i,
                                "initial_vco":
                                l.vert.co.copy(),
                                "initial_vco_2d":
                                loc_2d,
                                "initial_uv":
                                l[uv_layer].uv.copy(),
                                "strength":
                                _get_strength(diff.length,
                                              sc.muv_uv_sculpt_radius,
                                              sc.muv_uv_sculpt_strength)
                            }
                            loop_info.append(info)

                # mouse coordinate to UV coordinate
                ray_vec = view3d_utils.region_2d_to_vector_3d(
                    region, space.region_3d, mco)
                ray_vec.normalize()
                ray_orig = view3d_utils.region_2d_to_origin_3d(
                    region, space.region_3d, mco)
                ray_tgt = ray_orig + ray_vec * 1000000.0
                mwi = world_mat.inverted()
                ray_orig_obj = compat.matmul(mwi, ray_orig)
                ray_tgt_obj = compat.matmul(mwi, ray_tgt)
                ray_dir_obj = ray_tgt_obj - ray_orig_obj
                ray_dir_obj.normalize()
                tree = BVHTree.FromBMesh(bm)
                loc, _, fidx, _ = tree.ray_cast(ray_orig_obj, ray_dir_obj)
                if not loc:
                    return
                loops = [l for l in bm.faces[fidx].loops]
                uvs = [
                    Vector((l[uv_layer].uv.x, l[uv_layer].uv.y, 0.0))
                    for l in loops
                ]
                target_uv = barycentric_transform(loc, loops[0].vert.co,
                                                  loops[1].vert.co,
                                                  loops[2].vert.co, uvs[0],
                                                  uvs[1], uvs[2])
                target_uv = Vector((target_uv.x, target_uv.y))

                # move to target UV coordinate
                for info in loop_info:
                    l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
                    if sc.muv_uv_sculpt_pinch_invert:
                        diff_uv = \
                            (l[uv_layer].uv - target_uv) * info["strength"]
                    else:
                        diff_uv = \
                            (target_uv - l[uv_layer].uv) * info["strength"]
                    l[uv_layer].uv = l[uv_layer].uv + diff_uv / 10.0

            elif sc.muv_uv_sculpt_tools == 'RELAX':
                _, region, space = common.get_space('VIEW_3D', 'WINDOW',
                                                    'VIEW_3D')

                # get vertex and loop relation
                vert_db = {}
                for f in bm.faces:
                    for l in f.loops:
                        if l.vert in vert_db:
                            vert_db[l.vert]["loops"].append(l)
                        else:
                            vert_db[l.vert] = {"loops": [l]}

                # get relaxation information
                for k in vert_db.keys():
                    d = vert_db[k]
                    d["uv_sum"] = Vector((0.0, 0.0))
                    d["uv_count"] = 0

                    for l in d["loops"]:
                        ln = l.link_loop_next
                        lp = l.link_loop_prev
                        d["uv_sum"] = d["uv_sum"] + ln[uv_layer].uv
                        d["uv_sum"] = d["uv_sum"] + lp[uv_layer].uv
                        d["uv_count"] = d["uv_count"] + 2
                    d["uv_p"] = d["uv_sum"] / d["uv_count"]
                    d["uv_b"] = d["uv_p"] - d["loops"][0][uv_layer].uv
                for k in vert_db.keys():
                    d = vert_db[k]
                    d["uv_sum_b"] = Vector((0.0, 0.0))
                    for l in d["loops"]:
                        ln = l.link_loop_next
                        lp = l.link_loop_prev
                        dn = vert_db[ln.vert]
                        dp = vert_db[lp.vert]
                        d["uv_sum_b"] = d["uv_sum_b"] + dn["uv_b"] + dp["uv_b"]

                # apply
                for f in bm.faces:
                    if not f.select:
                        continue
                    for i, l in enumerate(f.loops):
                        loc_2d = location_3d_to_region_2d_extra(
                            region, space.region_3d,
                            compat.matmul(world_mat, l.vert.co))
                        diff = loc_2d - self.__initial_mco
                        if diff.length >= sc.muv_uv_sculpt_radius:
                            continue
                        db = vert_db[l.vert]
                        strength = _get_strength(diff.length,
                                                 sc.muv_uv_sculpt_radius,
                                                 sc.muv_uv_sculpt_strength)

                        base = (1.0 - strength) * l[uv_layer].uv
                        if sc.muv_uv_sculpt_relax_method == 'HC':
                            t = 0.5 * \
                                (db["uv_b"] + db["uv_sum_b"] / d["uv_count"])
                            diff = strength * (db["uv_p"] - t)
                            target_uv = base + diff
                        elif sc.muv_uv_sculpt_relax_method == 'LAPLACIAN':
                            diff = strength * db["uv_p"]
                            target_uv = base + diff
                        else:
                            continue

                        l[uv_layer].uv = target_uv

            bmesh.update_edit_mesh(obj.data)
Пример #18
0
    def _main(self, ob_act, objects, mode='OFFSET', use_clamp=False):

        def me_nos(verts):
            return [v.normal.copy() for v in verts]

        def me_cos(verts):
            return [v.co.copy() for v in verts]

        def ob_add_shape(ob, name):
            me = ob.data
            key = ob.shape_key_add(from_mix=False)
            if len(me.shape_keys.key_blocks) == 1:
                key.name = "Basis"
                key = ob.shape_key_add(from_mix=False)  # we need a rest
            key.name = name
            ob.active_shape_key_index = len(me.shape_keys.key_blocks) - 1
            ob.show_only_shape_key = True

        from mathutils.geometry import barycentric_transform
        from mathutils import Vector

        if use_clamp and mode == 'OFFSET':
            use_clamp = False

        me = ob_act.data
        orig_key_name = ob_act.active_shape_key.name

        orig_shape_coords = me_cos(ob_act.active_shape_key.data)

        orig_normals = me_nos(me.vertices)
        # actual mesh vertex location isn't as reliable as the base shape :S
        # orig_coords = me_cos(me.vertices)
        orig_coords = me_cos(me.shape_keys.key_blocks[0].data)

        for ob_other in objects:
            if ob_other.type != 'MESH':
                self.report({'WARNING'},
                            ("Skipping '%s', "
                             "not a mesh") % ob_other.name)
                continue
            me_other = ob_other.data
            if len(me_other.vertices) != len(me.vertices):
                self.report({'WARNING'},
                            ("Skipping '%s', "
                             "vertex count differs") % ob_other.name)
                continue

            target_normals = me_nos(me_other.vertices)
            if me_other.shape_keys:
                target_coords = me_cos(me_other.shape_keys.key_blocks[0].data)
            else:
                target_coords = me_cos(me_other.vertices)

            ob_add_shape(ob_other, orig_key_name)

            # editing the final coords, only list that stores wrapped coords
            target_shape_coords = [v.co for v in
                                   ob_other.active_shape_key.data]

            median_coords = [[] for i in range(len(me.vertices))]

            # Method 1, edge
            if mode == 'OFFSET':
                for i, vert_cos in enumerate(median_coords):
                    vert_cos.append(target_coords[i] +
                                    (orig_shape_coords[i] - orig_coords[i]))

            elif mode == 'RELATIVE_FACE':
                for poly in me.polygons:
                    idxs = poly.vertices[:]
                    v_before = idxs[-2]
                    v = idxs[-1]
                    for v_after in idxs:
                        pt = barycentric_transform(orig_shape_coords[v],
                                                   orig_coords[v_before],
                                                   orig_coords[v],
                                                   orig_coords[v_after],
                                                   target_coords[v_before],
                                                   target_coords[v],
                                                   target_coords[v_after],
                                                   )
                        median_coords[v].append(pt)
                        v_before = v
                        v = v_after

            elif mode == 'RELATIVE_EDGE':
                for ed in me.edges:
                    i1, i2 = ed.vertices
                    v1, v2 = orig_coords[i1], orig_coords[i2]
                    edge_length = (v1 - v2).length
                    n1loc = v1 + orig_normals[i1] * edge_length
                    n2loc = v2 + orig_normals[i2] * edge_length

                    # now get the target nloc's
                    v1_to, v2_to = target_coords[i1], target_coords[i2]
                    edlen_to = (v1_to - v2_to).length
                    n1loc_to = v1_to + target_normals[i1] * edlen_to
                    n2loc_to = v2_to + target_normals[i2] * edlen_to

                    pt = barycentric_transform(orig_shape_coords[i1],
                                               v2, v1, n1loc,
                                               v2_to, v1_to, n1loc_to)
                    median_coords[i1].append(pt)

                    pt = barycentric_transform(orig_shape_coords[i2],
                                               v1, v2, n2loc,
                                               v1_to, v2_to, n2loc_to)
                    median_coords[i2].append(pt)

            # apply the offsets to the new shape
            from functools import reduce
            VectorAdd = Vector.__add__

            for i, vert_cos in enumerate(median_coords):
                if vert_cos:
                    co = reduce(VectorAdd, vert_cos) / len(vert_cos)

                    if use_clamp:
                        # clamp to the same movement as the original
                        # breaks copy between different scaled meshes.
                        len_from = (orig_shape_coords[i] -
                                    orig_coords[i]).length
                        ofs = co - target_coords[i]
                        ofs.length = len_from
                        co = target_coords[i] + ofs

                    target_shape_coords[i][:] = co

        return {'FINISHED'}
Пример #19
0
    def _main(self, ob_act, objects, mode='OFFSET', use_clamp=False):

        def me_nos(verts):
            return [v.normal.copy() for v in verts]

        def me_cos(verts):
            return [v.co.copy() for v in verts]

        def ob_add_shape(ob, name):
            me = ob.data
            key = ob.shape_key_add(from_mix=False)
            if len(me.shape_keys.key_blocks) == 1:
                key.name = "Basis"
                key = ob.shape_key_add(from_mix=False)  # we need a rest
            key.name = name
            ob.active_shape_key_index = len(me.shape_keys.key_blocks) - 1
            ob.show_only_shape_key = True

        from mathutils.geometry import barycentric_transform
        from mathutils import Vector

        if use_clamp and mode == 'OFFSET':
            use_clamp = False

        me = ob_act.data
        orig_key_name = ob_act.active_shape_key.name

        orig_shape_coords = me_cos(ob_act.active_shape_key.data)

        orig_normals = me_nos(me.vertices)
        # actual mesh vertex location isn't as reliable as the base shape :S
        #~ orig_coords = me_cos(me.vertices)
        orig_coords = me_cos(me.shape_keys.key_blocks[0].data)

        for ob_other in objects:
            me_other = ob_other.data
            if len(me_other.vertices) != len(me.vertices):
                self.report({'WARNING'},
                            ("Skipping '%s', "
                             "vertex count differs") % ob_other.name)
                continue

            target_normals = me_nos(me_other.vertices)
            if me_other.shape_keys:
                target_coords = me_cos(me_other.shape_keys.key_blocks[0].data)
            else:
                target_coords = me_cos(me_other.vertices)

            ob_add_shape(ob_other, orig_key_name)

            # editing the final coords, only list that stores wrapped coords
            target_shape_coords = [v.co for v in
                                   ob_other.active_shape_key.data]

            median_coords = [[] for i in range(len(me.vertices))]

            # Method 1, edge
            if mode == 'OFFSET':
                for i, vert_cos in enumerate(median_coords):
                    vert_cos.append(target_coords[i] +
                                    (orig_shape_coords[i] - orig_coords[i]))

            elif mode == 'RELATIVE_FACE':
                for poly in me.polygons:
                    idxs = poly.vertices[:]
                    v_before = idxs[-2]
                    v = idxs[-1]
                    for v_after in idxs:
                        pt = barycentric_transform(orig_shape_coords[v],
                                                   orig_coords[v_before],
                                                   orig_coords[v],
                                                   orig_coords[v_after],
                                                   target_coords[v_before],
                                                   target_coords[v],
                                                   target_coords[v_after],
                                                   )
                        median_coords[v].append(pt)
                        v_before = v
                        v = v_after

            elif mode == 'RELATIVE_EDGE':
                for ed in me.edges:
                    i1, i2 = ed.vertices
                    v1, v2 = orig_coords[i1], orig_coords[i2]
                    edge_length = (v1 - v2).length
                    n1loc = v1 + orig_normals[i1] * edge_length
                    n2loc = v2 + orig_normals[i2] * edge_length

                    # now get the target nloc's
                    v1_to, v2_to = target_coords[i1], target_coords[i2]
                    edlen_to = (v1_to - v2_to).length
                    n1loc_to = v1_to + target_normals[i1] * edlen_to
                    n2loc_to = v2_to + target_normals[i2] * edlen_to

                    pt = barycentric_transform(orig_shape_coords[i1],
                                               v2, v1, n1loc,
                                               v2_to, v1_to, n1loc_to)
                    median_coords[i1].append(pt)

                    pt = barycentric_transform(orig_shape_coords[i2],
                                               v1, v2, n2loc,
                                               v1_to, v2_to, n2loc_to)
                    median_coords[i2].append(pt)

            # apply the offsets to the new shape
            from functools import reduce
            VectorAdd = Vector.__add__

            for i, vert_cos in enumerate(median_coords):
                if vert_cos:
                    co = reduce(VectorAdd, vert_cos) / len(vert_cos)

                    if use_clamp:
                        # clamp to the same movement as the original
                        # breaks copy between different scaled meshes.
                        len_from = (orig_shape_coords[i] -
                                    orig_coords[i]).length
                        ofs = co - target_coords[i]
                        ofs.length = len_from
                        co = target_coords[i] + ofs

                    target_shape_coords[i][:] = co

        return {'FINISHED'}
Пример #20
0
    def particle_hair_to_points_with_children(self, context):
        partsysMod = self.particleObj.particle_systems.active  # use last
        particle_id = self.particleObj.particle_systems.active_index  # use last
        particle_modal_settings = context.active_object.modal_hair.particle_system_modal_settings[
            particle_id]  # cos using self.particleObj gives random settings...
        diagonal = self.diagonal
        particle_count = len(partsysMod.particles)
        if particle_count == 0:  #require more that three strands
            return self.particle_hair_to_points(context)
        pointsList_hair = []

        coords = []
        global PARTICLE_CO  #cache strands for drawing
        strands_len = len(partsysMod.particles[0].hair_keys) - 1
        for strand in partsysMod.particles:  # for strand point
            pointsList_hair.append([
                hair_key.co for hair_key in strand.hair_keys
            ])  # DONE: exclude duplicates if first strand[0] in list already
            if context.active_object.modal_hair.drawStrands:
                for i, point in enumerate(
                        strand.hair_keys):  # create p1,p2,  p2,p3,  p3,p4
                    if i == 0 or i == strands_len:
                        coords.append((point.co[0], point.co[1], point.co[2]))
                    else:
                        coords.extend([(point.co[0], point.co[1], point.co[2]),
                                       (point.co[0], point.co[1], point.co[2])
                                       ])
            else:
                coords = [(0, 0, 0)]
        PARTICLE_CO = coords

        if particle_count == 1:  #create two fake strands so that barycentric works
            pointsList_hair.append([
                x.xyz + Vector((0.01 * diagonal, 0, 0))
                for x in pointsList_hair[0]
            ])
            pointsList_hair.append([
                x.xyz + Vector((0, 0.01 * diagonal, 0))
                for x in pointsList_hair[0]
            ])
        elif particle_count == 2:  #create one fake strands so that barycentric works
            pointsList_hair.append([
                x.xyz + Vector((0.01 * diagonal, 0, 0))
                for x in pointsList_hair[0]
            ])

        #TODO: damm it is slow - 0.3 sec - on 3333 particle mesh (while doing sinterpol is just 0.02 sec)
        #FIXED: it was here cos particles woudl fail on duplicates.... Fixed by removing duplis in init
        # pointsList_uniq = []
        # [pointsList_uniq.append(x) for x in pointsList_hair if x not in pointsList_uniq]  # removing doubles (can cause zero size tris)
        pointsList_uniq = pointsList_hair

        # same_point_count cos barycentric transform requires it
        pointsList = interpol_Catmull_Rom(
            pointsList_uniq,
            particle_modal_settings.t_in_y,
            uniform_spacing=False,
            same_point_count=True)  # just gives smoother result on borders
        searchDistance = 100 * diagonal
        parentRoots = [strand[0]
                       for strand in pointsList]  # first point of roots
        # create nnew Part Sytem with uniform points
        pointsChildRoots = HT_OT_RibbonsFromParticleHairChild.createUniformParticleSystem(
            context, particle_modal_settings.childCount,
            particle_modal_settings.PlacementJittering
        )  # return child part roots positions

        kd = kdtree.KDTree(len(parentRoots))
        for i, root in enumerate(parentRoots):
            kd.insert(root, i)
        kd.balance()
        sourceSurface_BVHT = self.sourceSurface_BVHT
        childStrandsPoints = []  # will contain strands with child points
        childStrandRootNormals = []
        seed(a=particle_modal_settings.lenSeed, version=2)
        for i, childRoot in enumerate(
                pointsChildRoots
        ):  # for each child find it three parents and genereate strands by barycentric transform
            snappedPoint, normalChildRoot, rootHitIndex, distance = sourceSurface_BVHT.find_nearest(
                childRoot, searchDistance)
            childStrandRootNormals.append(normalChildRoot)
            threeClosestParentRoots = kd.find_n(
                childRoot, 3)  # find three closes parent roots
            rootTri_co, ParentRootIndices, distances = zip(
                *threeClosestParentRoots)  # split it into 3 arrays
            sourceTri_BVHT = BVHTree.FromPolygons(
                rootTri_co, [(0, 1, 2)],
                all_triangles=True)  # [0,1,2] - polygon == vert indices list
            childRootSnapped, normalChildProjected, index, distance = sourceTri_BVHT.find_nearest(
                childRoot, searchDistance
            )  # snap generated child to parent triangle ares \normals are sometimes flipped
            childRootSnapped2, normalChildProjected2, index2, distance2 = sourceSurface_BVHT.find_nearest(
                childRootSnapped,
                searchDistance)  # this gives ok normals always

            lenWeight = 1 + uniform(
                -particle_modal_settings.RandomizeLengthMinus,
                particle_modal_settings.RandomizeLengthPlus)
            rotQuat = normalChildProjected2.rotation_difference(
                normalChildRoot)
            translationMatrix = Matrix.Translation(childRoot)
            rotMatrixRot = rotQuat.to_matrix().to_4x4()
            mat_sca = Matrix.Scale(lenWeight, 4)
            transformMatrix = translationMatrix @ rotMatrixRot
            strandPoints = []
            # for childRootSnapped points transform them from parent root triangles to parent next segment triangle t1,t2,t3
            # and compensate child snapping to root triangle from before
            for j, (t1, t2, t3) in enumerate(
                    zip(pointsList[ParentRootIndices[0]],
                        pointsList[ParentRootIndices[1]],
                        pointsList[ParentRootIndices[2]])):
                pointTransformed = barycentric_transform(
                    childRootSnapped, rootTri_co[0], rootTri_co[1],
                    rootTri_co[2], Vector(t1), Vector(t2), Vector(t3))
                childInterpolatedPoint = transformMatrix @ mat_sca @ (
                    pointTransformed - childRootSnapped
                )  # rotate child strand to original pos (from before snapt)
                strandPoints.append(childInterpolatedPoint)
            childStrandsPoints.append(strandPoints)
        if particle_modal_settings.use_parent_strands:
            childStrandsPoints.extend(pointsList)
        return childStrandsPoints
Пример #21
0
    def execute(self, context):
        depsgraph = bpy.context.depsgraph
        ob = bpy.context.active_object
        obj_eval = depsgraph.objects.get(ob.name, None)

        # particleObj = context.active_object
        particleObj = obj_eval
        if bpy.context.active_object.particle_systems is None:  # create new one
            self.report({'INFO'}, 'No active Particle Hair System found!')
            return {"CANCELLED"}
        index = particleObj.particle_systems.active_index
        psys_active = particleObj.particle_systems[index]
        if psys_active.settings.type != 'HAIR':  # create new one
            self.report({'INFO'},
                        'Active Particle System is not Hair type! Cancelling')
            return {"CANCELLED"}
        pointsList_hair = []
        context.scene.update()
        if len(psys_active.particles) == 0:  # require more that three strands
            self.report({'INFO'},
                        'Active Particle System has zero strands! Cancelling')
            return {"CANCELLED"}
        diagonal = sqrt(
            pow(particleObj.dimensions[0], 2) +
            pow(particleObj.dimensions[1], 2) +
            pow(particleObj.dimensions[2], 2))  # to normalize some values
        for particle in psys_active.particles:  # for strand point
            pointsList_hair.append([
                hair_key.co for hair_key in particle.hair_keys
            ])  # DONE: exclude duplicates if first strand[0] in list already
        if len(psys_active.particles
               ) == 1:  #create two fake strands so that barycentric works
            pointsList_hair.append([
                x.xyz + Vector((0.01 * diagonal, 0, 0))
                for x in pointsList_hair[0]
            ])
            pointsList_hair.append([
                x.xyz + Vector((0, 0.01 * diagonal, 0))
                for x in pointsList_hair[0]
            ])
        elif len(psys_active.particles
                 ) == 2:  #create one fake strands so that barycentric works
            pointsList_hair.append([
                x.xyz + Vector((0.01 * diagonal, 0, 0))
                for x in pointsList_hair[0]
            ])
        pointsList_uniq = []
        [
            pointsList_uniq.append(x) for x in pointsList_hair
            if x not in pointsList_uniq
        ]  #removing doubles (can cause zero size tris)

        #same_point_count cos barycentric transform requires it
        pointsList = interpol_Catmull_Rom(
            pointsList_uniq,
            self.t_in_y,
            uniform_spacing=True,
            same_point_count=True)  # just gives smoother result on borders

        searchDistance = 100 * diagonal
        parentRoots = [strand[0]
                       for strand in pointsList]  # first point of roots
        #create nnew Part Sytem with uniform points
        pointsChildRoots = self.createUniformParticleSystem(
            context, self.childCount, self.PlacementJittering,
            self.Seed)  # return child part roots positions

        kd = kdtree.KDTree(len(parentRoots))
        for i, root in enumerate(parentRoots):
            kd.insert(root, i)
        kd.balance()
        sourceSurface_BVHT = BVHTree.FromObject(particleObj, context.depsgraph)
        childStrandsPoints = []  #will contain strands with child points
        childStrandRootNormals = []
        length_ver_group_index = -1
        vertex_group_length_name = psys_active.vertex_group_length
        if vertex_group_length_name:  # calc weight based on root point
            length_ver_group_index = particleObj.vertex_groups[
                vertex_group_length_name].index
        particleObjMesh = particleObj.to_mesh(context.depsgraph,
                                              apply_modifiers=True,
                                              calc_undeformed=False)
        seed(a=self.lenSeed, version=2)
        embed = self.embed * 0.04 * diagonal
        cpow = calc_power(self.noiseFalloff)
        cpowClump = calc_power(self.ClumpingFalloff)
        noiseFalloff = [pow(i / self.t_in_y, cpow) for i in range(self.t_in_y)]
        ClumpFalloff = [
            pow((i + 1) / self.t_in_y, cpowClump) for i in range(self.t_in_y)
        ]

        for i, childRoot in enumerate(
                pointsChildRoots
        ):  #for each child find it three parents and genereate strands by barycentric transform
            snappedPoint, normalChildRoot, rootHitIndex, distance = sourceSurface_BVHT.find_nearest(
                childRoot, searchDistance)
            childStrandRootNormals.append(normalChildRoot)
            threeClosestParentRoots = kd.find_n(
                childRoot, 3)  #find three closes parent roots
            rootTri_co, ParentRootIndices, distances = zip(
                *threeClosestParentRoots)  #split it into 3 arrays
            sourceTri_BVHT = BVHTree.FromPolygons(
                rootTri_co, [(0, 1, 2)],
                all_triangles=True)  # [0,1,2] - polygon == vert indices list
            childRootSnapped, normalChildProjected, index, distance = sourceTri_BVHT.find_nearest(
                childRoot, searchDistance
            )  #snap generated child to parent triangle ares \normals are sometimes flipped
            childRootSnapped2, normalChildProjected2, index2, distance2 = sourceSurface_BVHT.find_nearest(
                childRootSnapped,
                searchDistance)  #this gives ok normals always

            lenWeight = 1
            if length_ver_group_index != -1:  # if vg exist
                averageWeight = 0
                for vertIndex in particleObjMesh.polygons[
                        rootHitIndex].vertices:  #DONE: check if work on mesh with modifiers
                    for group in particleObjMesh.vertices[vertIndex].groups:
                        if group.group == length_ver_group_index:
                            averageWeight += group.weight
                            break
                lenWeight = averageWeight / len(
                    particleObjMesh.polygons[rootHitIndex].vertices)
            ranLen = uniform(-self.RandomizeLengthMinus,
                             self.RandomizeLengthPlus)
            lenWeight *= (1 + ranLen)
            # diff = childRoot - childRootSnapped
            # mat_loc = Matrix.Translation(childRootSnapped)
            # matTriangleSpaceInv = mat_loc #* rotMatrix
            # matTriangleSpaceInv.invert()
            rotQuat = normalChildProjected2.rotation_difference(
                normalChildRoot)
            translationMatrix = Matrix.Translation(childRoot)
            rotMatrixRot = rotQuat.to_matrix().to_4x4()
            mat_sca = Matrix.Scale(lenWeight, 4)
            transformMatrix = translationMatrix @ rotMatrixRot
            strandPoints = []
            #for childRootSnapped points transform them from parent root triangles to parent next segment triangle t1,t2,t3
            # and compensate child snapping to root triangle from before
            for j, (t1, t2, t3) in enumerate(
                    zip(pointsList[ParentRootIndices[0]],
                        pointsList[ParentRootIndices[1]],
                        pointsList[ParentRootIndices[2]])):
                pointTransformed = barycentric_transform(
                    childRootSnapped, rootTri_co[0], rootTri_co[1],
                    rootTri_co[2], Vector(t1), Vector(t2), Vector(t3))
                childInterpolatedPoint = transformMatrix @ mat_sca @ (
                    pointTransformed - childRootSnapped
                )  #rotate child strand to original pos (from before snapt)
                #do noise
                noise.seed_set(self.Seed + i)  # add seed per strand/ring ?
                noiseVectorPerStrand = noise.noise_vector(
                    childInterpolatedPoint * self.freq / diagonal,
                    noise_basis='PERLIN_ORIGINAL'
                ) * noiseFalloff[j] * self.noiseAmplitude * diagonal / 10
                # childInterpolatedPoint += noiseVectorPerStrand

                #do clumping
                diff = Vector(
                    t1
                ) - childInterpolatedPoint  # calculate distance to parent strand (first strand from trio)
                # point += noiseVectorPerStrand * noiseFalloff[j] * self.noiseAmplitude * diagonal / 10
                # childClumped = childInterpolatedPoint + ClumpFalloff[j] * self.Clumping * diff + noiseVectorPerStrand * (1-ClumpFalloff[j])
                childClumped = childInterpolatedPoint + ClumpFalloff[
                    j] * self.Clumping * diff + noiseVectorPerStrand * (
                        1 - ClumpFalloff[j] * self.Clumping)
                # childClumped = childInterpolatedPoint + noiseVectorPerStrand

                strandPoints.append(childClumped)
            # embeding roots
            diff = strandPoints[0] - strandPoints[1]
            diff.normalize()
            normalWeight = abs(diff.dot(normalChildRoot))
            strandPoints[0] += (
                diff * normalWeight - normalChildRoot * (1 - normalWeight)
            ) * embed  # do childStrandRootNormal to move it more into mesh surface
            childStrandsPoints.append(strandPoints)

        bpy.data.meshes.remove(particleObjMesh)
        # create the Curve Datablock
        curveData = bpy.data.curves.new(particleObj.name + '_curve',
                                        type='CURVE')

        splinePointsNp = np.array(childStrandsPoints, dtype=np.float32)
        if self.hairType != 'BEZIER':
            splinePointsNpOnes = np.ones(
                (len(childStrandsPoints), self.t_in_y, 4),
                dtype=np.float32)  # 4 coord x,y,z ,1
            splinePointsNpOnes[:, :, :-1] = splinePointsNp
            splinePointsNp = splinePointsNpOnes
        for strandPoints in splinePointsNp:  # for strand point
            curveLength = len(strandPoints)
            polyline = curveData.splines.new(self.hairType)
            if self.hairType == 'BEZIER':
                polyline.bezier_points.add(curveLength - 1)
            elif self.hairType == 'POLY' or self.hairType == 'NURBS':
                polyline.points.add(curveLength - 1)
            if self.hairType == 'NURBS':
                polyline.order_u = 3  # like bezier thing
                polyline.use_endpoint_u = True

            if self.hairType == 'BEZIER':
                # polyline.bezier_points.co = (x, y, z)
                polyline.bezier_points.foreach_set("co", strandPoints.ravel())
                polyline.bezier_points.foreach_set('handle_left_type', 'AUTO')
                polyline.bezier_points.foreach_set('handle_right_type', 'AUTO')
            else:
                polyline.points.foreach_set("co", strandPoints.ravel())
                # polyline.points[i].co = (x, y, z, 1)
        curveData.resolution_u = self.strandResU
        curveData.dimensions = '3D'
        # create Object
        curveOB = bpy.data.objects.new(particleObj.name + '_curve', curveData)
        curveOB.matrix_world = particleObj.matrix_world
        scn = context.scene
        scn.collection.objects.link(curveOB)
        curveOB.targetObjPointer = particleObj.name  # store source surface for snapping oper
        context.view_layer.objects.active = curveOB
        curveOB.select_set(True)
        # curveOB.data.show_normal_face = False
        if self.generateRibbons:
            bpy.ops.object.generate_ribbons(strandResU=self.strandResU,
                                            strandResV=self.strandResV,
                                            strandWidth=self.strandWidth,
                                            strandPeak=self.strandPeak,
                                            strandUplift=self.strandUplift,
                                            alignToSurface=self.alignToSurface)
            HT_OT_CurvesUVRefresh.uvCurveRefresh(curveOB)
            context.view_layer.objects.active = particleObj
        else:
            curveData.fill_mode = 'FULL'
            curveData.bevel_depth = 0.004 * diagonal
            curveData.bevel_resolution = 2
            bpy.ops.object.curve_taper(TipRadiusFalloff=self.RadiusFalloff,
                                       TipRadius=self.TipRadius,
                                       MainRadius=self.Radius)
        return {"FINISHED"}
Пример #22
0
    def __stroke_apply(self, context, _):
        sc = context.scene
        obj = context.active_object
        world_mat = obj.matrix_world
        bm = bmesh.from_edit_mesh(obj.data)
        uv_layer = bm.loops.layers.uv.verify()
        mco = self.current_mco

        if sc.muv_uv_sculpt_tools == 'GRAB':
            for info in self.__loop_info:
                diff_uv = (mco - self.__initial_mco) * info["strength"]
                l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
                l[uv_layer].uv = info["initial_uv"] + diff_uv / 100.0

        elif sc.muv_uv_sculpt_tools == 'PINCH':
            _, region, space = common.get_space('VIEW_3D', 'WINDOW', 'VIEW_3D')
            loop_info = []
            for f in bm.faces:
                if not f.select:
                    continue
                for i, l in enumerate(f.loops):
                    loc_2d = view3d_utils.location_3d_to_region_2d(
                        region, space.region_3d,
                        compat.matmul(world_mat, l.vert.co))
                    diff = loc_2d - self.__initial_mco
                    if diff.length < sc.muv_uv_sculpt_radius:
                        info = {
                            "face_idx": f.index,
                            "loop_idx": i,
                            "initial_vco": l.vert.co.copy(),
                            "initial_vco_2d": loc_2d,
                            "initial_uv": l[uv_layer].uv.copy(),
                            "strength": _get_strength(
                                diff.length, sc.muv_uv_sculpt_radius,
                                sc.muv_uv_sculpt_strength)
                        }
                        loop_info.append(info)

            # mouse coordinate to UV coordinate
            ray_vec = view3d_utils.region_2d_to_vector_3d(region,
                                                          space.region_3d, mco)
            ray_vec.normalize()
            ray_orig = view3d_utils.region_2d_to_origin_3d(region,
                                                           space.region_3d,
                                                           mco)
            ray_tgt = ray_orig + ray_vec * 1000000.0
            mwi = world_mat.inverted()
            ray_orig_obj = compat.matmul(mwi, ray_orig)
            ray_tgt_obj = compat.matmul(mwi, ray_tgt)
            ray_dir_obj = ray_tgt_obj - ray_orig_obj
            ray_dir_obj.normalize()
            tree = BVHTree.FromBMesh(bm)
            loc, _, fidx, _ = tree.ray_cast(ray_orig_obj, ray_dir_obj)
            if not loc:
                return
            loops = [l for l in bm.faces[fidx].loops]
            uvs = [Vector((l[uv_layer].uv.x, l[uv_layer].uv.y, 0.0))
                   for l in loops]
            target_uv = barycentric_transform(
                loc, loops[0].vert.co, loops[1].vert.co, loops[2].vert.co,
                uvs[0], uvs[1], uvs[2])
            target_uv = Vector((target_uv.x, target_uv.y))

            # move to target UV coordinate
            for info in loop_info:
                l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
                if sc.muv_uv_sculpt_pinch_invert:
                    diff_uv = (l[uv_layer].uv - target_uv) * info["strength"]
                else:
                    diff_uv = (target_uv - l[uv_layer].uv) * info["strength"]
                l[uv_layer].uv = l[uv_layer].uv + diff_uv / 10.0

        elif sc.muv_uv_sculpt_tools == 'RELAX':
            _, region, space = common.get_space('VIEW_3D', 'WINDOW', 'VIEW_3D')

            # get vertex and loop relation
            vert_db = {}
            for f in bm.faces:
                for l in f.loops:
                    if l.vert in vert_db:
                        vert_db[l.vert]["loops"].append(l)
                    else:
                        vert_db[l.vert] = {"loops": [l]}

            # get relaxation information
            for k in vert_db.keys():
                d = vert_db[k]
                d["uv_sum"] = Vector((0.0, 0.0))
                d["uv_count"] = 0

                for l in d["loops"]:
                    ln = l.link_loop_next
                    lp = l.link_loop_prev
                    d["uv_sum"] = d["uv_sum"] + ln[uv_layer].uv
                    d["uv_sum"] = d["uv_sum"] + lp[uv_layer].uv
                    d["uv_count"] = d["uv_count"] + 2
                d["uv_p"] = d["uv_sum"] / d["uv_count"]
                d["uv_b"] = d["uv_p"] - d["loops"][0][uv_layer].uv
            for k in vert_db.keys():
                d = vert_db[k]
                d["uv_sum_b"] = Vector((0.0, 0.0))
                for l in d["loops"]:
                    ln = l.link_loop_next
                    lp = l.link_loop_prev
                    dn = vert_db[ln.vert]
                    dp = vert_db[lp.vert]
                    d["uv_sum_b"] = d["uv_sum_b"] + dn["uv_b"] + dp["uv_b"]

            # apply
            for f in bm.faces:
                if not f.select:
                    continue
                for i, l in enumerate(f.loops):
                    loc_2d = view3d_utils.location_3d_to_region_2d(
                        region, space.region_3d,
                        compat.matmul(world_mat, l.vert.co))
                    diff = loc_2d - self.__initial_mco
                    if diff.length >= sc.muv_uv_sculpt_radius:
                        continue
                    db = vert_db[l.vert]
                    strength = _get_strength(diff.length,
                                             sc.muv_uv_sculpt_radius,
                                             sc.muv_uv_sculpt_strength)

                    base = (1.0 - strength) * l[uv_layer].uv
                    if sc.muv_uv_sculpt_relax_method == 'HC':
                        t = 0.5 * (db["uv_b"] + db["uv_sum_b"] / d["uv_count"])
                        diff = strength * (db["uv_p"] - t)
                        target_uv = base + diff
                    elif sc.muv_uv_sculpt_relax_method == 'LAPLACIAN':
                        diff = strength * db["uv_p"]
                        target_uv = base + diff
                    else:
                        continue

                    l[uv_layer].uv = target_uv

        bmesh.update_edit_mesh(obj.data)