-
-
Save pgtwitter/74665852177db828e91025c3cd0d98f1 to your computer and use it in GitHub Desktop.
3フレーム前から現在までの対象頂点位置を繋いだメッシュ(vとeのみ)を作成し,以降フレーム毎に位置を変えてシェープキーとして登録し,これを切り替えて動かしてみる.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bpy | |
import mathutils | |
import bmesh | |
def d2r(deg): | |
return deg / 180.0 * 3.1415926 | |
def deleteMesh(name): | |
if name not in bpy.data.objects: | |
return | |
obj = bpy.data.objects[name] | |
if hasattr(obj, "animation_data"): | |
if hasattr(obj.animation_data, "action"): | |
action = obj.animation_data.action | |
if action is not None: | |
bpy.data.actions.remove(action) | |
mesh = bpy.data.meshes[name] | |
if hasattr(mesh, "animation_data"): | |
if hasattr(mesh.animation_data, "action"): | |
action = mesh.animation_data.action | |
if action is not None: | |
bpy.data.actions.remove(action) | |
if mesh.shape_keys is not None: | |
if hasattr(mesh, "animation_data"): | |
if hasattr(mesh.animation_data, "action"): | |
action = mesh.shape_keys.animation_data.action | |
if action is not None: | |
bpy.data.actions.remove(action) | |
bpy.data.meshes.remove(mesh) | |
def setPlane(name="Plane"): | |
if name in bpy.data.meshes: | |
deleteMesh(name) | |
bpy.ops.mesh.primitive_plane_add(size=20) | |
plane = bpy.context.object | |
plane.data.name = name | |
plane.name = name | |
plane.location.z = -1.1 | |
return plane | |
def setLight(name="Light"): | |
if name in bpy.data.lights: | |
bpy.data.lights.remove(bpy.data.lights[name]) | |
bpy.ops.object.light_add( | |
type="AREA", | |
location=(0.0, 0.0, 8.0),) | |
light = bpy.context.object | |
light.data.name = name | |
light.name = name | |
light.data.energy = 500 | |
light.data.shape = "SQUARE" | |
light.data.size = 3 | |
def setCamera(name="Camera"): | |
if name in bpy.data.cameras: | |
bpy.data.cameras.remove(bpy.data.cameras[name]) | |
bpy.ops.object.camera_add( | |
location=(0.0, -22.0, 10.0), | |
rotation=(d2r(63.0), 0.0, 0.0)) | |
camera = bpy.context.object | |
camera.data.name = name | |
camera.name = name | |
return camera | |
def setCubeAnime(cube): | |
lrs = [ | |
[(-5, -5, 0), (0, 0, 0)], | |
[(5, -5, 0), (0, 0, 0)], | |
[(5, -5, 0), (0, 0, d2r(135))], | |
[(-5, 5, 0), (d2r(180), 0, d2r(135))], | |
[(-5, 5, 0), (d2r(180), 0, 0)], | |
[(5, 5, 0), (d2r(180), 0, 0)], | |
[(5, 5, 0), (d2r(180), 0, -d2r(135+360))], | |
[(-5, -5, 0), (0, 0, -d2r(135+360))], | |
[(-5, -5, 0), (0, 0, -d2r(360))] | |
] | |
w = 15 | |
cube.location = lrs[0][0] | |
cube.rotation_euler = lrs[0][1] | |
cube.keyframe_insert(data_path="location", frame=1) | |
cube.keyframe_insert(data_path="rotation_euler", frame=1) | |
for t in range(1, len(lrs)): | |
cube.location = lrs[t][0] | |
cube.rotation_euler = lrs[t][1] | |
cube.keyframe_insert(data_path="location", frame=w*t) | |
cube.keyframe_insert(data_path="rotation_euler", frame=w*t) | |
return w * (len(lrs)-1) | |
def setCube(name="Cube"): | |
bpy.ops.object.select_all(action="DESELECT") | |
if name in bpy.data.meshes: | |
deleteMesh(name) | |
bpy.ops.mesh.primitive_cube_add() | |
cube = bpy.context.object | |
cube.name = name | |
cube.data.name = name | |
bpy.ops.object.modifier_add(type="BEVEL") | |
bevel = cube.modifiers.active | |
bevel.segments = 5 | |
bpy.ops.object.shade_smooth(use_auto_smooth=True) | |
return cube, setCubeAnime(cube) | |
def getMatrixs(cube): | |
bpy.ops.object.select_all(action="DESELECT") | |
matrixs = [] | |
scene = bpy.context.scene | |
for t in range(scene.frame_start, scene.frame_end+1): | |
bpy.context.scene.frame_set(t) | |
matrixs.append(mathutils.Matrix(cube.matrix_world)) | |
return matrixs | |
def getJet(name="jet", n=4): | |
bpy.ops.object.select_all(action="DESELECT") | |
if name in bpy.data.meshes: | |
deleteMesh(name) | |
mesh = bpy.data.meshes.new(name) | |
obj = bpy.data.objects.new(name, mesh) | |
bpy.context.scene.collection.objects.link(obj) | |
vs = [(0, 0, i+1) for i in range(n)] | |
es = [(i, i+1) for i in range(n-1)] | |
mesh.from_pydata(vs, es, []) | |
mesh.update() | |
return obj | |
def getShapeKeysIndexes(obj, idx): | |
idxes = [] | |
bpy.ops.object.select_all(action="DESELECT") | |
obj.select_set(True) | |
bpy.context.view_layer.objects.active = obj | |
bpy.ops.object.shape_key_add(from_mix=False) | |
idxes.append(obj.active_shape_key_index) # Basis | |
for t in range(bpy.data.scenes["Scene"].frame_end): | |
bpy.ops.object.shape_key_add(from_mix=False) | |
idxes.append(obj.active_shape_key_index) | |
return idxes | |
def visibillity(obj, flag, t): | |
obj.hide_viewport = flag | |
obj.keyframe_insert(data_path="hide_viewport", frame=t) | |
obj.hide_render = flag | |
obj.keyframe_insert(data_path="hide_render", frame=t) | |
def setVertexPosition(obj, matrixs, v, j, sk_idx, cube): | |
obj.active_shape_key_index = sk_idx | |
shape_key = obj.data.shape_keys.key_blocks[sk_idx] | |
if j != 0: | |
shape_key.name = f"frame {j}" | |
bpy.ops.object.mode_set(mode="EDIT") | |
visibillity(obj, True, j) | |
if j < 3: | |
return | |
flag = False | |
for i in range(len(shape_key.data)): | |
loc = j - i - 1 | |
if not (0 <= loc and loc < len(matrixs)): | |
flag = True | |
break | |
shape_key.data[i].co = (matrixs[loc] @ v).xyz | |
visibillity(obj, flag, j) | |
if not flag: | |
for value, frame in zip([0, 1, 0], [j-1, j, j+1]): | |
shape_key.value = value | |
shape_key.keyframe_insert(data_path="value", frame=frame) | |
def setPositionsOfVertex(cube): | |
ret = [] | |
matrixs = getMatrixs(cube) | |
vs = [mathutils.Vector(v.co) for v in cube.data.vertices] | |
for i, v in enumerate(vs): | |
obj = getJet(name=f"{cube.name}_jet_{i}") | |
ret.append(obj) | |
idxes = getShapeKeysIndexes(obj, i) | |
bpy.ops.object.select_all(action="DESELECT") | |
cube.select_set(True) | |
bpy.context.view_layer.objects.active = cube | |
bpy.ops.object.mode_set(mode="OBJECT") | |
for j, sk_idx in enumerate(idxes): | |
setVertexPosition(obj, matrixs, v, j, sk_idx, cube) | |
bpy.ops.object.mode_set(mode="OBJECT") | |
return ret | |
def setMaterial(jets, name="jet_Material"): | |
if name in bpy.data.materials: | |
bpy.data.materials.remove(bpy.data.materials[name]) | |
bpy.ops.object.select_all(action="DESELECT") | |
bpy.context.view_layer.objects.active = jets[0] | |
bpy.ops.material.new() | |
mat = bpy.data.materials[-1] | |
mat.name = name | |
mat.use_nodes = True | |
bsdf = mat.node_tree.nodes["Principled BSDF"] | |
bsdf.inputs["Emission"].default_value = mathutils.Vector((1, 1, 1, 1)) | |
bsdf.inputs["Emission Strength"].default_value = 1.5 | |
return mat | |
def setNodes(jets, material, name="jet_NodeTree"): | |
if name in bpy.data.node_groups: | |
bpy.data.node_groups.remove(bpy.data.node_groups[name]) | |
bpy.ops.object.select_all(action="DESELECT") | |
bpy.context.view_layer.objects.active = jets[0] | |
bpy.ops.object.modifier_add(type="NODES") | |
mod = jets[0].modifiers.active | |
mod.name = name | |
bpy.ops.node.new_geometry_node_group_assign() | |
nodes = mod.node_group.nodes | |
links = mod.node_group.links | |
gi = nodes["Group Input"] | |
go = nodes["Group Output"] | |
sm = nodes.new(type="GeometryNodeSetMaterial") | |
sm.inputs['Material'].default_value = material | |
links.new(sm.outputs["Geometry"], go.inputs["Geometry"]) | |
c2m = nodes.new(type="GeometryNodeCurveToMesh") | |
c2m.inputs["Fill Caps"].default_value = True | |
links.new(c2m.outputs["Mesh"], sm.inputs["Geometry"]) | |
scr = nodes.new(type="GeometryNodeSetCurveRadius") | |
links.new(scr.outputs["Curve"], c2m.inputs["Curve"]) | |
cc = nodes.new(type="GeometryNodeCurvePrimitiveCircle") | |
cc.inputs['Resolution'].default_value = 6 | |
cc.inputs['Radius'].default_value = 0.05 | |
links.new(cc.outputs["Curve"], c2m.inputs["Profile Curve"]) | |
rsc = nodes.new(type="GeometryNodeResampleCurve") | |
links.new(rsc.outputs["Curve"], scr.inputs["Curve"]) | |
m2c = nodes.new(type="GeometryNodeMeshToCurve") | |
links.new(m2c.outputs["Curve"], rsc.inputs["Curve"]) | |
links.new(gi.outputs["Geometry"], m2c.inputs["Mesh"]) | |
mul = nodes.new(type="ShaderNodeMath") | |
mul.operation = "MULTIPLY" | |
mul.inputs[1].default_value = 2.0 | |
links.new(mul.outputs["Value"], scr.inputs["Radius"]) | |
fc = nodes.new(type="ShaderNodeFloatCurve") | |
ps = fc.mapping.curves[-1].points | |
ps[0].location = mathutils.Vector((0.0, 0.25)) | |
ps[1].location = mathutils.Vector((1.0, 0.0)) | |
cmp = ps.new(0.1, 1.0) | |
cmp.handle_type = "VECTOR" | |
ps.new(0.5, 0.25) | |
links.new(fc.outputs["Value"], mul.inputs[0]) | |
spp = nodes.new(type="GeometryNodeSplineParameter") | |
links.new(spp.outputs["Factor"], fc.inputs["Value"]) | |
for jet in jets: | |
jet.select_set(True) | |
bpy.ops.object.make_links_data(type="MODIFIERS") | |
setCamera() | |
setLight() | |
setPlane() | |
cube, n = setCube() | |
bpy.data.scenes["Scene"].frame_end = n | |
jets = setPositionsOfVertex(cube) | |
setNodes(jets, setMaterial(jets)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
dist145_cont.mp4