def test_disconnect_tree(): n = 8 ssos = [SSO(str(i)) for i in xrange(n)] partial = [0, 1, 1, 2, 3, 3, 5, 6] top = SSO.connect_tree(ssos, partial) top.disconnect_tree() assert not any(sso.hasParent() for sso in ssos)
def test_connect_tree(): n = 4 ssos = [SSO(str(i)) for i in xrange(n)] partial = [0, 1, 1, 2] top = SSO.connect_tree(ssos, partial) top2 = ssos[0] ssos[1].reparentTo(ssos[0]) ssos[2].reparentTo(ssos[0]) ssos[3].reparentTo(ssos[1]) assert top.tree() == top2.tree()
def test_build_tree(): n = 4 ssos = [SSO(str(i)) for i in xrange(n)] props = [SSO(str(i)).read_prop() for i in xrange(n)] partial = [0, 1, 1, 2] top = SSO.build_tree(ssos, partial) top2 = SSO.build_tree(props, partial) top3 = ssos[0] ssos[1].reparentTo(ssos[0]) ssos[2].reparentTo(ssos[0]) ssos[3].reparentTo(ssos[1]) assert top.tree() == top3.tree() assert top.tree_prop() == top2.tree_prop()
def _prepare_resources(self): """Set up all of the nodes and physics resources.""" # Set up scene. self.scene = SSO("scene") # Physics. self.bbase = BulletBase() self.bbase.init() self.bbase.gravity = self.params["physics"]["gravity"] self.bbase.sim_par = { "size": self.params['simulation']["step_size"], "n_subs": self.params['simulation']['n_substeps'], "size_sub": self.params['simulation']["substep_size"], }
def test_tree_prop(): n = 8 ssos = [SSO(str(i)) for i in xrange(n)] partial = [0, 1, 1, 2, 3, 3, 5, 6] # for c, p in izip(ssos, partial): # if p > 0: # c.reparentTo(ssos[p - 1]) SSO.connect_tree(ssos, partial) ssos.append(NodePath("last")) ssos[-1].reparentTo(ssos[-2]) props = [SSO.cast(c).read_prop() for c in ssos] props2, partial2 = ssos[0].tree_prop() assert sorted(props) == sorted(props2)
def __init__(self, *args, **kwargs): # Converts args so they're appropriate for self.type_. if len(args) == 0: args = ("", ) if isinstance(args[0], str): args = (self.type_(args[0]), ) + args[1:] tag = self.__class__ else: tag = None ## Using super fails, probably because NodePath is a C++ class. # super(PSO, self).__init__(self, *new_args, **kwargs) SSO.__init__(self, *args, **kwargs) if tag: self.setPythonTag("sso", tag)
def __init__(self, *args, **kwargs): # Converts args so they're appropriate for self.type_. if len(args) == 0: args = ("",) if isinstance(args[0], str): args = (self.type_(args[0]),) + args[1:] tag = self.__class__ else: tag = None ## Using super fails, probably because NodePath is a C++ class. # super(PSO, self).__init__(self, *new_args, **kwargs) SSO.__init__(self, *args, **kwargs) if tag: self.setPythonTag("sso", tag)
def test_cpso_init_tree(): c = 3. n = 4 sso = SSO("parent") cpso = CPSO("foo") cpso.reparentTo(sso) objs = [RBSO(str(i)) for i in xrange(n)] for obj in objs: obj.setPos((c * (i - np.floor(n / 2.)), 0, 0)) obj.set_shape("Box") cpso.add(objs) sso.init_tree(tags=("shape", )) assert cpso.node().getNumShapes() == n for obj in cpso.components: assert obj.node().getNumShapes() == 0
def test_res_tags(): sso = SSO("sso") gso = GSO("gso") brso = RBSO("pso") assert set(sso.res_tags) == set(SSO._res_tags) assert set(gso.res_tags) == set(SSO._res_tags + GSO._res_tags) assert set(brso.res_tags) == set(SSO._res_tags + PSO._res_tags + RBSO._res_tags)
def load(args): """ Setup Bullet and load SSOs from input arguments.""" ssos = [] for filename in args: if path(filename).isfile(): ssos.append(SSO.load_tree(filename)) else: print("Cannot find file: %s" % filename) return ssos
def test_tree(): n = 8 ssos = [SSO(str(i)) for i in xrange(n)] partial = [0, 1, 1, 2, 3, 3, 5, 6] for c, p in izip(ssos, partial): if p > 0: c.reparentTo(ssos[p - 1]) ssos2, partial2 = ssos[0].tree() assert sorted(ssos) == sorted(ssos2)
def test_from_tag(): np = NodePath("sso") np.setPythonTag("sso", SSO) np2 = NodePath("gso") np2.setPythonTag("sso", GSO) assert not isinstance(np, SSO) assert not isinstance(np2, GSO) assert isinstance(SSO.from_tag(np), SSO) assert isinstance(GSO.from_tag(np2), GSO)
def test_read_dump(): sso = SSO("foo") with tmpfile() as pth: with pth.open("w") as fid: sso.dump(fid) with pth.open() as fid: read = SSO.read(fid) assert (sso.__class__, sso.read_prop()) == read
def test_cast(): sso = SSO.cast(NodePath("sso")) gso = GSO.cast(NodePath("gso")) pso = PSO.cast(NodePath("pso")) ghso = GHSO.cast(NodePath("ghso")) rbso = RBSO.cast(NodePath("rbso")) assert isinstance(sso, NodePath) assert isinstance(sso, SSO) assert isinstance(gso, NodePath) assert isinstance(gso, SSO) assert isinstance(gso, GSO) assert isinstance(ghso, NodePath) assert isinstance(ghso, SSO) assert isinstance(ghso, PSO) assert isinstance(ghso, GHSO) assert isinstance(rbso, NodePath) assert isinstance(rbso, SSO) assert isinstance(rbso, PSO) assert isinstance(rbso, RBSO)
def test_name_immutability(): sso = SSO("foo") before = sso.read_prop() before["name"] = "bar" assert sso.read_prop()["name"] != before["name"]
def test_init(): np = NodePath("np") np.setPythonTag("sso", GSO) npsso = SSO(np) assert isinstance(npsso, NodePath) assert isinstance(npsso, SSO)
def test_reads_dumps(): sso = SSO("foo") dump = sso.dumps() read = SSO.reads(dump) assert (sso.__class__, sso.read_prop()) == read
def test_sso(): obj = SSO("sso") assert isinstance(obj.node(), PandaNode)
def test_save_load_tree(): sso = SSO("foo") sso2 = SSO("bar") sso2.reparentTo(sso) with tmpfile() as pth: with pth.open("w") as fid: sso.save_tree(fid) sso3 = SSO.load_tree(pth) with pth.open() as fid: sso4 = SSO.load_tree(fid) sso.save_tree(pth) sso5 = SSO.load_tree(pth) with pth.open() as fid: sso6 = SSO.load_tree(fid) assert (sso.tree_prop() == sso3.tree_prop() == sso4.tree_prop() == sso5.tree_prop() == sso6.tree_prop())
def test_copy(): sso = SSO("foo") sso2 = SSO("bar") sso2.reparentTo(sso) assert sso.copy().tree_prop() == sso.tree_prop()
def test_apply_prop_read_prop_SSO(): sso = SSO("foo") other = SSO("other") other.setPos(100, 200, 300) other.setHpr(23, 20, 100) other.setScale(6, 2, 9) prop0 = { "name": "testname", "pos": Point3(1, 2, 3), "quat": Quat(2**0.5, 2**0.5, 0, 0), "scale": Vec3(10, 9, 8), } sso.setName(prop0["name"]) sso.setPos(prop0["pos"]) sso.setQuat(prop0["quat"]) sso.setScale(prop0["scale"]) assert prop0 == sso.read_prop() oprop = sso.read_prop(other=other) sso.wrtReparentTo(other) assert sso.read_prop() == oprop
def test_loads_dumps(): sso = SSO("foo") dump = sso.dumps() sso2 = SSO.loads(dump) assert (sso.__class__, sso.read_prop()) == (sso2.__class__, sso2.read_prop())
def test_pos_immutability(): sso = SSO("foo") before = sso.read_prop() before["pos"][0] = 10 assert sso.read_prop()["pos"] != before["pos"]
class Viewer(ShowBase, object): """ Viewer for SSOs.""" def __init__(self): ShowBase.__init__(self) resize_window = ConfigVariableBool('viewer-resize-window', '#t') if resize_window.getValue(): self.win_size = (800, 800) # Black background self.win.setClearColor((0.0, 0.0, 0.0, 1.0)) # Set up lights. self.lights = NodePath("lights") # Spotlight. Casts shadows. slight = Spotlight("slight") slight.setScene(self.render) slight.setShadowCaster(True, 2**11, 2**11) # Set shadow mask, so we can exclude objects from casting shadows self.shadow_mask = BitMask32.bit(2) slight.setCameraMask(self.shadow_mask) slight.setColor((1.2, 1.2, 1.2, 1.)) slight.getLens().setFov(45) slight.getLens().setNearFar(1, 100) slnp = self.lights.attachNewNode(slight) slnp.setPos((6, 8, 20)) slnp.lookAt(0, 0, 0) self.render.setLight(slnp) # Ambient light. alight = AmbientLight("alight") a = 0.75 alight.setColor((a, a, a, 1.0)) #alight.setColor((0.8, 0.8, 0.8, 1.0)) alnp = self.lights.attachNewNode(alight) self.render.setLight(alnp) self.lights.reparentTo(self.render) # Set auto shading for shadows use_shaders = ConfigVariableBool('viewer-use-shaders', '#t') if use_shaders.getValue(): self.render.setShaderAuto() # Set antialiasing on self.render.setAntialias(AntialiasAttrib.MAuto) # Camera self.camera_rot = self.render.attachNewNode("camera_rot") self.cameras = self.camera_rot.attachNewNode("cameras") self.cameras.setPos(14, 32, 9.) self.look_at = self.render.attachNewNode("look_at") self.look_at.setPos(Point3(2, 0, 1)) self.cameras.lookAt(self.look_at) self.camera.reparentTo(self.cameras) # Adjust the camera's lens lens = PerspectiveLens() self.camLens = lens self.camLens.setNearFar(0.01, 1000.0) setlens = ConfigVariableBool('viewer-set-cam-lens', '#t') if setlens: self.cam.node().setLens(self.camLens) # # Initialize / set variables self.sso = None self.ssos = [] self.cache = None self.scene = SSO("scene") self.scene.reparentTo(self.render) # Key callbacks. self.accept("shift-control-escape", self.exit) self.accept("escape", self.exit) self.accept("0", self.reset_sso) self.accept("arrow_left", self.prev) self.accept("arrow_right", self.next) self.accept("page_down", self.prev, [100]) self.accept("page_up", self.next, [100]) self.accept("f1", self.toggle_debug) self.accept("o", self.physics_once, extraArgs=[1. / 10]) self.accept("i", self.physics_once, extraArgs=[1. / 10000]) # Remove existing keyboard tasks. self.mandatory_events = ("window-event", "async_loader_0", "render-texture-targets-changed", "shift-control-escape") # Task list: name: (key, args) events = { "physics": ("p", ), "repel": ("t", ), "bump": ("f", ), "rotate": ("r", 20), "rotate90": ("h", ), "ss_task": ("s", ), "ssa_task": ("w", ), "bp": ("b", ) } # Add events for key, val in events.iteritems(): call = [key] + list(val[1:]) self.accept(val[0], self.toggle_task, call) # These are the key events that we will never ignore self.permanent_events = self.getAllAccepting() # These are the key events that we will never ignore self.permanent_tasks = [ task.getName() for task in self.taskMgr.getAllTasks() ] self.start_time = -1 self.old_elapsed = 0 @property def win_size(self): """ Returns window size.""" props = WindowProperties(self.win.getProperties()) return props.getXSize(), props.getYSize() @win_size.setter def win_size(self, wh): """ Sets window size.""" props = WindowProperties(self.win.getProperties()) props.setSize(*wh) self.size = wh self.win.requestProperties(props) def toggle_fullscreen(self): """ Toggles fullscreen mode.""" props = WindowProperties(self.win.getProperties()) if props.getFullscreen(): props.setSize(*self.size) props.setFullscreen(False) else: w = self.pipe.getDisplayWidth() h = self.pipe.getDisplayHeight() props.setSize(w, h) props.setFullscreen(True) self.win.requestProperties(props) def _get_screen_size(self): winx = self.win.getXSize() winy = self.win.getYSize() return winx, winy def _convert_coordinate(self, P0): """ Convert 3 coordinates to 2d projection, and 2d coordinates to 3d extrusion.""" P0 = array(P0) proj_mat = get_projection_mat(self.cam) if P0.size == 2: # 2d to 3d. line = extrude(P0, proj_mat) normal = array((0., 0., 1.)) P = plane_intersection(line, array(self.origin), normal) else: # 3d to 2d. P = project(P0, proj_mat) return P def _get_screen_mouse_location(self): """ Gets mouse location in screen coordinates.""" md = self.win.getPointer(0) s2d = array((md.getX(), md.getY())) return s2d def _set_screen_mouse_location(self, s2d): """ Sets mouse location in screen coordinates.""" self.win.movePointer(0, *s2d.astype("i")) def _get_cursor_location(self): """ Return cursor's 2D or 3D location.""" # Mouse's screen coordinates x = self.mouseWatcherNode.getMouseX() y = self.mouseWatcherNode.getMouseY() return self._convert_coordinate((x, y)) def _set_cursor_location(self, p2d): """ Sets cursor location in window coords [-1, 1].""" s2d = ((p2d * array( (1, -1)) + 1.) / 2. * array(self._get_screen_size())) self._set_screen_mouse_location(s2d) def _set_cursor_hidden(self, b): """ Toggle cursor.""" props = WindowProperties() props.setCursorHidden(b) self.win.requestProperties(props) def draw_cursor2d(self, task): """ Draw cursor indicator.""" if getattr(self, "cursor", None) and self.mouseWatcherNode.hasMouse(): res = self._get_screen_size() ar = float(res[0]) / res[1] mx = self.mouseWatcherNode.getMouseX() my = self.mouseWatcherNode.getMouseY() self.cursor.setPos(mx * ar, 0, my) return task.cont # def draw_cursor2d(self, task): # """ Draw cursor indicator.""" # if getattr(self, "cursor", None) and self.mouseWatcherNode.hasMouse(): # mx = self.mouseWatcherNode.getMouseX() # my = self.mouseWatcherNode.getMouseY() # p3d = self._convert_coordinate((mx, my)) # p2d = self._convert_coordinate(p3d)[0].squeeze() # res = self._get_screen_size() # ar = float(res[0]) / res[1] # x = p2d[0] * ar # y = p2d[1] # self.cursor.setPos(x, 0., y) # return task.cont def init_physics(self, bbase): """ Initialize the physics resources.""" self.bbase = bbase self.debug_np = self.render.attachNewNode(self.bbase.setup_debug()) def init_ssos(self, ssos): """ Initialize the ssos.""" GSO.loader = Loader # self.graphicsEngine.getDefaultLoader() # Put all the input ssos into one list. self.ssos = [] for sso in ssos: if not isinstance(sso, NodePath): raise TypeError("Must be NodePath: %s (%s)" % (sso, type(sso))) # Set up the node and its descendants. sso.init_tree(tags=("model", )) self.ssos.append(sso) # Number of ssos. self.n_ssos = len(self.ssos) def init_background(self, bg): """ Initialize the background.""" # Put all the input ssos into one list. if not isinstance(bg, NodePath): raise TypeError("Must be NodePath: %s (%s)" % (bg, type(bg))) GSO.loader = Loader # self.graphicsEngine.getDefaultLoader() bg.init_tree(tags=("model", )) self.background = bg self.background.reparentTo(self.scene) def optimize_camera(self): """ Calculate good camera parameters given the current stim.""" top = self.cameras.getTop() p0 = Point3() p1 = Point3() self.sso.calcTightBounds(p0, p1) shape = p1 - p0 extent = (shape[0], shape[2]) extent = [max(extent)] * 2 center = shape / 2. + p0 # Adjust camera's x-position. self.cameras.setX(top, center[0]) self.cameras.setZ(top, p1[2]) # Compute where camera will point. # look_at = Point3(center[0], self.look_at.getY(), self.look_at.getZ()) # look_at = (center[0], center[1], self.look_at.getZ()) look_at = center origin = Point3(center[0], center[1], p1[2]) displacement = self.cameras.getPos(top) - origin distance = displacement.length() fov = self.cam.node().getLens().getFov() target_ratio = 0.65 dx = extent[0] / 2. / target_ratio / tan(radians(fov[0]) / 2.) dz = extent[1] / 2. / target_ratio / tan(radians(fov[1]) / 2.) dr = max(dx, dz) / distance pos = origin + displacement * dr self.cameras.setPos(top, pos) #BP() # Point camera toward stim. self.look_at.setPos(top, look_at) self.cameras.lookAt(self.look_at) def _load(self, model): """ Wrapper for egg/bam loading.""" node = NodePath(GSO.loader.loadSync(model)) return node def toggle_task(self, taskname, sort=0): """ Toggles taskMgr task 'taskname'.""" if not self.taskMgr.hasTaskNamed(taskname): self.taskMgr.add(getattr(self, taskname), taskname, sort=sort) if taskname == "physics": self.reset_physics() else: self.taskMgr.remove(taskname) def reset_physics(self): """ Resets physics.""" self.start_time = self.taskMgr.globalClock.getFrameTime() self.old_elapsed = 0. def physics(self, task): """ Task: simulate physics.""" # Elapsed time. dt = self._get_elapsed() - self.old_elapsed # Update amount of time simulated so far. self.old_elapsed += dt # Step the physics dt time. size_sub = self.bbase.sim_par["size_sub"] n_subs = int(dt / size_sub) self.bbase.step(dt, n_subs, size_sub) return task.cont def repel(self, task): """ Task: perform repel.""" self.bbase.repel() return task.done def bump(self, task): """ Task: perform bump.""" mag0 = Vec3(0, 0, 1. / self.bbase.sim_par["size"]) * 10. pos = Point3(-1, 0, 0) nodes = self.background.descendants() bodies = [n.node() for n in nodes if n.type_ is BulletRigidBodyNode] for body in bodies: mag = mag0 * body.getMass() print mag body.applyForce(mag, pos) #BP() return task.done def physics_once(self, dt): """ Step the physics dt.""" n_subs = 10 size_sub = dt / n_subs self.bbase.step(dt, n_subs, size_sub) # self.bbase.attenuate_velocities(self.bbase.get_bodies()) def bp(self, task): """ Task: break.""" BP() return task.done def toggle_debug(self): """ Shows/hides debug node.""" if self.debug_np.isHidden(): self.debug_np.show() else: self.debug_np.hide() def rotate(self, task): """ Task: rotate camera.""" H = (self.camera_rot.getH() + 1) % 360 self.camera_rot.setH(H) return task.cont def rotate90(self, task): """ Task: rotate in ticks.""" angs = [15, 105, 195, 285] H = int(self.camera_rot.getH()) if H in angs: self.camera_rot.setH(angs[(angs.index(H) + 1) % len(angs)]) else: self.camera_rot.setH(angs[0]) return task.done def ss_task(self, task): """ Task: Take a screenshot.""" self.screenshot() return task.done def ssa_task(self, task): """ Task: Take a screenshot of every sso.""" self.screenshot(namePrefix=self.sso.getName() + ".jpg", defaultFilename=False) if self.n_ssos - 1 == self.ssos.index(self.sso): return task.done self.next() return task.cont def _expunge_events(self): """ Turn OFF any non-permanent key handlers.""" events = self.getAllAccepting() for event in set(events).difference(self.permanent_events): self.ignore(event) def _expunge_tasks(self): """ Turn OFF any non-permanent tasks floating around.""" tasknames = [task.getName() for task in self.taskMgr.getAllTasks()] for taskname in set(tasknames).difference(self.permanent_tasks): self.taskMgr.remove(taskname) def reset_sso(self): """ Reset to initial scene state.""" self.goto_sso(self.ssos.index(self.sso)) def goto_sso(self, i): """ Switches to the i-th SSO.""" print "SSO %d" % i # Remove existing tasks and events. self._expunge_tasks() self._expunge_events() if getattr(self, "sso", False): # Detach from physical world. self.bbase.remove_all() # Reset its state to the initial one. self.cache.restore() # Detach from scene. self.sso.detachNode() # Set the new sso. self.sso = self.ssos[i] self.sso.reparentTo(self.scene) self.cache = self.scene.store_tree() self.attach_physics() self.optimize_camera() def attach_physics(self): # Attach `self.scene` to the physics world. self.scene.init_tree(tags=("shape", )) bnodes = self.scene.descendants(type_=PSO) for bnode in bnodes: bnode.setCollideMask(BitMask32.allOn()) bnode.node().setDeactivationEnabled(False) self.bbase.attach(bnodes) def remove_physics(self): # Remove `self.scene` from the physics world. self.bbase.remove(self.scene.descendants(type_=PSO)) self.scene.destroy_tree(tags=("shape", )) def prev(self, steps=1): """ Task: Go back one SSO.""" i = max(0, self.ssos.index(self.sso) - steps) self.goto_sso(i) def next(self, steps=1): """ Task: Go forward one SSO.""" i = min(self.n_ssos - 1, self.ssos.index(self.sso) + steps) self.goto_sso(i) def _get_elapsed(self): """ Gets the time spent in this phase so far.""" # Current time. current_time = self.taskMgr.globalClock.getFrameTime() # Elapsed time in this phase elapsed = current_time - self.start_time return elapsed def run(self): # Start with first sso. self.goto_sso(0) # Call parent's run(). ShowBase.run(self) def exit(self): """ Stuff to do before exiting.""" sys.exit()
def test_scale_immutability(): sso = SSO("foo") before = sso.read_prop() before["scale"][0] = 10 assert sso.read_prop()["scale"] != before["scale"]
def test_quat_immutability(): sso = SSO("foo") before = sso.read_prop() before["quat"][1] = 0.55 assert sso.read_prop()["quat"] != before["quat"]
def load_cpo(pth): """Load a cpo from disk.""" with open(pth, "r") as fid: cpo = SSO.load_tree(fid) return cpo
import os from scenesim.objects.sso import SSO from libpanda import LVector3f, LPoint3f, LVecBase3f, LQuaternionf, LVecBase4f sso_paths = [] for dirname, dirnames, filenames in os.walk("stimuli"): for filename in filenames: if filename.endswith(".cpo"): sso_paths.append(os.path.join(dirname, filename)) for filename in sso_paths: sso_name = os.path.splitext(os.path.basename(filename))[0] dest = os.path.join(os.path.split(filename)[0], "{}.json".format(sso_name)) print(dest) sso = SSO.load_tree(filename) types, props, porder = sso.state_prop() types = [[t.__module__, t.__name__] for t in types] for p in props: for prop, val in p.items(): if isinstance( val, (LVecBase3f, LVecBase4f, LVector3f, LPoint3f, LQuaternionf)): p[prop] = { "__class__": [type(val).__module__, type(val).__name__], "value": list(val) } with open(dest, 'w') as fh: json.dump([types, props, porder], fh)
def __init__(self, *args, **kwargs): ## Using super fails, probably because NodePath is a C++ class. # super(GSO, self).__init__(*args, **kwargs) SSO.__init__(self, *args, **kwargs)
def __init__(self): ShowBase.__init__(self) resize_window = ConfigVariableBool('viewer-resize-window', '#t') if resize_window.getValue(): self.win_size = (800, 800) # Black background self.win.setClearColor((0.0, 0.0, 0.0, 1.0)) # Set up lights. self.lights = NodePath("lights") # Spotlight. Casts shadows. slight = Spotlight("slight") slight.setScene(self.render) slight.setShadowCaster(True, 2**11, 2**11) # Set shadow mask, so we can exclude objects from casting shadows self.shadow_mask = BitMask32.bit(2) slight.setCameraMask(self.shadow_mask) slight.setColor((1.2, 1.2, 1.2, 1.)) slight.getLens().setFov(45) slight.getLens().setNearFar(1, 100) slnp = self.lights.attachNewNode(slight) slnp.setPos((6, 8, 20)) slnp.lookAt(0, 0, 0) self.render.setLight(slnp) # Ambient light. alight = AmbientLight("alight") a = 0.75 alight.setColor((a, a, a, 1.0)) #alight.setColor((0.8, 0.8, 0.8, 1.0)) alnp = self.lights.attachNewNode(alight) self.render.setLight(alnp) self.lights.reparentTo(self.render) # Set auto shading for shadows use_shaders = ConfigVariableBool('viewer-use-shaders', '#t') if use_shaders.getValue(): self.render.setShaderAuto() # Set antialiasing on self.render.setAntialias(AntialiasAttrib.MAuto) # Camera self.camera_rot = self.render.attachNewNode("camera_rot") self.cameras = self.camera_rot.attachNewNode("cameras") self.cameras.setPos(14, 32, 9.) self.look_at = self.render.attachNewNode("look_at") self.look_at.setPos(Point3(2, 0, 1)) self.cameras.lookAt(self.look_at) self.camera.reparentTo(self.cameras) # Adjust the camera's lens lens = PerspectiveLens() self.camLens = lens self.camLens.setNearFar(0.01, 1000.0) setlens = ConfigVariableBool('viewer-set-cam-lens', '#t') if setlens: self.cam.node().setLens(self.camLens) # # Initialize / set variables self.sso = None self.ssos = [] self.cache = None self.scene = SSO("scene") self.scene.reparentTo(self.render) # Key callbacks. self.accept("shift-control-escape", self.exit) self.accept("escape", self.exit) self.accept("0", self.reset_sso) self.accept("arrow_left", self.prev) self.accept("arrow_right", self.next) self.accept("page_down", self.prev, [100]) self.accept("page_up", self.next, [100]) self.accept("f1", self.toggle_debug) self.accept("o", self.physics_once, extraArgs=[1. / 10]) self.accept("i", self.physics_once, extraArgs=[1. / 10000]) # Remove existing keyboard tasks. self.mandatory_events = ("window-event", "async_loader_0", "render-texture-targets-changed", "shift-control-escape") # Task list: name: (key, args) events = { "physics": ("p", ), "repel": ("t", ), "bump": ("f", ), "rotate": ("r", 20), "rotate90": ("h", ), "ss_task": ("s", ), "ssa_task": ("w", ), "bp": ("b", ) } # Add events for key, val in events.iteritems(): call = [key] + list(val[1:]) self.accept(val[0], self.toggle_task, call) # These are the key events that we will never ignore self.permanent_events = self.getAllAccepting() # These are the key events that we will never ignore self.permanent_tasks = [ task.getName() for task in self.taskMgr.getAllTasks() ] self.start_time = -1 self.old_elapsed = 0
class Viewer(ShowBase, object): """ Viewer for SSOs.""" def __init__(self): ShowBase.__init__(self) resize_window = ConfigVariableBool('viewer-resize-window', '#t') if resize_window.getValue(): self.win_size = (800, 800) # Black background self.win.setClearColor((0.0, 0.0, 0.0, 1.0)) # Set up lights. self.lights = NodePath("lights") # Spotlight. Casts shadows. slight = Spotlight("slight") slight.setScene(self.render) slight.setShadowCaster(True, 2 ** 11, 2 ** 11) # Set shadow mask, so we can exclude objects from casting shadows self.shadow_mask = BitMask32.bit(2) slight.setCameraMask(self.shadow_mask) slight.setColor((1.2, 1.2, 1.2, 1.)) slight.getLens().setFov(45) slight.getLens().setNearFar(1, 100) slnp = self.lights.attachNewNode(slight) slnp.setPos((6, 8, 20)) slnp.lookAt(0, 0, 0) self.render.setLight(slnp) # Ambient light. alight = AmbientLight("alight") a = 0.75 alight.setColor((a, a, a, 1.0)) #alight.setColor((0.8, 0.8, 0.8, 1.0)) alnp = self.lights.attachNewNode(alight) self.render.setLight(alnp) self.lights.reparentTo(self.render) # Set auto shading for shadows use_shaders = ConfigVariableBool('viewer-use-shaders', '#t') if use_shaders.getValue(): self.render.setShaderAuto() # Set antialiasing on self.render.setAntialias(AntialiasAttrib.MAuto) # Camera self.camera_rot = self.render.attachNewNode("camera_rot") self.cameras = self.camera_rot.attachNewNode("cameras") self.cameras.setPos(14, 32, 9.) self.look_at = self.render.attachNewNode("look_at") self.look_at.setPos(Point3(2, 0, 1)) self.cameras.lookAt(self.look_at) self.camera.reparentTo(self.cameras) # Adjust the camera's lens lens = PerspectiveLens() self.camLens = lens self.camLens.setNearFar(0.01, 1000.0) setlens = ConfigVariableBool('viewer-set-cam-lens', '#t') if setlens: self.cam.node().setLens(self.camLens) # # Initialize / set variables self.sso = None self.ssos = [] self.cache = None self.scene = SSO("scene") self.scene.reparentTo(self.render) # Key callbacks. self.accept("shift-control-escape", self.exit) self.accept("escape", self.exit) self.accept("0", self.reset_sso) self.accept("arrow_left", self.prev) self.accept("arrow_right", self.next) self.accept("page_down", self.prev, [100]) self.accept("page_up", self.next, [100]) self.accept("f1", self.toggle_debug) self.accept("o", self.physics_once, extraArgs=[1. / 10]) self.accept("i", self.physics_once, extraArgs=[1. / 10000]) # Remove existing keyboard tasks. self.mandatory_events = ("window-event", "async_loader_0", "render-texture-targets-changed", "shift-control-escape") # Task list: name: (key, args) events = {"physics": ("p",), "repel": ("t",), "bump": ("f",), "rotate": ("r", 20), "rotate90": ("h",), "ss_task": ("s",), "ssa_task": ("w",), "bp": ("b",)} # Add events for key, val in events.iteritems(): call = [key] + list(val[1:]) self.accept(val[0], self.toggle_task, call) # These are the key events that we will never ignore self.permanent_events = self.getAllAccepting() # These are the key events that we will never ignore self.permanent_tasks = [task.getName() for task in self.taskMgr.getAllTasks()] self.start_time = -1 self.old_elapsed = 0 @property def win_size(self): """ Returns window size.""" props = WindowProperties(self.win.getProperties()) return props.getXSize(), props.getYSize() @win_size.setter def win_size(self, wh): """ Sets window size.""" props = WindowProperties(self.win.getProperties()) props.setSize(*wh) self.size = wh self.win.requestProperties(props) def toggle_fullscreen(self): """ Toggles fullscreen mode.""" props = WindowProperties(self.win.getProperties()) if props.getFullscreen(): props.setSize(*self.size) props.setFullscreen(False) else: w = self.pipe.getDisplayWidth() h = self.pipe.getDisplayHeight() props.setSize(w, h) props.setFullscreen(True) self.win.requestProperties(props) def _get_screen_size(self): winx = self.win.getXSize() winy = self.win.getYSize() return winx, winy def _convert_coordinate(self, P0): """ Convert 3 coordinates to 2d projection, and 2d coordinates to 3d extrusion.""" P0 = array(P0) proj_mat = get_projection_mat(self.cam) if P0.size == 2: # 2d to 3d. line = extrude(P0, proj_mat) normal = array((0., 0., 1.)) P = plane_intersection(line, array(self.origin), normal) else: # 3d to 2d. P = project(P0, proj_mat) return P def _get_screen_mouse_location(self): """ Gets mouse location in screen coordinates.""" md = self.win.getPointer(0) s2d = array((md.getX(), md.getY())) return s2d def _set_screen_mouse_location(self, s2d): """ Sets mouse location in screen coordinates.""" self.win.movePointer(0, *s2d.astype("i")) def _get_cursor_location(self): """ Return cursor's 2D or 3D location.""" # Mouse's screen coordinates x = self.mouseWatcherNode.getMouseX() y = self.mouseWatcherNode.getMouseY() return self._convert_coordinate((x, y)) def _set_cursor_location(self, p2d): """ Sets cursor location in window coords [-1, 1].""" s2d = ((p2d * array((1, -1)) + 1.) / 2. * array(self._get_screen_size())) self._set_screen_mouse_location(s2d) def _set_cursor_hidden(self, b): """ Toggle cursor.""" props = WindowProperties() props.setCursorHidden(b) self.win.requestProperties(props) def draw_cursor2d(self, task): """ Draw cursor indicator.""" if getattr(self, "cursor", None) and self.mouseWatcherNode.hasMouse(): res = self._get_screen_size() ar = float(res[0]) / res[1] mx = self.mouseWatcherNode.getMouseX() my = self.mouseWatcherNode.getMouseY() self.cursor.setPos(mx * ar, 0, my) return task.cont # def draw_cursor2d(self, task): # """ Draw cursor indicator.""" # if getattr(self, "cursor", None) and self.mouseWatcherNode.hasMouse(): # mx = self.mouseWatcherNode.getMouseX() # my = self.mouseWatcherNode.getMouseY() # p3d = self._convert_coordinate((mx, my)) # p2d = self._convert_coordinate(p3d)[0].squeeze() # res = self._get_screen_size() # ar = float(res[0]) / res[1] # x = p2d[0] * ar # y = p2d[1] # self.cursor.setPos(x, 0., y) # return task.cont def init_physics(self, bbase): """ Initialize the physics resources.""" self.bbase = bbase self.debug_np = self.render.attachNewNode(self.bbase.setup_debug()) def init_ssos(self, ssos): """ Initialize the ssos.""" GSO.loader = Loader # self.graphicsEngine.getDefaultLoader() # Put all the input ssos into one list. self.ssos = [] for sso in ssos: if not isinstance(sso, NodePath): raise TypeError("Must be NodePath: %s (%s)" % (sso, type(sso))) # Set up the node and its descendants. sso.init_tree(tags=("model",)) self.ssos.append(sso) # Number of ssos. self.n_ssos = len(self.ssos) def init_background(self, bg): """ Initialize the background.""" # Put all the input ssos into one list. if not isinstance(bg, NodePath): raise TypeError("Must be NodePath: %s (%s)" % (bg, type(bg))) GSO.loader = Loader # self.graphicsEngine.getDefaultLoader() bg.init_tree(tags=("model",)) self.background = bg self.background.reparentTo(self.scene) def optimize_camera(self): """ Calculate good camera parameters given the current stim.""" top = self.cameras.getTop() p0 = Point3() p1 = Point3() self.sso.calcTightBounds(p0, p1) shape = p1 - p0 extent = (shape[0], shape[2]) extent = [max(extent)] * 2 center = shape / 2. + p0 # Adjust camera's x-position. self.cameras.setX(top, center[0]) self.cameras.setZ(top, p1[2]) # Compute where camera will point. # look_at = Point3(center[0], self.look_at.getY(), self.look_at.getZ()) # look_at = (center[0], center[1], self.look_at.getZ()) look_at = center origin = Point3(center[0], center[1], p1[2]) displacement = self.cameras.getPos(top) - origin distance = displacement.length() fov = self.cam.node().getLens().getFov() target_ratio = 0.65 dx = extent[0] / 2. / target_ratio / tan(radians(fov[0]) / 2.) dz = extent[1] / 2. / target_ratio / tan(radians(fov[1]) / 2.) dr = max(dx, dz) / distance pos = origin + displacement * dr self.cameras.setPos(top, pos) #BP() # Point camera toward stim. self.look_at.setPos(top, look_at) self.cameras.lookAt(self.look_at) def _load(self, model): """ Wrapper for egg/bam loading.""" node = NodePath(GSO.loader.loadSync(model)) return node def toggle_task(self, taskname, sort=0): """ Toggles taskMgr task 'taskname'.""" if not self.taskMgr.hasTaskNamed(taskname): self.taskMgr.add(getattr(self, taskname), taskname, sort=sort) if taskname == "physics": self.reset_physics() else: self.taskMgr.remove(taskname) def reset_physics(self): """ Resets physics.""" self.start_time = self.taskMgr.globalClock.getFrameTime() self.old_elapsed = 0. def physics(self, task): """ Task: simulate physics.""" # Elapsed time. dt = self._get_elapsed() - self.old_elapsed # Update amount of time simulated so far. self.old_elapsed += dt # Step the physics dt time. size_sub = self.bbase.sim_par["size_sub"] n_subs = int(dt / size_sub) self.bbase.step(dt, n_subs, size_sub) return task.cont def repel(self, task): """ Task: perform repel.""" self.bbase.repel() return task.done def bump(self, task): """ Task: perform bump.""" mag0 = Vec3(0, 0, 1. / self.bbase.sim_par["size"]) * 10. pos = Point3(-1, 0, 0) nodes = self.background.descendants() bodies = [n.node() for n in nodes if n.type_ is BulletRigidBodyNode] for body in bodies: mag = mag0 * body.getMass() print mag body.applyForce(mag, pos) #BP() return task.done def physics_once(self, dt): """ Step the physics dt.""" n_subs = 10 size_sub = dt / n_subs self.bbase.step(dt, n_subs, size_sub) # self.bbase.attenuate_velocities(self.bbase.get_bodies()) def bp(self, task): """ Task: break.""" BP() return task.done def toggle_debug(self): """ Shows/hides debug node.""" if self.debug_np.isHidden(): self.debug_np.show() else: self.debug_np.hide() def rotate(self, task): """ Task: rotate camera.""" H = (self.camera_rot.getH() + 1) % 360 self.camera_rot.setH(H) return task.cont def rotate90(self, task): """ Task: rotate in ticks.""" angs = [15, 105, 195, 285] H = int(self.camera_rot.getH()) if H in angs: self.camera_rot.setH(angs[(angs.index(H) + 1) % len(angs)]) else: self.camera_rot.setH(angs[0]) return task.done def ss_task(self, task): """ Task: Take a screenshot.""" self.screenshot() return task.done def ssa_task(self, task): """ Task: Take a screenshot of every sso.""" self.screenshot(namePrefix=self.sso.getName() + ".jpg", defaultFilename=False) if self.n_ssos - 1 == self.ssos.index(self.sso): return task.done self.next() return task.cont def _expunge_events(self): """ Turn OFF any non-permanent key handlers.""" events = self.getAllAccepting() for event in set(events).difference(self.permanent_events): self.ignore(event) def _expunge_tasks(self): """ Turn OFF any non-permanent tasks floating around.""" tasknames = [task.getName() for task in self.taskMgr.getAllTasks()] for taskname in set(tasknames).difference(self.permanent_tasks): self.taskMgr.remove(taskname) def reset_sso(self): """ Reset to initial scene state.""" self.goto_sso(self.ssos.index(self.sso)) def goto_sso(self, i): """ Switches to the i-th SSO.""" print "SSO %d" % i # Remove existing tasks and events. self._expunge_tasks() self._expunge_events() if getattr(self, "sso", False): # Detach from physical world. self.bbase.remove_all() # Reset its state to the initial one. self.cache.restore() # Detach from scene. self.sso.detachNode() # Set the new sso. self.sso = self.ssos[i] self.sso.reparentTo(self.scene) self.cache = self.scene.store_tree() self.attach_physics() self.optimize_camera() def attach_physics(self): # Attach `self.scene` to the physics world. self.scene.init_tree(tags=("shape",)) bnodes = self.scene.descendants(type_=PSO) for bnode in bnodes: bnode.setCollideMask(BitMask32.allOn()) bnode.node().setDeactivationEnabled(False) self.bbase.attach(bnodes) def remove_physics(self): # Remove `self.scene` from the physics world. self.bbase.remove(self.scene.descendants(type_=PSO)) self.scene.destroy_tree(tags=("shape",)) def prev(self, steps=1): """ Task: Go back one SSO.""" i = max(0, self.ssos.index(self.sso) - steps) self.goto_sso(i) def next(self, steps=1): """ Task: Go forward one SSO.""" i = min(self.n_ssos - 1, self.ssos.index(self.sso) + steps) self.goto_sso(i) def _get_elapsed(self): """ Gets the time spent in this phase so far.""" # Current time. current_time = self.taskMgr.globalClock.getFrameTime() # Elapsed time in this phase elapsed = current_time - self.start_time return elapsed def run(self): # Start with first sso. self.goto_sso(0) # Call parent's run(). ShowBase.run(self) def exit(self): """ Stuff to do before exiting.""" sys.exit()
import json import os from scenesim.objects.sso import SSO from libpanda import LVector3f, LPoint3f, LVecBase3f, LQuaternionf, LVecBase4f sso_paths = [] for dirname, dirnames, filenames in os.walk("stimuli"): for filename in filenames: if filename.endswith(".cpo"): sso_paths.append(os.path.join(dirname, filename)) for filename in sso_paths: sso_name = os.path.splitext(os.path.basename(filename))[0] dest = os.path.join(os.path.split(filename)[0], "{}.json".format(sso_name)) print(dest) sso = SSO.load_tree(filename) types, props, porder = sso.state_prop() types = [[t.__module__, t.__name__] for t in types] for p in props: for prop, val in p.items(): if isinstance(val, (LVecBase3f, LVecBase4f, LVector3f, LPoint3f, LQuaternionf)): p[prop] = {"__class__": [type(val).__module__, type(val).__name__], "value": list(val)} with open(dest, 'w') as fh: json.dump([types, props, porder], fh)
def __init__(self): ShowBase.__init__(self) resize_window = ConfigVariableBool('viewer-resize-window', '#t') if resize_window.getValue(): self.win_size = (800, 800) # Black background self.win.setClearColor((0.0, 0.0, 0.0, 1.0)) # Set up lights. self.lights = NodePath("lights") # Spotlight. Casts shadows. slight = Spotlight("slight") slight.setScene(self.render) slight.setShadowCaster(True, 2 ** 11, 2 ** 11) # Set shadow mask, so we can exclude objects from casting shadows self.shadow_mask = BitMask32.bit(2) slight.setCameraMask(self.shadow_mask) slight.setColor((1.2, 1.2, 1.2, 1.)) slight.getLens().setFov(45) slight.getLens().setNearFar(1, 100) slnp = self.lights.attachNewNode(slight) slnp.setPos((6, 8, 20)) slnp.lookAt(0, 0, 0) self.render.setLight(slnp) # Ambient light. alight = AmbientLight("alight") a = 0.75 alight.setColor((a, a, a, 1.0)) #alight.setColor((0.8, 0.8, 0.8, 1.0)) alnp = self.lights.attachNewNode(alight) self.render.setLight(alnp) self.lights.reparentTo(self.render) # Set auto shading for shadows use_shaders = ConfigVariableBool('viewer-use-shaders', '#t') if use_shaders.getValue(): self.render.setShaderAuto() # Set antialiasing on self.render.setAntialias(AntialiasAttrib.MAuto) # Camera self.camera_rot = self.render.attachNewNode("camera_rot") self.cameras = self.camera_rot.attachNewNode("cameras") self.cameras.setPos(14, 32, 9.) self.look_at = self.render.attachNewNode("look_at") self.look_at.setPos(Point3(2, 0, 1)) self.cameras.lookAt(self.look_at) self.camera.reparentTo(self.cameras) # Adjust the camera's lens lens = PerspectiveLens() self.camLens = lens self.camLens.setNearFar(0.01, 1000.0) setlens = ConfigVariableBool('viewer-set-cam-lens', '#t') if setlens: self.cam.node().setLens(self.camLens) # # Initialize / set variables self.sso = None self.ssos = [] self.cache = None self.scene = SSO("scene") self.scene.reparentTo(self.render) # Key callbacks. self.accept("shift-control-escape", self.exit) self.accept("escape", self.exit) self.accept("0", self.reset_sso) self.accept("arrow_left", self.prev) self.accept("arrow_right", self.next) self.accept("page_down", self.prev, [100]) self.accept("page_up", self.next, [100]) self.accept("f1", self.toggle_debug) self.accept("o", self.physics_once, extraArgs=[1. / 10]) self.accept("i", self.physics_once, extraArgs=[1. / 10000]) # Remove existing keyboard tasks. self.mandatory_events = ("window-event", "async_loader_0", "render-texture-targets-changed", "shift-control-escape") # Task list: name: (key, args) events = {"physics": ("p",), "repel": ("t",), "bump": ("f",), "rotate": ("r", 20), "rotate90": ("h",), "ss_task": ("s",), "ssa_task": ("w",), "bp": ("b",)} # Add events for key, val in events.iteritems(): call = [key] + list(val[1:]) self.accept(val[0], self.toggle_task, call) # These are the key events that we will never ignore self.permanent_events = self.getAllAccepting() # These are the key events that we will never ignore self.permanent_tasks = [task.getName() for task in self.taskMgr.getAllTasks()] self.start_time = -1 self.old_elapsed = 0
# create dimension for kappa data = data[:, :, None] else: raise ValueError("unexpected number of dimensions: %d" % data.ndim) # convert stimuli names to something coherent stims = [convert_name(stim) for stim in meta['stim']] # figure out object names objs = None for stim in stims: stim_path = os.path.join(stimset_path, stim + ".cpo") if not stim_path.exists(): raise IOError("cannot find stimulus: %s" % stim) cpo = SSO.load_tree(stim_path) psos = cpo.descendants(type_=RBSO) pso_names = [x.getName() for x in psos] if objs is None: objs = pso_names else: if objs != pso_names: raise AssertionError("inconsistent pso names") # construct the new metadata dictionary diminfo = { 'sigma': map(float, meta['sigmas']), 'phi': map(float, meta['phis']), 'kappa': map(float, meta.get('kappas', [0.0])), 'stimulus': stims,