def _trackballTask(self, task): if not self.mouseDown: return Task.cont if (base.mouseWatcherNode.hasMouse()): mpos = base.mouseWatcherNode.getMouse() if mpos == self.lastMousePos: return Task.cont mDelta = mpos - self.clickPos heading = -mDelta.x * 100 + self.initialHpr.x pitch = mDelta.y * 100 + self.initialHpr.y if pitch > 90: pitch = 90 elif pitch < -90: pitch = -90 trans1 = Mat4.translateMat(self.focus) rotx = Mat4.rotateMat(heading, Vec3(0, 0, 1)) roty = Mat4.rotateMat(pitch, Vec3(1, 0, 0)) trans2 = Mat4.translateMat(0, -self.initialTranslation, 0) rotation = trans2 * roty * rotx * trans1 base.camera.setMat(rotation) self.eventDispatcher.dispatchEvent(EVT_CAMERA_MOVE, base.camera) self.lastMousePos = Vec2(mpos) return Task.cont
def check_mouse1drag(self): """ this function uses a collision sphere to track the rotational mouse motion :return: author: weiwei date: 20200315 """ curm1pos = self.get_world_mouse1() if curm1pos is None: if self.lastm1pos is not None: self.lastm1pos = None return if self.lastm1pos is None: # first time click self.lastm1pos = curm1pos return curm1vec = Vec3(curm1pos - self.lookatpos_pdv3) lastm1vec = Vec3(self.lastm1pos - self.lookatpos_pdv3) curm1vec.normalize() lastm1vec.normalize() rotatevec = curm1vec.cross(lastm1vec) if rotatevec.length() > 1e-9: # avoid zero length rotateangle = curm1vec.signedAngleDeg(lastm1vec, rotatevec) rotateangle = rotateangle * self.camdist * 5000 if rotateangle > .02 or rotateangle < -.02: rotmat = Mat4(self.base.cam.getMat()) posvec = Vec3(self.base.cam.getPos()) rotmat.setRow(3, Vec3(0, 0, 0)) self.base.cam.setMat(rotmat * Mat4.rotateMat(rotateangle, rotatevec)) self.base.cam.setPos(Mat3.rotateMat(rotateangle, rotatevec). \ xform(posvec - self.lookatpos_pdv3) + self.lookatpos_pdv3) self.lastm1pos = self.get_world_mouse1() self.update_trackplane()
def genPandaRotmat4(self, icolevel=1, angles=[0, 45, 90, 135, 180, 225, 270, 315]): """ generate panda3d rotmat4 using icospheres and rotationaangle each origin-vertex vector of the icosphere :param icolevel, the default value 1 = 42vertices :param angles, 8 directions by default :return: a list of [pandarotmat4, ...] size of the inner list is size of the angles author: weiwei date: 20170221, tsukuba """ self.__icos = trimesh.creation.icosphere(icolevel) self.mat40list = [] initmat40 = self.objnp0.getMat() for vert in self.icos.vertices: self.__mat40list.append([]) self.objnp0.lookAt(vert[0], vert[1], vert[2]) ytozmat4 = Mat4.rotateMat(-90, self.objnp0.getMat().getRow3(0)) newobjmat4 = self.objnp0.getMat() * ytozmat4 for angle in angles: tmppandamat4 = Mat4.rotateMat(angle, newobjmat4.getRow3(2)) tmppandamat4 = newobjmat4 * tmppandamat4 self.__mat40list[-1].append(tmppandamat4) self.objnp0.setMat(initmat40) self.__floatingposemat40 = [e for l in self.__mat40list for e in l] self.mat41list = [] initmat41 = self.objnp1.getMat() for vert in self.icos.vertices: self.__mat41list.append([]) self.objnp1.lookAt(vert[0], vert[1], vert[2]) ytozmat4 = Mat4.rotateMat(-90, self.objnp1.getMat().getRow3(0)) newobjmat4 = self.objnp1.getMat() * ytozmat4 for angle in angles: tmppandamat4 = Mat4.rotateMat(angle, newobjmat4.getRow3(2)) tmppandamat4 = newobjmat4 * tmppandamat4 self.__mat41list[-1].append(tmppandamat4) self.objnp1.setMat(initmat41) self.__floatingposemat41 = [e for l in self.__mat41list for e in l] return self.__floatingposemat40, self.__floatingposemat41
def rotsToMat4(x, y, z): rotx = Mat4(1, 0, 0, 0, 0, cos(x), -sin(x), 0, 0, sin(x), cos(x), 0, 0, 0, 0, 1) roty = Mat4(cos(y), 0, sin(y), 0, 0, 1, 0, 0, -sin(y), 0, cos(y), 0, 0, 0, 0, 1) rotz = Mat4(cos(z), -sin(z), 0, 0, sin(z), cos(z), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) swapyz = Mat4.rotateMat(90, Vec3(-1, 0, 0)) return rotx * roty * rotz * swapyz
def handleDragging(self, task): """ Does the actual work of manipulating objects, once the needed attributes have been setup by handleManipulationSetup(). """ if not self.isDragging: return task.done mPos3D = Point3(0.0) # # This section handles the actual translating rotating or scale after it's been set up in mouse1SetupManip...() # ONLY one operation is preformed per frame if self.currTransformOperation == self.transformOpEnum.trans: # 1st translation, rotation's section is at next elif if self.getMousePlaneIntersect(mPos3D, self.currPlaneColNorm): # get the difference between the last mouse and this frames mouse selectedNewPos = mPos3D - self.interFrameMousePosition # store this frames mouse self.interFrameMousePosition = mPos3D # add the difference to the selected object's pos self.selected.setPos(render, self.selected.getPos(render).x + self.currTransformDir.x * selectedNewPos.x, self.selected.getPos(render).y + self.currTransformDir.y * selectedNewPos.y, self.selected.getPos(render).z + self.currTransformDir.z * selectedNewPos.z) self.grabModelNP.setPos(render, self.selected.getPos(render)) elif self.currTransformOperation == self.transformOpEnum.rot: # 2nd rotation, followed finally by scaling # if operating on the z-axis, use the y (vertical screen coordinates otherwise use x (horizontal) mPos = base.mouseWatcherNode.getMouse() #rotMag = 0.0 if self.currTransformDir == Vec3( 0.0, 0.0, 1.0): rotMag = (mPos.x - self.interFrameMousePosition.x) * 1000 else: rotMag = (self.interFrameMousePosition.y - mPos.y) * 1000 initPos = self.selected.getPos() initPar = self.selected.getParent() self.selected.wrtReparentTo(render) self.selected.setMat(self.selected.getMat() * Mat4.rotateMat(rotMag, self.currTransformDir)) self.selected.wrtReparentTo(initPar) self.selected.setPos(initPos) self.interFrameMousePosition = Point3(mPos.x, mPos.y, 0.0) elif self.currTransformOperation == self.transformOpEnum.scale: # 3rd and final is scaling mPos = base.mouseWatcherNode.getMouse() # TODO: make dragging away from the object larger and to the object smaller (not simply left right up down) # td The problem with this MAY come if negative, mirrored, scaling is implemented. # if operating on the z-axis, use the y (vertical screen coordinates otherwise use x (horizontal) if self.currTransformDir == Point3( 0.0, 0.0, 1.0): sclMag = (mPos.y - self.interFrameMousePosition.y) * 5.5 elif self.currTransformDir == Point3( 0.0, 1.0, 0.0): sclMag = (mPos.x - self.interFrameMousePosition.x) * 5.5 else: sclMag = (self.interFrameMousePosition.x - mPos.x) * 5.5 # This is the line that prevents scaling past the origin. Flipping the faces doesn't seem to work. if -0.0001 < sclMag < 0.0001: sclMag = 0.000001 # create a dummy node to parent to and position such that applying scale to it will scale selected properly dummy = self.levitorNP.attachNewNode('dummy') initScl = dummy.getScale() # Don't forget the parent. Selected needs put back in place initPar = self.selected.getParent() initPos = self.selected.getPos() self.selected.wrtReparentTo(dummy) dummy.setScale(initScl.x + sclMag * self.currTransformDir.x, initScl.y + sclMag * self.currTransformDir.y, initScl.z + sclMag * self.currTransformDir.z) # reset selected's parent then destroy dummy self.selected.wrtReparentTo(initPar) self.selected.setPos(initPos) dummy.removeNode() dummy = None self.interFrameMousePosition = Point3( mPos.x, mPos.y, 0.0) else: self.notify.error("Err: Dragging with invalid curTransformOperation enum in handleDragging") return task.cont # ended by handleM1Up(), the mouse1-up event handler
def rotsToMat4(x, y, z): rotx = Mat4(1,0,0,0,0,cos(x),-sin(x),0,0,sin(x),cos(x),0,0,0,0,1); roty = Mat4(cos(y),0,sin(y),0,0,1,0,0,-sin(y),0,cos(y),0,0,0,0,1); rotz = Mat4(cos(z),-sin(z),0,0,sin(z),cos(z),0,0,0,0,1,0,0,0,0,1); swapyz = Mat4.rotateMat(90, Vec3(-1,0,0)) return rotx * roty * rotz * swapyz