示例#1
0
def compute_verts(nodes: Iterable[Node], bone: Bone) -> None:
    """Build the initial vertexes of each node."""
    bone_weight = [(bone, 1.0)]
    todo = set(nodes)

    def vert(pos: Vec, off: Vec, u: float, v: float) -> Vertex:
        """Make a vertex, with appropriate UVs."""
        if config.flip_uv:
            v, u = u, v
        return Vertex(pos + off, off.norm(), u, v, bone_weight)

    while todo:
        start = todo.pop()
        start = start.find_start()
        if start.next is None:
            continue
        v_start = 0.0
        for node1 in start.follow():
            todo.discard(node1)
            node2 = node1.next if node1.next is not None else node1
            config = node1.config
            count = node1.config.side_count
            v_end = v_start + config.v_scale * (node2.pos - node1.pos).mag()
            for i in range(count):
                ang = lerp(i, 0, count, 0, 2 * math.pi)
                local = Vec(0, math.cos(ang), math.sin(ang))
                u = lerp(i, 0, count, config.u_min, config.u_max)
                node1.points_next.append(
                    vert(node1.pos, node1.radius * local @ node1.orient, u,
                         v_start))
                if node1.next is not None:
                    node1.next.points_prev.append(
                        vert(node2.pos, node2.radius * local @ node2.orient, u,
                             v_end))
            v_start = v_end
示例#2
0
    def vec_point(self, t: float, dest: DestType = DestType.PRIMARY) -> Vec:
        """Return the position along the curve."""
        assert dest is DestType.PRIMARY
        if self.reversed:
            t = 1.0 - t

        if t < self.STRAIGHT_PERC:
            x = 0
            y = lerp(t, 0.0, self.STRAIGHT_PERC, 128, 72)
        else:
            ang = lerp(t, self.STRAIGHT_PERC, 1.0, 0.0, math.pi / 4)
            x = lerp(math.cos(ang), 1.0, math.cos(math.pi / 4), 0, 64)
            y = lerp(math.sin(ang), 0.0, math.sin(math.pi / 4), 72, -64)

        return Vec(x, self.y * y, 0) @ self.matrix + self.origin
示例#3
0
 def make_cap(orig, norm):
     # Recompute the UVs to use the first bit of the cable.
     points = [
         Vertex(
             point.pos,
             norm,
             lerp(Vec.dot(point.norm, node.orient.up()), -1, 1,
                  node.config.u_min, node.config.u_max),
             lerp(Vec.dot(point.norm, node.orient.left()), -1, 1, 0, v_max),
             point.links,
         ) for point in orig
     ]
     mesh.triangles.append(Triangle(mat, points[0], points[1], points[2]))
     for a, b in zip(points[2:], points[3:]):
         mesh.triangles.append(Triangle(mat, points[0], a, b))
示例#4
0
def interpolate_straight(node1: Node, node2: Node,
                         seg_count: int) -> List[Node]:
    """Simply interpolate in a straight line."""
    diff = (node2.pos - node1.pos) / (seg_count + 1)
    return [
        Node(node1.pos + diff * i, node1.config,
             lerp(i, 0, seg_count + 1, node1.radius, node2.radius))
        for i in range(1, seg_count + 1)
    ]
示例#5
0
def interpolate_rope(node1: Node, node2: Node, seg_count: int) -> List[Node]:
    """Compute the move_rope style hanging points.

    This uses a quite unusual implementation in Source, doing a physics simulation.
    See the following files for this code:
        - src/public/keyframe.cpp
        - src/public/simple_physics.cpp
        - src/public/rope_physics.cpp
    """
    diff = node2.pos - node1.pos
    total_len = diff.mag() + max(0.0, node1.config.slack - 100.0)
    max_len = total_len / (seg_count + 1)
    max_len_sqr = max_len**2

    interp_diff = diff / (seg_count + 1)
    points = [
        RopePhys(
            node1.pos + interp_diff * i,
            lerp(i, 0, seg_count + 2, node1.radius, node2.radius),
        ) for i in range(0, seg_count + 2)
    ]
    springs = list(zip(points, points[1:]))

    time = 0
    step = TIME_STEP
    gravity = Vec(z=ROPE_GRAVITY) * step**2

    # Start/end doesn't move.
    anchor1, *moveable, anchor2 = points

    while time < SIM_TIME:
        time += step
        points[0].pos = node1.pos.copy()
        points[-1].pos = node2.pos.copy()
        # Gravity.
        for node in moveable:
            node.prev_pos, node.pos = node.pos, (
                node.pos + (node.pos - node.prev_pos) * 0.98 + gravity)

        # Spring constraints.
        for _ in range(3):
            for phys1, phys2 in springs:
                diff = phys1.pos - phys2.pos
                dist = diff.mag_sq()
                if dist > max_len_sqr:
                    diff *= 0.5 * (1 - (max_len / math.sqrt(dist)))
                    if phys1 is not anchor1:
                        phys1.pos -= diff
                    if phys2 is not anchor2:
                        phys2.pos += diff

    return [Node(point.pos, node1.config, point.radius) for point in moveable]
示例#6
0
def interpolate_catmull_rom(node1: Node, node2: Node,
                            seg_count: int) -> List[Node]:
    """Interpolate a spline curve, matching Valve's implementation."""
    # If no points are found, extrapolate out the line.
    diff = (node2.pos - node1.pos).norm()
    if node1.prev is None:
        p0 = node1.pos - diff
    else:
        p0 = node1.prev.pos
    p1 = node1.pos
    p2 = node2.pos
    if node2.next is None:
        p3 = node2.pos + diff
    else:
        p3 = node2.next.pos
    t0 = 0
    t1 = t0 + (p1 - p0).mag()
    t2 = t1 + (p2 - p1).mag()
    t3 = t2 + (p3 - p2).mag()
    points: List[Node] = []
    for i in range(1, seg_count + 1):
        t = lerp(i, 0, seg_count + 1, t1, t2)
        A1 = (t1 - t) / (t1 - t0) * p0 + (t - t0) / (t1 - t0) * p1
        A2 = (t2 - t) / (t2 - t1) * p1 + (t - t1) / (t2 - t1) * p2
        A3 = (t3 - t) / (t3 - t2) * p2 + (t - t2) / (t3 - t2) * p3

        B1 = (t2 - t) / (t2 - t0) * A1 + (t - t0) / (t2 - t0) * A2
        B2 = (t3 - t) / (t3 - t1) * A2 + (t - t1) / (t3 - t1) * A3

        points.append(
            Node(
                (t2 - t) / (t2 - t1) * B1 + (t - t1) / (t2 - t1) * B2,
                node1.config,
                lerp(i, 0, seg_count + 1, node1.radius, node2.radius),
            ))
    return points