Last active
December 31, 2020 08:58
-
-
Save shspage/1b0d115b227c32ef8176e8572e805c30 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 math | |
import numpy as np | |
from time import time | |
# 参考: | |
# https://blender.stackexchange.com/questions/190547/mesh-edges-foreach-set-doesnt-update | |
bpy.app.handlers.frame_change_pre.clear() | |
bpy.app.handlers.frame_change_post.clear() | |
bpy.context.scene.frame_set(0) | |
class Params: | |
freq = 5.0 | |
speed = 0.4 | |
amp = 0.18 | |
radius = 7.0 | |
class MySceneLoop: | |
def __init__(self): | |
self.fc = 0 # frame count | |
self.t = None # time | |
self.vs = None # vertices | |
self.d1s = None # distances 1 | |
self.d2s = None # distandes 2 | |
def initPlane(self): | |
# Plane : a grid | |
# dots : a polyline on the grid | |
self.vs = bpy.data.objects['Plane'].data.vertices | |
self.d1s = [0.0] * len(self.vs) | |
self.d2s = [0.0] * len(self.vs) | |
dots = bpy.data.objects['dots'].data.vertices | |
for v in self.vs: | |
v.co.z = 0.0 | |
d1, d2 = self.minDist(v.co, dots) | |
self.d1s[v.index] = d1 | |
self.d2s[v.index] = d2 | |
def minDist(self, p, dots): | |
r = [(v.co - p).length for v in dots] | |
r.sort() | |
return r[0], r[1] | |
def my_handler(self, *args): | |
if self.t is None: | |
self.t = time() | |
scene = args[0] | |
self.fc = float(scene.frame_current) | |
pr = Params | |
for v in self.vs: | |
d1 = self.d1s[v.index] | |
d2 = self.d2s[v.index] | |
w1 = math.sin(d1 * pr.freq - (self.fc * pr.speed)) * pr.amp | |
w1 *= 1.0 - max(0, min(d1, pr.radius)) / pr.radius | |
w2 = math.sin(d2 * pr.freq - (self.fc * pr.speed)) * pr.amp | |
w2 *= 1.0 - max(0, min(d2, pr.radius)) / pr.radius | |
v.co.z = w1 + w2 | |
# shows elapsed time | |
if self.fc == 100: | |
print(time() - self.t) | |
class MySceneNp: | |
def __init__(self): | |
self.fc = 0 # frame count | |
self.t = None # time | |
self.vs = None # vertices | |
self.vsw = None # vertices (working) | |
self.d1s = None # distances 1 | |
self.d2s = None # distances 2 | |
def initPlane(self): | |
self.vs = bpy.data.objects['Plane'].data.vertices | |
d1s = [0.0] * len(self.vs) | |
d2s = [0.0] * len(self.vs) | |
dots = bpy.data.objects['dots'].data.vertices | |
for v in self.vs: | |
v.co.z = 0.0 | |
d1, d2 = self.minDist(v.co, dots) | |
d1s[v.index] = d1 | |
d2s[v.index] = d2 | |
self.d1s = np.array(d1s) | |
self.d2s = np.array(d2s) | |
vsw = np.zeros((len(self.vs) * 3), dtype=np.float) | |
self.vs.foreach_get("co", vsw) | |
self.vsw = np.reshape(vsw, (len(self.vs), 3)) | |
def minDist(self, p, dots): | |
r = [(v.co - p).length for v in dots] | |
r.sort() | |
return r[0], r[1] | |
def my_handler(self, *args): | |
if self.t is None: | |
self.t = time() | |
scene = args[0] | |
self.fc = float(scene.frame_current) | |
pr = Params | |
w1 = np.sin(self.d1s * pr.freq - (self.fc * pr.speed)) * pr.amp | |
w1 *= 1.0 - np.clip(self.d1s, 0, pr.radius) / pr.radius | |
w2 = np.sin(self.d2s * pr.freq - (self.fc * pr.speed)) * pr.amp | |
w2 *= 1.0 - np.clip(self.d2s, 0, pr.radius) / pr.radius | |
self.vsw[:, -1] = w1 + w2 | |
self.vs.foreach_set("co", self.vsw.ravel()) | |
bpy.data.meshes['Plane'].update() | |
# shows elapsed time | |
if self.fc == 100: | |
print(time() - self.t) | |
# run script, then start animation manually | |
#myscene = MySceneLoop() | |
myscene = MySceneNp() | |
myscene.initPlane() | |
bpy.app.handlers.frame_change_pre.append(myscene.my_handler) | |
print("done") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment