def setFile(self, filename): """ Redraws the spreadsheet with a new particle file """ if filename == self.filename: return self.filename = filename # reusing empty list causes column resizing problem so delete it if self.treeView and not self.hasParticles: self.layout().removeWidget(self.treeView) del self.treeView self.treeView = None if not self.treeView: self.treeView = QtWidgets.QTreeView() self.treeView.setRootIsDecorated(False) self.treeView.setUniformRowHeights(True) self.layout().addWidget(self.treeView) p = partio.read(filename) if not p: p = partio.create() self.hasParticles = False else: self.hasParticles = True model = PartioTreeModel(self.treeView, p, self.attrsOnly) proxyModel = FilterModel(self.lineEdit, self.attrsOnly, self) self.lineEdit.textChanged.connect(proxyModel.filter) proxyModel.setSourceModel(model) self.treeView.setModel(proxyModel) for i in range(model.columnCount(self.treeView)): self.treeView.resizeColumnToContents(i) self.setWindowTitle(filename) self.show()
def remove_particles(infile, outfile, keep_rate): """Remove a percentage of particles from a .bgeo file. Args: infile: Path to input .bgeo file. outfile: The file where the reduced number of particles will be stored. keep_rate: A float between 0 and 1 that describes how much percentage of particles will be kept in the new file. """ particles = partio.read(infile) orig_attr = particles.attributeInfo("position") orig_num_p = particles.numParticles() all_indices = np.arange(orig_num_p) keep_indices = np.random.choice(all_indices, size=int(orig_num_p * keep_rate), replace=False) new_particles = partio.create() P = new_particles.addAttribute("position", partio.VECTOR, 3) id = new_particles.addAttribute("id", partio.INT, 1) new_particles.addParticles(len(keep_indices)) for index, i in enumerate(keep_indices): pos = particles.get(orig_attr, i) new_particles.set(P, index, pos) partio.write(outfile, new_particles)
def createDelta(self): """ Creates a delta particle set between the current and original data set. This is the brute-force method, simply comparing the current data set against the original, but it's easier than tracking individual changes. """ def hashParticles(data): """ Given a partio data set, create a dictionary of hashes to indices """ items = {} numAttrs = data.numAttributes() for pnum in range(data.numParticles()): item = [] for anum in range(numAttrs): attr = data.attributeInfo(anum) item.append(data.get(attr, pnum)) items[hash(str(item))] = pnum return items # TODO: Handle new attributes as deltas # For now, any new attributes will write all of the particles # Hash up the new data into an index table newParticles = hashParticles(self.data) oldParticles = hashParticles(self.originalData) # If nothing changed, easy out data = partio.create() if newParticles == oldParticles: return data # Identify which particles changed oldHashes = set(oldParticles.keys()) newHashes = set(newParticles.keys()) modifiedHashes = newHashes - oldHashes # Create the new particle set numAttrs = self.data.numAttributes() newAttrs = [] oldAttrs = [] for anum in range(numAttrs): attr = self.data.attributeInfo(anum) oldAttrs.append(attr) newAttr = data.addAttribute(attr.name, attr.type, attr.count) newAttrs.append(newAttr) data.addParticles(len(modifiedHashes)) for newIndex, modifiedHash in enumerate(modifiedHashes): oldIndex = newParticles[modifiedHash] for anum, oldAttr in enumerate(oldAttrs): value = self.data.get(oldAttr, oldIndex) data.set(newAttrs[anum], newIndex, value) return data
def copy(srcData): """ Creates a copy of the given partio data set """ dstData = partio.create() srcAttrs = [] dstAttrs = [] for anum in range(srcData.numAttributes()): attr = srcData.attributeInfo(anum) srcAttrs.append(attr) dstAttrs.append(dstData.addAttribute(attr.name, attr.type, attr.count)) dstData.addParticles(srcData.numParticles()) for pnum in range(srcData.numParticles()): for anum, srcAttr in enumerate(srcAttrs): dstData.set(dstAttrs[anum], pnum, srcData.get(srcAttr, pnum)) return dstData
def partio_write_rigid_body(vertices, filename): """Write vertices of an object into a .bgeo file. Args: vertices: A num_vertices x 3 numpy array. filename: Path to the .bgeo file to create. """ os.makedirs(os.path.dirname(filename), exist_ok=True) particleSet = partio.create() P = particleSet.addAttribute("position", partio.VECTOR, 3) id = particleSet.addAttribute("id", partio.INT, 1) particleSet.addParticles(len(vertices)) for i, vertex in enumerate(vertices): particleSet.set(P, i, [float(x) for x in vertex]) partio.write(filename, particleSet)
def read(self, filename): """ Opens a file from disk and populates the UI """ if not os.path.exists(filename): sys.stderr.write('Invalid filename: {}\n'.format(filename)) return data = partio.read(filename) if not data: sys.stderr.write('Invalid particle file: {}\n'.format(filename)) data = partio.create() self.filename = filename self.setData(data) self.setDirty(False)
def write_bgeo_from_numpy(outpath, pos_arr, vel_arr): import partio n = pos_arr.shape[0] if not (vel_arr.shape[0] == n and pos_arr.shape[1] == 3 and vel_arr.shape[1] == 3): raise ValueError( "invalid shapes for pos_arr {} and/or vel_arr {}".format( pos_arr.shape, vel_arr.shape)) p = partio.create() position_attr = p.addAttribute("position", partio.VECTOR, 3) velocity_attr = p.addAttribute("velocity", partio.VECTOR, 3) for i in range(n): idx = p.addParticle() p.set(position_attr, idx, pos_arr[i].astype(float)) p.set(velocity_attr, idx, vel_arr[i].astype(float)) partio.write(outpath, p)
def removeAttributes(self, names): """ Removes the attributes with the given names. partio doesn't support removing data, so we have to construct all new data sans the given attribute(s). """ newData = partio.create() for anum in range(self.numAttributes()): attr = self.attributeInfo(anum) if attr.name not in names: newData.addAttribute(attr.name, attr.type, attr.count) # Copy particle data with new attributes copyParticles(src=self.data, dst=newData) # Copy fixed attributes for anum in range(self.data.numFixedAttributes()): oldAttr = self.data.fixedAttributeInfo(anum) newAttr = newData.addFixedAttribute(oldAttr.name, oldAttr.type, oldAttr.count) newData.setFixed(newAttr, self.data.getFixed(oldAttr)) self.setData(newData) self.setDirty(True)
def removeFixedAttributes(self, names): """ Removes the fixed attributes with the given names. partio doesn't support removing data, so we have to construct all new data sans the given attribute(s). """ newData = partio.create() # Copy the regular (non-fixed) attributes and particles for anum in range(self.data.numAttributes()): attr = self.attributeInfo(anum) newData.addAttribute(attr.name, attr.type, attr.count) copyParticles(src=self.data, dst=newData) # Create new fixed attributes for anum in range(self.data.numFixedAttributes()): srcAttr = self.fixedAttributeInfo(anum) if srcAttr.name not in names: dstAttr = newData.addFixedAttribute(srcAttr.name, srcAttr.type, srcAttr.count) newData.setFixed(dstAttr, self.data.getFixed(srcAttr)) self.setData(newData) self.setDirty(True)
def run(config): os.environ[ "CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" # so the IDs match nvidia-smi os.environ["CUDA_VISIBLE_DEVICES"] = config.gpu_id # "0, 1" for multiple prepare_dirs_and_logger(config) tf.compat.v1.set_random_seed(config.seed) config.rng = np.random.RandomState(config.seed) styler = Styler(config) styler.load_img(config.resolution[1:]) params = {} # load particles nmin, nmax = np.iinfo(np.int32).max, 0 for i in range(config.num_frames): pt_path = os.path.join(config.data_dir, config.dataset, config.d_path % (config.target_frame + i)) pt = partio.read(pt_path) p_num = pt.numParticles() nmin = min(p_num, nmin) nmax = max(p_num, nmax) print('# range:', nmin, nmax) p = [] # r = [] for i in trange(config.num_frames, desc='load particle'): # last one for mask pt_path = os.path.join(config.data_dir, config.dataset, config.d_path % (config.target_frame + i)) pt = partio.read(pt_path) p_attr_id = pt.attributeInfo('id') p_attr_pos = pt.attributeInfo('position') # p_attr_den = pt.attributeInfo('density') p_ = np.ones([nmax, 3], dtype=np.float32) * -1 # r_ = np.zeros([nmax,1], dtype=np.float32) p_num = pt.numParticles() for j in range(p_num): p_id_j = pt.get(p_attr_id, j)[0] p_[p_id_j] = pt.get(p_attr_pos, p_id_j) # r_[p_id_j] = pt.get(p_attr_den, p_id_j) # r.append(r_) # normalize particle position [0-1] px, py, pz = p_[..., 0], p_[..., 1], p_[..., 2] px /= config.domain[2] py /= config.domain[1] pz /= config.domain[0] p_ = np.stack([pz, py, px], axis=-1) p.append(p_) print('resolution:', config.resolution) print('domain:', config.domain) print('radius:', config.radius) print('normalized px range', px.min(), px.max()) print('normalized py range', py.min(), py.max()) params['p'] = p # styler.render_test(params) result = styler.run(params) # save loss plot l = result['l'] lb = [] for o, l_ in enumerate(l): lb_, = plt.plot(range(len(l_)), l_, label='oct %d' % o) lb.append(lb_) plt.legend(handles=lb) # plt.show() plot_path = os.path.join(config.log_dir, 'loss_plot.png') plt.savefig(plot_path) # save particle (load using Houdini GPlay) p_sty = result['p'] p = [] # v_sty = result['v'] # v = [] for i in range(config.num_frames): # denormalize particle positions px, py, pz = p_sty[i][..., 2], p_sty[i][..., 1], p_sty[i][..., 0] px *= config.domain[2] py *= config.domain[1] pz *= config.domain[0] p_sty_ = np.stack([px, py, pz], axis=-1) p.append(p_sty_) # # denormalize particle displacement for stylization # vx, vy, vz = v_sty[i][...,2], v_sty[i][...,1], v_sty[i][...,0] # vx *= config.domain[2] # vy *= config.domain[1] # vz *= config.domain[0] # v_sty_ = np.stack([vx,vy,vz], axis=-1) # v.append(v_sty_) # create a particle set and attributes pt = partio.create() position = pt.addAttribute("position", partio.VECTOR, 3) # color = pt.addAttribute("Cd",partio.FLOAT,3) radius = pt.addAttribute("radius", partio.FLOAT, 1) # normal = pt.addAttribute("normal",partio.VECTOR,3) for p_sty_i in p_sty_: if p_sty_i[0] < 0: continue p_ = pt.addParticle() pt.set(position, p_, tuple(p_sty_i.astype(np.float))) pt.set(radius, p_, (config.radius, )) p_path = os.path.join(config.log_dir, '%03d.bgeo' % (config.target_frame + i)) partio.write(p_path, pt) r_sty = result['r'] for i, r_sty_ in enumerate(r_sty): im = Image.fromarray(r_sty_) d_path = os.path.join(config.log_dir, '%03d.png' % (config.target_frame + i)) im.save(d_path) d_intm = result['d_intm'] for o, d_intm_o in enumerate(d_intm): for i, d_intm_ in enumerate(d_intm_o): if d_intm_ is None: continue im = Image.fromarray(d_intm_) d_path = os.path.join( config.log_dir, 'o%02d_%03d.png' % (o, config.target_frame + i)) im.save(d_path) # visualization using open3d bbox = [ [0, 0, 0], [config.domain[2], config.domain[1], config.domain[0]], # [X,Y,Z] ] draw_pt(p, bbox=bbox, dt=0.1, is_2d=False) # pv=v,
import partio selected = cmds.ls(sl=True) cmds.select(hi=True) particles = cmds.ls(sl=True, type='particle') path = 'Z:/marza/proj/onyx/team/lookdev/bake/nodesOfTime' for pobj in particles: pset = partio.create() pattr = pset.addAttribute("position", partio.VECTOR, 3) cattr = pset.addAttribute("color", partio.VECTOR, 3) nattr = pset.addAttribute("normal", partio.VECTOR, 3) pcount = cmds.getAttr(pobj + '.count') pset.addParticles(pcount) print('[Particle Export] Exporting %s (%d points)...' % (pobj, pcount)) for i in range(pcount): # get position pos = cmds.getParticleAttr(pobj + '.pt[%d]' % i, at='position')[0:3] # get color if cmds.attributeQuery('rgbPP', n=pobj, ex=True): col = cmds.getParticleAttr(pobj + '.pt[%d]' % i, at='rgbPP')[0:3] elif cmds.attributeQuery('colorRed', n=pobj, ex=True): col = (cmds.getAttr(pobj + '.colorRed'), cmds.getAttr(pobj + '.colorGreen'), cmds.getAttr(pobj + '.colorBlue')) else: col = (1, 0, 0) # normal nml = (0, 0, 0) # set attributes
def __init__(self): QObject.__init__(self) self.setData(partio.create()) self.filename = None self.dirty = False
def fromJson(data): """ Converts a json dictionary to a particle set """ particleSet = partio.create() # Convert fixed attributes fixedAttributes = {} if 'fixedAttributes' in data: for attrName, attrInfo in data['fixedAttributes'].items(): attrName = str(attrName) attr = particleSet.addFixedAttribute(attrName, attrInfo['type'], attrInfo['count']) fixedAttributes[attrName] = attr if len(attrInfo['value']) == attrInfo['count']: particleSet.setFixed(attr, attrInfo['value']) else: sys.stderr.write( 'Mismatched count for fixed attribute {}. Skipping.\n'. format(attrName)) # Convert attributes attributes = {} if 'attributes' in data: for attrName, attrInfo in data['attributes'].items(): attrName = str(attrName) attr = particleSet.addAttribute(attrName, attrInfo['type'], attrInfo['count']) attributes[attrName] = attr # Convert fixed indexed strings if 'fixedIndexedStrings' in data: for attrName, strings in data['fixedIndexedStrings'].items(): if attrName not in fixedAttributes: sys.stderr.write( 'Could not match fixed indexed string {} with any defined fixed attribute. Skipping.\n' .format(attrName)) continue for string in strings: particleSet.registerFixedIndexedStr(fixedAttributes[attrName], string) # Convert indexed strings if 'indexedStrings' in data: for attrName, strings in data['indexedStrings'].items(): if attrName not in attributes: sys.stderr.write( 'Could not match indexed string {} with any defined attribute. Skipping.\n' .format(attrName)) continue for string in strings: particleSet.registerIndexedStr(attributes[attrName], str(string)) # Convert particles if 'particles' in data: particleSet.addParticles(len(data['particles'])) for pnum, particle in data['particles'].items(): pnum = int(pnum) for attrName, value in particle.items(): try: attr = attributes[attrName] except IndexError: sys.stderr.write( 'Could not match attribute "{}" for particle {} with any defined attributes. Skipping.\n' .format(attrName, pnum)) continue if len(value) != attr.count: sys.stderr.write( 'Mismatched count for attribute "{}" ({}) and particle {} ({}). Skipping.\n' .format(attrName, attr.count, pnum, len(value))) continue particleSet.set(attr, pnum, value) return particleSet
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED. # IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. import partio # create a particle set and attributes p=partio.create() position=p.addAttribute("position",partio.VECTOR,3) color=p.addAttribute("Cd",partio.FLOAT,3) radius=p.addAttribute("radius",partio.FLOAT,1) normal=p.addAttribute("normal",partio.VECTOR,3) # make a spiral circle thingy t=0 dt=.01 import math while t<2*math.pi: # allocate new particle i=p.addParticle() # set particle attributes
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED. # IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. import partio # create a particle set and attributes p = partio.create() position = p.addAttribute("position", partio.VECTOR, 3) color = p.addAttribute("Cd", partio.FLOAT, 3) radius = p.addAttribute("radius", partio.FLOAT, 1) normal = p.addAttribute("normal", partio.VECTOR, 3) # make a spiral circle thingy t = 0 dt = .01 import math while t < 2 * math.pi: # allocate new particle i = p.addParticle() # set particle attributes
def run(config): os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" # so the IDs match nvidia-smi os.environ["CUDA_VISIBLE_DEVICES"] = config.gpu_id # "0, 1" for multiple prepare_dirs_and_logger(config) tf.compat.v1.set_random_seed(config.seed) config.rng = np.random.RandomState(config.seed) styler = Styler(config) styler.load_img(config.resolution) params = {} # load particles p = [] r = [] for i in trange(config.num_frames, desc='load particle'): pt_path = os.path.join(config.data_dir, config.dataset, config.d_path % (config.target_frame+i)) pt = partio.read(pt_path) p_id = pt.attributeInfo('id') p_pos = pt.attributeInfo('position') p_den = pt.attributeInfo('density') p_num = pt.numParticles() p_ = np.zeros([p_num,2], dtype=np.float32) r_ = np.zeros([p_num,1], dtype=np.float32) for j in range(p_num): p_id_ = pt.get(p_id, j)[0] p_[p_id_] = pt.get(p_pos, p_id_)[:-1] # 2d r_[p_id_] = pt.get(p_den, p_id_) r.append(r_) # normalize particle position [0-1] px, py = p_[...,0], p_[...,1] px /= config.domain[1] py /= config.domain[0] p_ = np.stack([py,px], axis=-1) p.append(p_) print('resolution:', config.resolution) print('domain:', config.domain) print('radius:', config.radius) print('normalized px range', px.min(), px.max()) print('normalized py range', py.min(), py.max()) print('num particles:', p[0].shape) # the number of particles is fixed params['p'] = p params['r'] = r # styler.render_test(params) result = styler.run(params) # save loss plot l = result['l'] lb = [] for o, l_ in enumerate(l): lb_, = plt.plot(range(len(l_)), l_, label='oct %d' % o) lb.append(lb_) plt.legend(handles=lb) # plt.show() plot_path = os.path.join(config.log_dir, 'loss_plot.png') plt.savefig(plot_path) # save density fields d_sty = result['d'] # [0-255], uint8 # d_path = os.path.join(config.log_dir, 'd%03d_%03d.png' % (config.target_frame,config.target_frame+config.num_frames-1)) # save_image(d_sty, d_path, nrow=5, gray=not 'c' in config.target_field) for i, d_sty_ in enumerate(d_sty): im = Image.fromarray(d_sty_) d_path = os.path.join(config.log_dir, '%03d.png' % (config.target_frame+i)) im.save(d_path) d_intm = result['d_intm'] for o, d_intm_o in enumerate(d_intm): for i, d_intm_ in enumerate(d_intm_o): im = Image.fromarray(d_intm_) d_path = os.path.join(config.log_dir, 'o%02d_%03d.png' % (o, config.target_frame)) im.save(d_path) # save particles (load using Houdini GPlay) c_sty = result['c'] p_org = [] for p_ in p: # denormalize particle positions px, py = p_[...,1], p_[...,0] px *= config.domain[1] py *= config.domain[0] p_org.append(np.stack([px,py], axis=-1)) for i in range(config.num_frames): # create a particle set and attributes pt = partio.create() position = pt.addAttribute("position",partio.VECTOR,2) color = pt.addAttribute("Cd",partio.FLOAT,3) radius = pt.addAttribute("radius",partio.FLOAT,1) # normal = pt.addAttribute("normal",partio.VECTOR,3) for pi in range(p_org[i].shape[0]): p_ = pt.addParticle() pt.set(position, p_, tuple(p_org[i][pi].astype(np.float))) pt.set(color, p_, tuple(c_sty[i][pi].astype(np.float))) pt.set(radius, p_, (config.radius,)) p_path = os.path.join(config.log_dir, '%03d.bgeo' % (config.target_frame+i)) partio.write(p_path, pt) # visualization using open3d bbox = [ [0,0,-1], [config.domain[1],config.domain[0],1], # [X,Y,Z] ] draw_pt(p_org, pc=c_sty, bbox=bbox, dt=0.1)
def run(config): os.environ[ "CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" # so the IDs match nvidia-smi os.environ["CUDA_VISIBLE_DEVICES"] = config.gpu_id # "0, 1" for multiple prepare_dirs_and_logger(config) tf.compat.v1.set_random_seed(config.seed) config.rng = np.random.RandomState(config.seed) resampler = SimG2P(config) # load input density fields for t in trange(config.num_frames, desc='load density'): # last one for mask d_path = os.path.join(config.data_dir, config.dataset, config.d_path % (config.target_frame + t)) with np.load(d_path) as data: d = data['x'][:, ::-1] # [D,H,W], [0-1] # mantaflow dataset v_path = os.path.join(config.data_dir, config.dataset, config.v_path % (config.target_frame + t)) with np.load(v_path) as data: v_ = data['x'] # [D,H,W,3] vx = np.dstack( (v_, np.zeros((v_.shape[0], v_.shape[1], 1, v_.shape[3])))) vx = (vx[:, :, 1:, 0] + vx[:, :, :-1, 0]) * 0.5 vy = np.hstack( (v_, np.zeros((v_.shape[0], 1, v_.shape[2], v_.shape[3])))) vy = (vy[:, 1:, :, 1] + vy[:, :-1, :, 1]) * 0.5 vz = np.vstack( (v_, np.zeros((1, v_.shape[1], v_.shape[2], v_.shape[3])))) vz = (vz[1:, :, :, 2] + vz[:-1, :, :, 2]) * 0.5 v_ = np.stack([vx, vy, vz], axis=-1) v_ = v_[:, ::-1] vx = v_[..., 0] / v_.shape[2] * config.scale vy = -v_[..., 1] / v_.shape[1] * config.scale vz = v_[..., 2] / v_.shape[0] * config.scale u = np.stack([vz, vy, vx], axis=-1) if config.resampling: if t == 0: n_prev = 0 # sampling at the beginning wo opt. p, p_id = resampler.sample(d, disc=config.disc, threshold=0) result = resampler.optimize(p, p_id, d, u) p = result['p'] p_id = result['p_id'] p_den = result['p_den'] # d_diff = result['d_diff'] # plt.imshow(d_diff); plt.show() l = result['l'][-1] # last loss d_smp = result['d_smp'] else: if t == 0: n_prev = 0 # sampling at the beginning wo opt. p, p_id = resampler.sample(d, disc=config.disc, threshold=0) p_src = p else: # simply source particles of t=0 p = np.concatenate([p, p_src], axis=0) p_id = np.arange(p.shape[0]) p_den = np.ones([p.shape[0], 1]) p, d_smp = resampler.naive_adv(p, u, p_den) l = 0 print(t, 'num particles', p.shape[0], '(+%d)' % (p.shape[0] - n_prev), 'loss', l) n_prev = p.shape[0] # convert to the original domain coordinate px, py, pz = p[..., 2], 1 - p[..., 1], p[..., 0] p_ = np.stack([ px * config.domain[2], py * config.domain[1], pz * config.domain[0] ], axis=-1) # create a particle set and attributes pt = partio.create() pid = pt.addAttribute('id', partio.INT, 1) position = pt.addAttribute("position", partio.VECTOR, 3) if p_den.shape[1] > 1: density = pt.addAttribute('density', partio.VECTOR, p_den.shape[1]) else: density = pt.addAttribute('density', partio.FLOAT, 1) color = pt.addAttribute("Cd", partio.FLOAT, 3) radius = pt.addAttribute("radius", partio.FLOAT, 1) for i in range(p_.shape[0]): pt_ = pt.addParticle() pt.set(pid, pt_, (int(p_id[i]), )) pt.set(position, pt_, tuple(p_[i].astype(np.float))) if p_den.shape[1] > 1: pt.set(density, pt_, tuple(p_den[i].astype(np.float))) else: pt.set(density, pt_, (float(p_den[i]), )) pt.set(color, pt_, tuple(np.array([p_den[i, 0]] * 3, dtype=np.float))) pt.set(radius, pt_, (config.radius, )) # save particle p_path = os.path.join(config.log_dir, '%03d.bgeo' % (config.target_frame + t)) partio.write(p_path, pt) # save density image transmit = np.exp(-np.cumsum(d_smp[::-1], axis=0) * config.transmit) d_img = np.sum(d_smp * transmit, axis=0) d_img /= d_img.max() im = Image.fromarray((d_img[::-1] * 255).astype(np.uint8)) im_path = os.path.join(config.log_dir, '%03d.png' % (config.target_frame + t)) im.save(im_path) stat_path = os.path.join(config.log_dir, 'stat.txt') with open(stat_path, 'w') as f: f.write('num particles %d\n' % p.shape[0]) f.write('loss %.2f' % l)
def fromJson(data): """ Converts a json dictionary to a particle set """ particleSet = partio.create() # Convert fixed attributes fixedAttributes = {} if 'fixedAttributes' in data: for attrName, attrInfo in data['fixedAttributes'].items(): attrName = str(attrName) attr = particleSet.addFixedAttribute(attrName, attrInfo['type'], attrInfo['count']) fixedAttributes[attrName] = attr if len(attrInfo['value']) == attrInfo['count']: particleSet.setFixed(attr, attrInfo['value']) else: sys.stderr.write('Mismatched count for fixed attribute {}. Skipping.\n'.format(attrName)) # Convert attributes attributes = {} if 'attributes' in data: for attrName, attrInfo in data['attributes'].items(): attrName = str(attrName) attr = particleSet.addAttribute(attrName, attrInfo['type'], attrInfo['count']) attributes[attrName] = attr # Convert fixed indexed strings if 'fixedIndexedStrings' in data: for attrName, strings in data['fixedIndexedStrings'].items(): if attrName not in fixedAttributes: sys.stderr.write('Could not match fixed indexed string {} with any defined fixed attribute. Skipping.\n'.format(attrName)) continue for string in strings: particleSet.registerFixedIndexedStr(fixedAttributes[attrName], string) # Convert indexed strings if 'indexedStrings' in data: for attrName, strings in data['indexedStrings'].items(): if attrName not in attributes: sys.stderr.write('Could not match indexed string {} with any defined attribute. Skipping.\n'.format(attrName)) continue for string in strings: particleSet.registerIndexedStr(attributes[attrName], str(string)) # Convert particles if 'particles' in data: particleSet.addParticles(len(data['particles'])) for pnum, particle in data['particles'].items(): pnum = int(pnum) for attrName, value in particle.items(): try: attr = attributes[attrName] except IndexError: sys.stderr.write('Could not match attribute "{}" for particle {} with any defined attributes. Skipping.\n'.format(attrName, pnum)) continue if len(value) != attr.count: sys.stderr.write('Mismatched count for attribute "{}" ({}) and particle {} ({}). Skipping.\n'.format(attrName, attr.count, pnum, len(value))) continue particleSet.set(attr, pnum, value) return particleSet