def _reset_cue(self): # Position and orient the cue pos = self.ball['cue'].motion.getWorldTransform().getOrigin() p = self.cue.org_pivot self.cue.set_pivot(eVector3(p.x, p.y, p.z + SCALE_FACTOR * 0.1)) self.cue.set_position(eVector3(pos.x, pos.y, pos.z + self.cue.pivot.z)) self.cue.orient_from_direction()
def __init__(self, filename, view): self.model = OBJ_vbo(filename) self.view = view self.morient = Matrix4() self.pivot = eVector3() self.position = eVector3() self.do_transformation_matrix()
def getWorldTransform(self): p = self.cue.pivot t = self.cue.position self.cue.set_pivot(eVector3(p.x, p.y, p.z + self.cue.delta * 0.2)) self.cue.set_position(eVector3(t.x, t.y, t.z + self.cue.delta * 0.2)) self.cue.do_transformation_matrix() mnumpy = array(self.cue.m, 'f') self.transform.setFromOpenGLMatrix(mnumpy) return self.transform
def internal_tick_callback(self, timeStep): if self._cue_ball_rest(): disp = self.world.getDispatcher() n = disp.getNumManifolds() for i in xrange(n): cm = disp.getManifoldByIndexInternal(i) contacts = cm.getNumContacts() for c in xrange(contacts): obA = cm.getBody0().getUserPointer() obB = cm.getBody1().getUserPointer() if obA == 'Cue' and obB == 'Cue Ball' \ or obA == 'Cue Ball' and obB == 'Cue': p = cm.getContactPoint(c) if p.getDistance() < 0.0: # test for penetration # The cue's strike force is calculated from actual # linear velocity applied to the cues orientation vector b = self.cue.body.getLinearVelocity() v = eVector3(b.x, b.y, b.z) d = self.cue.direction if hasattr(self.cue, 'direction') \ else self.view.dir # get force impuls = v.magnitude() * SCALE_FACTOR * 25. force = bVector3(d.x * impuls, d.y * impuls, 0.0) # span offset to [0..1] offset = eVector3(self.cue.dx * 4., 0., self.cue.dy * 4.) # calculate offset from cue's position [convert from eye into object space] # TODO: (rewrite this in compact form of vector vs. matrix multiplication) moffset = self.view.orient.inverse() * Matrix4.new_translate(*offset) offset = eVector3(moffset.d, moffset.h, moffset.l) cue = self.ball['cue'] cue.body.clearForces() cue.body.applyGravity() cue.body.applyForce(force, bVector3(offset.x, offset.y, offset.z)) # Restore cue self._reset_cue() def ball_cant_fly(ball): # check for flying pos = ball.motion.getWorldTransform().getOrigin() if pos.z > ball.radius: ball.body.applyCentralForce(bVector3(0, 0, -15 * SCALE_FACTOR)) # check for ball speed v = ball.body.getLinearVelocity() vel = eVector3(v.x, v.y, v.z) if vel.magnitude_squared() > PoolWindow.BALL_MAX_SPEED: ball.body.setLinearVelocity(v * 0.9) for ball in self.ball.values(): ball_cant_fly(ball)
def __init__(self, filename, view, mass, position=eVector3()): super(CueBall, self).__init__(filename, view) self.radius = self.model.dimension.z / 2.0 self.mass = mass # Update z pos from radius position.z = self.radius # Init Transform transform = Transform() self.position = position self.do_transformation_matrix() self.mnumpy = array(self.m, 'f') transform.setFromOpenGLMatrix(self.mnumpy) # The Rigid Body mass = self.mass * SCALE_FACTOR shape = SphereShape(self.radius) i = shape.getLocalInertia(mass) * 0.65 self.motion = DefaultMotionState() self.motion.setWorldTransform(transform) self.body = RigidBody.fromConstructionInfo(self.motion, # MotionState motion shape, # CollisionShape shape mass, # btScalar mass bVector3(i.x, i.y, i.z), # Vector3 inertia transform, # Transform worldTransform 0.2, # btScalar linearDamping 0.65, # btScalar angularDamping 0.25, # btScalar friction 0.7, # btScalar restitution 1.5, # btScalar linearSleepingThreshold 1.5) # btScalar angularSleepingThreshold self.body.setContactProcessingThreshold(0) self.body.setCcdMotionThreshold(0) self.body.setHitFraction(0.1 * SCALE_FACTOR)
def redraw_scene(self, debug=False): # table self.table.render() # rails self.rails.render() # balls for ball in self.ball.values(): p = ball.motion.getWorldTransform().getOrigin() q = ball.motion.getWorldTransform().getRotation() a = q.getAxis() ball.set_position((p.x, p.y, p.z)) ball.orient_from_axis_angle(q.getAngle(), eVector3(a.x, a.y, a.z)) ball.render() # cue stick (only if cue ball is resting) if self._cue_ball_rest(): self.cue.render() # debug draw if debug: self.debug.reset() self.world.debugDrawWorld() glDisable(GL_LIGHTING) glBegin(GL_LINES) for line in self.debug.lines: glColor3f(*line[6:]) glVertex3f(*line[:3]) glVertex3f(*line[3:6]) glEnd() glEnable(GL_LIGHTING)
def _update_scroll(self, dt): distance = self.view.distance * self.zmul self.view.set_distance(distance) pos = self.ball['cue'].motion.getWorldTransform().getOrigin() self.view.set_center(eVector3(pos.x, pos.y, pos.z)) self._setup_pan() self.wheel_step -= 1 if self.wheel_step == 0: pyglet.clock.unschedule(self._update_scroll)
def ball_cant_fly(ball): # check for flying pos = ball.motion.getWorldTransform().getOrigin() if pos.z > ball.radius: ball.body.applyCentralForce(bVector3(0, 0, -15 * SCALE_FACTOR)) # check for ball speed v = ball.body.getLinearVelocity() vel = eVector3(v.x, v.y, v.z) if vel.magnitude_squared() > PoolWindow.BALL_MAX_SPEED: ball.body.setLinearVelocity(v * 0.9)
def render_front_cue(self): # Redraw helper top-right (front view) glViewport(self.width - self.width / 3, self.height - self.height / 3, self.width / 3, self.height / 3) glLoadIdentity() eye = eVector3(self.cue.mtransform.d, self.cue.mtransform.h, self.cue.mtransform.l) eye += self.cue.direction * 6. # render front pos = self.ball['cue'].position gluLookAt(eye.x, eye.y, eye.z, pos.x, pos.y, pos.z, 0., 0., 1.) redraw_scene(self, True)
def on_mouse_drag(self, x, y, dx, dy, button, modifiers): if button & mouse.LEFT: if modifiers & key.MOD_WINDOWS: self.view.rotate(dx, dy) else: self.view.rotate(dx, dy) pos = self.ball['cue'].motion.getWorldTransform().getOrigin() self.view.set_center(eVector3(pos.x, pos.y, pos.z)) self.cue.set_position(eVector3(pos.x, pos.y, pos.z + self.cue.pivot.z)) self.cue.orient_from_direction() self._setup_pan() elif button & mouse.RIGHT: pos = self.ball['cue'].motion.getWorldTransform().getOrigin() self.view.set_center(eVector3(pos.x, pos.y, pos.z)) self.view.zoom(y) self._setup_pan() elif button & mouse.MIDDLE: if modifiers & key.MOD_SHIFT: self.cue.move(dx, dy) else: self.view.pan(dx, dy)
def orient_from_direction(self, direction=None): ''' Slightly lower direction vector for pi/32 radian's, so cue will render beneath the view's eye position. ''' c = self.view.dir.cross(self.view.up).normalize() self.direction = eVector3(*self.view.dir) self.direction = self.direction.rotate_around(c, pi / 32.) super(CueStick, self).orient_from_direction(self.direction) self.update_body_position() self.dx = 0. self.dy = 0.
def __init__(self, filename, view, cball_radius): super(CueStick, self).__init__(filename, view) self.half = self.model.dimension / 2.0 self.tip_radius = self.half.x self.pivot = eVector3(0, 0, self.half.z + cball_radius) self.org_pivot = eVector3(*self.pivot) shape = CapsuleShapeZ(self.tip_radius, self.model.dimension.z - self.tip_radius * 2) #shape = CylinderShapeZ(bVector3(*self.half)) transform = Transform() transform.setIdentity() self.motion = CSMotionState() self.motion.cue = self self.delta = 0. self.dx = 0. self.dy = 0. self.motion.setWorldTransform(transform) self.body = RigidBody.fromConstructionInfo(self.motion, # MotionState motion shape, # CollisionShape shape 0.0, # btScalar mass bVector3(0, 0, 0), # Vector3 inertia transform, # Transform worldTransform 0.0, # btScalar linearDamping 0.0, # btScalar angularDamping 0.0, # btScalar friction 0.71, # btScalar restitution 0.0, # btScalar linearSleepingThreshold 0.0) # btScalar angularSleepingThreshold self.body.setContactProcessingThreshold(0) self.body.setCcdMotionThreshold(0) self.body.setHitFraction(0.1 * SCALE_FACTOR) self.body.setGravity(bVector3(0, 0, 0)) # Make it kinematic body with collision contacts generation but no response impulses flags = self.body.getCollisionFlags() | CueStick.CF_KINEMATIC_OBJECT | CueStick.CF_NO_CONTACT_RESPONSE self.body.setCollisionFlags(flags) self.body.setActivationState(DISABLE_DEACTIVATION)
def set_pivot(self, pivot): self.pivot = eVector3(*pivot)
def set_position(self, position): self.position = eVector3(*position)
def __init__(self, *args, **kwargs): super(PoolWindow, self).__init__(*args, **kwargs) self.set_size(1680, 1000) #self.set_fullscreen() self.keys = key.KeyStateHandler() self.push_handlers(self.keys) # Setup GL self.set_vsync(True) glClearColor(.15, .15, .15, 1) glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) glShadeModel(GL_SMOOTH) self.lpos1 = (0, 0.5 * SCALE_FACTOR, 1 * SCALE_FACTOR, 0) self.lpos2 = (0, -0.5 * SCALE_FACTOR, 1 * SCALE_FACTOR, 0) glLightfv(GL_LIGHT0, GL_POSITION, vec(*self.lpos1)) glLightfv(GL_LIGHT1, GL_POSITION, vec(*self.lpos2)) glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE) glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) glEnable(GL_LIGHT1) # Scroll zoom self.wheel_step = PoolWindow.ZOOM_SCROLL_STEP # Setup view self.view = View(eye=(0, -3 * SCALE_FACTOR, .75 * SCALE_FACTOR), center=(0, 0, -SCALE_FACTOR)) self.view.set_distance(SCALE_FACTOR) # The scene self.table = Table('obj/table.obj', self.view) self.rails = Rails('obj/rails.obj', self.view) self.ball = {} self.ball['cue'] = CueBall('obj/ball.obj', self.view, .260) self.ball['red'] = CueBall('obj/red.obj', self.view, .260, eVector3(0, 0.5 * SCALE_FACTOR, 0)) self.ball['yellow'] = CueBall('obj/yellow.obj', self.view, .260, eVector3(0, -0.5 * SCALE_FACTOR, 0)) self.cue = CueStick('obj/cue.obj', self.view, self.ball['cue'].radius) self.table.body.setUserPointer("Table") self.rails.body.setUserPointer("Rails") self.cue.body.setUserPointer("Cue") self.ball['cue'].body.setUserPointer("Cue Ball") self.ball['red'].body.setUserPointer("Red") self.ball['yellow'].body.setUserPointer("Yellow") # Set view center pos = self.ball['cue'].motion.getWorldTransform().getOrigin() self.view.set_center(eVector3(pos.x, pos.y, pos.z)) # Setup cue (position and orient) self._reset_cue() # Initialize physics self.world = DiscreteDynamicsWorld() self.debug = DebugDraw() self.world.setDebugDrawer(self.debug) self.world.addRigidBody(self.table.body) self.world.addRigidBody(self.cue.body) self.world.addRigidBody(self.rails.body) for ball in self.ball.values(): self.world.addRigidBody(ball.body) self.world.setGravity(bVector3(0, 0, -9.81 * SCALE_FACTOR)) # Register call-backs # A 1/60 call-back to run physics (the same as render) pyglet.clock.schedule(self._step) # Physic clock callback (usually few times faster than render clock) self.world.setInternalTickCallback(self.internal_tick_callback, True) self._setup_pan() self.topview = False self.helper = True self.push_handlers(on_key_press=self._on_key_press)
def _cue_ball_rest(self): vel = self.ball['cue'].body.getLinearVelocity() mag = eVector3(vel.x, vel.y, vel.z).magnitude() return mag < 0.001