def rig_propagate_scale(self, mch, index1, index2, factor, use_y=False): handles = self.get_all_mch_handles() self.make_constraint( mch, 'COPY_SCALE', handles[index1], space='LOCAL', use_x=True, use_y=use_y, use_z=True, use_offset=True, power=clamp(1-factor) ) self.make_constraint( mch, 'COPY_SCALE', handles[index2], space='LOCAL', use_x=True, use_y=use_y, use_z=True, use_offset=True, power=clamp(factor) )
def get_node_parent_bones(self, node): """Get parent bones and their armature weights for the given control node.""" self.arrange_child_chains() # Choose correct layer bones layer = self.chain_to_layer[node.rig] top_mch = LazyRef(self.bones.mch, 'top_out', layer) bottom_mch = LazyRef(self.bones.mch, 'bottom_out', layer) middle_mch = LazyRef(self.bones.mch, 'middle_out', layer) # Corners have one input corner = self.is_corner_node(node) if corner: if corner == SideZ.TOP: return [top_mch] elif corner == SideZ.BOTTOM: return [bottom_mch] else: return [middle_mch] # Otherwise blend two if node.rig in self.chains_by_side[SideZ.TOP]: side_mch = top_mch else: side_mch = bottom_mch pt_x = (self.to_mouth_space @ node.point).x side = Side.LEFT if pt_x * self.left_sign >= 0 else Side.RIGHT corner_x = (self.to_mouth_space @ self.corners[side][layer].point).x factor = math.sqrt(1 - clamp(pt_x / corner_x) ** 2) return [(side_mch, factor), (middle_mch, 1-factor)]
def get_pivot_projection(self, pos, index): """Compute the interpolation factor within the chain for a control at pos and index.""" if self.params.skin_chain_falloff_length: # Position along the length of the chain return self.chain_lengths[index] / self.chain_lengths[-1] else: # Position projected on the line connecting chain ends return clamp((pos - self.pivot_base).dot(self.pivot_vector) / self.pivot_length)
def rig_propagate_twist(self, mch, index1, index2, factor): handles = self.get_all_mch_handles() handles_pre = self.get_all_mch_handles_pre() variables = { 'y1': driver_var_transform(self.obj, handles[index1], type='ROT_Y', space='LOCAL', rotation_mode='SWING_TWIST_Y'), 'y2': driver_var_transform(self.obj, handles[index2], type='ROT_Y', space='LOCAL', rotation_mode='SWING_TWIST_Y'), } if handles_pre[index1] != handles[index1]: variables['p1'] = driver_var_transform( self.obj, handles_pre[index1], type='ROT_Y', space='LOCAL', rotation_mode='SWING_TWIST_Y') expr1 = 'y1-p1' else: expr1 = 'y1' if handles_pre[index2] != handles[index2]: variables['p2'] = driver_var_transform( self.obj, handles_pre[index2], type='ROT_Y', space='LOCAL', rotation_mode='SWING_TWIST_Y') expr2 = 'y2-p2' else: expr2 = 'y2' bone = self.get_bone(mch) bone.rotation_mode = 'YXZ' self.make_driver(bone, 'rotation_euler', index=1, expression='lerp({},{},{})'.format( expr1, expr2, clamp(factor)), variables=variables)
def extend_control_node_parent(self, parent, node): if node.rig != self or node.index in (0, self.num_orgs): return parent parent = ControlBoneParentOffset(self, node, parent) # Add offsets from the end controls to other nodes factor = self.get_pivot_projection(node.point, node.index) if self.use_falloff_curve(Control.START): parent.add_copy_local_location( LazyRef(self.control_nodes[0], 'reparent_bone'), influence=self.apply_falloff_curve(1 - factor, Control.START), ) if self.use_falloff_curve(Control.END): parent.add_copy_local_location( LazyRef(self.control_nodes[-1], 'reparent_bone'), influence=self.apply_falloff_curve(factor, Control.END), ) # Add offset from the middle pivot if self.pivot_pos and node.index != self.pivot_pos: if self.use_falloff_curve(Control.MIDDLE): if node.index < self.pivot_pos: factor = factor / self.middle_pivot_factor else: factor = (1 - factor) / (1 - self.middle_pivot_factor) parent.add_copy_local_location( LazyRef(self.control_nodes[self.pivot_pos], 'reparent_bone'), influence=self.apply_falloff_curve(clamp(factor), Control.MIDDLE), ) # If Propagate To Controls is set, add an extra wrapper for twist/scale if node.index != self.pivot_pos and self.params.skin_chain_falloff_to_controls: if self.params.skin_chain_falloff_twist or self.params.skin_chain_falloff_scale: parent = ControlBoneChainPropagate(self, node, parent) return parent
def extend_control_node_parent(self, parent, node): if node.rig != self or node.index in (0, self.num_orgs): return parent parent = ControlBoneParentOffset(self, node, parent) factor = self.get_pivot_projection(node.point, node.index) if self.use_falloff_curve(0): parent.add_copy_local_location( LazyRef(self.control_nodes[0], 'reparent_bone'), influence=self.apply_falloff_start(1 - factor), ) if self.use_falloff_curve(2): parent.add_copy_local_location( LazyRef(self.control_nodes[-1], 'reparent_bone'), influence=self.apply_falloff_end(factor), ) if self.pivot_pos and node.index != self.pivot_pos and self.use_falloff_curve( 1): if node.index < self.pivot_pos: factor = factor / self.middle_pivot_factor else: factor = (1 - factor) / (1 - self.middle_pivot_factor) parent.add_copy_local_location( LazyRef(self.control_nodes[self.pivot_pos], 'reparent_bone'), influence=self.apply_falloff_middle(clamp(factor)), ) if node.index != self.pivot_pos and self.params.skin_chain_falloff_to_controls: if self.params.skin_chain_falloff_twist or self.params.skin_chain_falloff_scale: parent = ControlBoneChainPropagate(self, node, parent) return parent
def drawBoltGPU(self, lines, pixels, coord, w, h): vertexSource = ''' in vec3 position; void main() { gl_Position = vec4(position, 1.0); } ''' geometrySource = ''' layout(lines) in; layout(triangle_strip, max_vertices = 4) out; void main() { float width = gl_in[1].gl_Position.z; vec2 line = gl_in[1].gl_Position.xy - gl_in[0].gl_Position.xy; vec2 normal = normalize(vec2(line.y, -line.x))*(width/2.0); for(int i=0; i<4; i++) { vec2 coords = gl_in[i/2].gl_Position.xy+(1-2*(i%2))*normal; gl_Position = vec4(coords, 0.0, 1.0); EmitVertex(); } EndPrimitive(); } ''' fragmentSource = ''' out vec4 fragColor; void main() { fragColor = vec4(1.0,1.0,1.0,1.0); } ''' positions = [] for segment in lines.segments: pts = lines.getCoords(segment)[0] ptA = np.divide(pts[0], np.array([w, h])) * 2 - 1.0 ptB = np.divide(pts[1], np.array([w, h])) * 2 - 1.0 width = bl_math.clamp( self.thickness * (1.0 - (segment.level / (self.falloff * lines.getMaxLevel()))), 0, self.thickness) / w positions.append((ptA[0], ptA[1], width)) positions.append((ptB[0], ptB[1], width)) offscreen = gpu.types.GPUOffScreen(w, h) shaders = gpu.types.GPUShader(vertexSource, fragmentSource, geocode=geometrySource) batch = batch_for_shader(shaders, 'LINES', {"position": tuple(positions)}) with offscreen.bind(): bgl.glClearColor(0.0, 0.0, 0.0, 1.0) bgl.glClear(bgl.GL_COLOR_BUFFER_BIT) with gpu.matrix.push_pop(): gpu.matrix.load_matrix(mathutils.Matrix.Identity(4)) gpu.matrix.load_projection_matrix(mathutils.Matrix.Identity(4)) shaders.bind() batch.draw(shaders) buffer = bgl.Buffer(bgl.GL_FLOAT, w * h * 4) bgl.glReadBuffer(bgl.GL_BACK) bgl.glReadPixels(0, 0, w, h, bgl.GL_RGBA, bgl.GL_FLOAT, buffer) pixels.foreach_set(buffer) offscreen.free()
def drawBolt(self, lines, pixels, coord, w, h): bitmap = [0.0, 0.0, 0.0, 1.0] * (w * h) def drawLine(start, end, thickness): def scaleRadius(radius, point, start, end, scale): if (scale == 1.0): return radius maxDistMultiplier = 1.0 maxDist = math.dist((coord[0], coord[1]), (coord[2], coord[3])) * maxDistMultiplier currentDist = math.dist(point, (coord[0], coord[1])) if (currentDist == 0.0): return radius return int( round((currentDist / maxDist) * scale * radius + radius)) def setPixel(x, y): if (0 <= x < w) and (0 <= y < h): offset = (x + int(y * w)) * 4 for i in range(4): try: bitmap[offset + i] = 1.0 except: {} def drawPoint(x, y, thickness): radius = scaleRadius(thickness, [x, y], start, end, self.perspectiveScale) for X in range(-radius, radius + 1): for Y in range(-radius, radius + 1): if (X * X + Y * Y <= radius * radius): setPixel(X + x, Y + y) # Bressenham dx = abs(end[0] - start[0]) dy = abs(end[1] - start[1]) x, y = start[0], start[1] sx = -1 if start[0] > end[0] else 1 sy = -1 if start[1] > end[1] else 1 if dx > dy: err = dx / 2.0 while x != end[0] and (0 <= x < w): drawPoint(x, y, thickness) err -= dy if err < 0: y += sy err += dx x += sx else: err = dy / 2.0 while y != end[1] and (0 <= y < h): drawPoint(x, y, thickness) err -= dx if err < 0: x += sx err += dy y += sy drawPoint(x, y, thickness) for segment in lines.segments: pts = lines.getCoords(segment)[0] width = int( bl_math.clamp( self.thickness * (1.0 - (segment.level / (self.falloff * lines.getMaxLevel()))), 0, self.thickness)) drawLine((int(pts[0][0]), int(pts[0][1])), (int(pts[1][0]), int(pts[1][1])), width) pixels.foreach_set(bitmap)
def get_pivot_projection(self, pos, index): if self.params.skin_chain_falloff_length: return self.chain_lengths[index] / self.chain_lengths[-1] else: return clamp((pos - self.pivot_base).dot(self.pivot_vector) / self.pivot_length)