示例#1
0
    def __init__(self, length = 0.4, cyradius = 0.005, coradius = 0.075, mid=0.80, parent=None):
        """
        Constructor.

        @param cyradius The radius of the cylinder used in the arrow shaft
        @param coradius The radius of the cone used in the arrow tip
        @param mid      The "mid point" or the percentage [0,1] along the length where the cylinder and cone join
        @param parent   The parent SceneGraphNode instance.
        """
        super(GnomonNode, self).__init__(self.__description__, parent)

        self.__length = length
        self.__o = Vector3D();
        self.__x = Vector3D(length, 0, 0)
        self.__y = Vector3D(0, length, 0)
        self.__z = Vector3D(0, 0, length)
        self.__mid = mid
        self.__cyradius = cyradius
        self.__coradius = coradius
        self._updateGeometry()
示例#2
0
    def paint_enter(self):
        """
        Implements the GLNodeAdapter's paint_enter method for an OpenGL Render operation.
        """
        GL.glPushAttrib(GL.GL_ENABLE_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_LINE_BIT | GL.GL_CURRENT_BIT)
        GL.glPushClientAttrib(GL.GL_CLIENT_VERTEX_ARRAY_BIT)
        GL.glMatrixMode(GL.GL_MODELVIEW)
        GL.glPushMatrix()
        GL.glMultMatrixf(self._node.matrix().data())
        GL.glColor(self._node.color.getRgbF())
        
        # The positive Z-axis is the default direction for Cylinder Quadrics in OpenGL.
        # If our vector is not parallel to the z-axis, e.g. (0, 0, Z), then rotate it.
        #   1) Get a normal from the z-v plane
        #   2) Get the angle inbetween z-v on the plane (see vector dot product)
        #   3) Rotate the normal by that angle.
        v = self._node.axis
        m = Matrix4x4.identity()
        if v.x != 0 or v.y != 0:
            zaxis  = Vector3D(0,0,1)
            angle  = zaxis.angle(v)
            normal = zaxis.crossproduct(v, True)
            m *= Matrix4x4.rotation(angle, normal)

        # The positive Z-axis is the default direction fo Cylinder Quadrics in OpenGL.
        # If our z is negative, we need to flip the cylinder
        if v.z < 0:
            yaxis  = Vector3D(1,0,0)
            m *= Matrix4x4.rotation(math.radians(180), yaxis)       
        GL.glMultMatrixf(m.data())

        q = self.__quadric
        r = self._node.radius
        h = self._node.length
        sl = self._node.slices
        st = self._node.stacks
        lp = self._node.loops
        GLU.gluQuadricDrawStyle (q, GLU.GLU_FILL)
        GLU.gluQuadricNormals (q, GLU.GLU_SMOOTH)
        GLU.gluQuadricOrientation(q, GLU.GLU_OUTSIDE)
        self._glcylinder(q, r, h, sl, st, lp)
示例#3
0
    def __init__(self, direction=None):
        """
        Constructor.

        @param direction The Translation direction vector.
        """
        super(TranslationComponent, self).__init__()
        self.__direction = None
        self.blockSignals(True)
        self.direction = direction or Vector3D(0, 0, 0)
        self.blockSignals(False)
        self._updateMatrix()
示例#4
0
    def __init__(self, length = 0.5, width = 0.5, normal = Vector3D(0,1,0), parent=None):
        """
        Constructor.

        @param length   The length of one dimension of the plane.
        @param width    The length of one dimension of the plane.
        @param normal   The surface normal of the plane.
        @param parent   The parent SceneGraphNode instance.
        """
        super(PlaneNode, self).__init__(self.__description__, parent)
        self.__length = length
        self.__width = width
        self.__normal = normal
示例#5
0
    def __init__(self, radius = 1.0, length = 1, axis=Vector3D(0,1,0), parent=None):
        """
        Constructor.

        @param radius   The radius of the cylinder base.
        @param length   The length of the cylinder.
        @param axis     The axis of the cylinder.
        @param parent   The parent SceneGraphNode instance.
        """
        super(CylinderNode, self).__init__(self.__description__, parent)
        self.__radius = radius
        self.__length = length
        self.__axis = axis
示例#6
0
    def __init__(self, spacing=0.5, count = 14, normal=Vector3D(0,1,0), parent=None):
        """
        Constructor.

        @param count    The number of lines in the grid.
        @param space    The spaceing between lines.
        @param length   The length of one dimension of the plane.
        @param width    The length of one dimension of the plane.
        @param normal   The surface normal of the plane.
        @param parent   The parent SceneGraphNode instance.
        """
        super(GridNode, self).__init__(spacing * count, spacing * count, normal, parent)
        self.__spacing = spacing
        self.__count = count
示例#7
0
    def __init__(self, angle=0, axis=None, point=None):
        """
        Constructor.

        @param angle   The initial rotation angle (degrees).
        @param axis    The initial rotation axis.
        @param point   The initial rotation origin point.
        """
        super(RotationComponent, self).__init__()
        self.__angle = None
        self.__axis = None
        self.__point = None
        self.blockSignals(True)
        self.angle = angle
        self.axis = axis or Vector3D(0, 0, 0)
        self.point = point or Point3D(0, 0, 0)
        self.blockSignals(False)
        self._updateMatrix()
示例#8
0
文件: quadric.py 项目: dbarsam/kousen
    def __init__(self,
                 radius=1.0,
                 length=1,
                 axis=Vector3D(0, 1, 0),
                 slices=32,
                 stacks=1,
                 loops=1,
                 parent=None):
        """
        Constructor.

        @param radius   The radius of the cylinder base.
        @param length   The length of the cylinder.
        @param axis     The axis of the cylinder.
        @param slices   The number of subdivisions around the z-axis (similar to lines of longitude).
        @param stacks   The number of subdivisions along the z-axis (similar to lines of latitude).
        @param loops    The number of concentric rings about the origin into which the cylinder's base is subdivided.
        @param parent   The parent SceneGraphNode instance.
        """
        super(QuadricCylinderNode, self).__init__(radius, length, axis, parent)
        self.__stacks = stacks
        self.__slices = slices
        self.__loops = loops
示例#9
0
class CameraNode(ObjectNode, VirtualScreen):
    """
    The Camera Node provides Camera implementation of a AbstractSceneGraphItem.
    """
    # Additional Meta Information
    __category__     = "Camera Node"
    __icon__         = ":/icons/camera.png"
    __description__  = "Camera"
    __instantiable__ = True

    # Camera default values
    __camera_target__   = Point3D(0, 0, 0)
    __camera_position__ = Point3D(21, 28, 21)
    __camera_upvector__ = Vector3D(0, 1, 0)
    __camera_fov__      = 30.0    # (degrees)
    __camera_znear__    = 1.0
    __camera_zfar__     = 1000
    __camera_swidth__   = 1.0
    __camera_sheight__  = 1.0

    # The rotation speed; The amount of rotation (in degrees) that will occur
    # from dragging the mouse across the entire width of the screen.
    __camera_max_screen_rotation__ = 180.0

    def __init__(self, position=None, target=None, up=None, fov=None, znear=None, zfar=None, swidth=None, sheight=None, parent=None):        
        """
        Constructor.

        @param position The position of the camera (in world space). If None, it will default to CameraNode.__camera_target__.
        @param target   The camera target point (in world space).  If None, it will default to CameraNode.__camera_position__.
        @param up       The camera up point (in world space). If None, it will default to CameraNode.__camera_upvector__.
        @param fov      The field of view (in degrees). If None, it will default to CameraNode.__camera_fov__.
        @param znear    The distance from position to the near clipping plane. If None, it will default to CameraNode.__camera_znear__.
        @param zfar     The distance from position to the far clipping plane. If None, it will default to CameraNode.__camera_zfar__.
        @param swidth   The initial screen width (in pixels). If None, it will default to CameraNode.__camera_swidth__.
        @param sheight  The initial screen height (in pixels). If None, it will default to CameraNode.__camera_sheight__.
        @param parent   The parent AbstractSceneGraphItem instance.
        """
        super(CameraNode, self).__init__("camera", parent)
        # Register the 'reset' data
        self._restore['_znear']        = znear or self.__camera_znear__
        self._restore['_zfar']         = zfar or self.__camera_zfar__
        self._restore['_screenwidth']  = swidth  or self.__camera_swidth__
        self._restore['_screenheight'] = sheight or self.__camera_sheight__
        self._restore['_fov']          = fov or self.__camera_fov__
        self._restore['_position']     = (position or self.__camera_position__).duplicate()
        self._restore['_target']       = (target or self.__camera_target__).duplicate()
        self._restore['_up']           = (up or self.__camera_upvector__).duplicate()
        self._restore['_viewport']     = self._generateViewport(self._restore['_fov'], self._restore['_screenwidth'], self._restore['_screenheight'], self._restore['_znear'])

        self.__projectionmatrix = None

        self.reset()
        self._updateProjectionMatrix()

    @property
    def znear(self):
        return self._znear;

    @property
    def zfar(self):
        return self._zfar;

    @property
    def screenwidth(self):
        return self._screenwidth;

    @property
    def screenheight(self):
        return self._screenheight;

    @property
    def fov(self):
        return self._fov;

    @property
    def position(self):
        return self._position;

    @property
    def target(self):
        return self._target;

    @property
    def up(self):
        return self._up;

    @property
    def viewport(self):
        return self._viewport;

    def _generateProjectionMatrix(self):
        """
        Generates a LookAt matrix from internal data.

        @returns A Matrix4x4 representation of camera's LookAt component.
        """
        return Matrix4x4.lookAt(self._position, self._target, self._up, False)

    def _generateViewport(self, fov, width, height, znear):
        """
        Generates a viewport from the dimensions.

        @param fov    The Field of View angle (in degrees).
        @param width  The screen width (in pixels).
        @param height The screen height (in pixels).
        @param znear  The z position of the near clipping plane.
        @returns      A tuple of (left, right, bottom, top) of the viewing frustrum at znear.
        """
        # Figure out the viewport rectangle that contains the conocircle along it's shortest
        # dimensions; maintain the ratio of the otherdimension.
        if width < height:
            znear_width  = conicwidth(fov, znear)
            znear_height = znear_width * height / width
        else:
            znear_height = conicwidth(fov, znear)
            znear_width  = znear_height * width / height

        # Center the viewport
        zleft   = - 0.5 * znear_width
        zright  =   0.5 * znear_width
        zbottom = - 0.5 * znear_height
        ztop    =   0.5 * znear_height

        return (zleft, zright, zbottom, ztop)

    def _updateProjectionMatrix(self):
        """
        Internal method to manually update the cached transformation matrix from internal data.
        """
        self.__projectionmatrix = self._generateProjectionMatrix()

    def projectionMatrix(self):
        """
        Returns the component pre-calcaulted transformation matrix.
        
        @returns A Matrix4x4 representation of the transformation component.
        """
        return self.__projectionmatrix

    def resize(self, width, height):
        """
        Resizes the virtual screen.
        """
        self._viewport = self._generateViewport(self._fov, width, height, self._znear)
        self._screenminsize = min(width, height)
        self._screenwidth = width
        self._screenheight = height

        self._rotationspeed = self.__camera_max_screen_rotation__ / self._screenminsize
        self._pixelradians = math.radians(self._rotationspeed)

    def tumble(self, hdelta, vdelta):
        """
        This is equivalent of rotating the camera around it's target point while maintaining the direction vector; to reflect the change in view the camera will be rotated by the additive inverse of the deltas.

        @param hdelta The horizontal delta (the up vector rotation)
        @param vdelta The vertical delta (the right vector rotation)

        @see Maya Rotation defintions (http://download.autodesk.com/global/docs/maya2013/en_us/index.html?url=files/Viewing_the_scene_Tumble_track_dolly_or_tilt_the_view.htm,topicNumber=d30e15213)
        @see Rotation algorithm (http://gamedev.stackexchange.com/questions/20758/how-can-i-orbit-a-camera-about-its-target-point)
        """
        # Get the current look at vector (e.g inverse direction)
        idirection = self._position - self._target

        # Rotate the y-axis (aka 'up' vector) which is the plane normal coming out of the x-z plane.
        # The x-z plane is typically the horizontal plane and the yaw angle is measured by the horizontal delta parameter.
        hrotation  = - hdelta * self._pixelradians
        M          = Matrix4x4.rotation( hrotation, self.__camera_upvector__ )
        idirection = M * idirection
        self._up   = M * self._up
        right      = (self._up ^ idirection).normalized()

        # Now rotate the x-axis (aka 'right' vector) which is the plane normal coming out of the y-z plane.
        # The y-z plane is typically the vertical plane and the pitch angle is measured by the vertical delta parameter.
        vrotation  = - vdelta * self._pixelradians
        M          = Matrix4x4.rotation( vrotation, right )
        idirection = M * idirection
        self._up   = M * self._up

        # Update the camera's position
        self._position = self._target + idirection
        
        self._updateProjectionMatrix()

    def roll(self, delta):
        """
        Executes a rotation operation around the z-axis

        This is equivalent of rotating the camera around it's z-axis; to reflect the change in view the camera will be rotated by the additive inverse of the delta.

        @param delta The rotation delta (the change in rotating around the direction vector)
        """
        # Get the current look at vector (e.g inverse direction)
        direction = self._target - self._position

        # Rotate the z-axis (aka 'look at' vector) which is the plane normal coming out of the x-y plane.
        # Since we're rotating the x-y plane, the concept of vertical or horizontal delta doesn't apply; it's
        # a straight up spin of the look at vector
        rotation = - delta * self._pixelradians
        M        = Matrix4x4.rotation( rotation, direction )
        self._up = M * self._up
        
        self._updateProjectionMatrix()

    def track( self, hdelta, vdelta ):
        """
        Executes a translate operation the x-y axis.

        This is equivalent of moving the scene along the x-y axis; to reflect the change in view the camera will be translated by the additive inverse of the deltas.

        @param hdelta The horizontal delta (the change in distance along the right vector)
        @param vdelta The vertical delta (the change in distance along the up vector)
        """
        # We need to calculation a ratio of pixels to world units for speed.
        # Get the direction vector (normalized) and the distance.
        direction = self._target - self._position
        distance  = direction.length()
        direction = direction.normalized()

        # Get the view width at the point along the z-axis and build a pixels to unit ratio
        viewwidth = conicwidth(self._fov, distance)
        factor = viewwidth / self._screenminsize

        # Update the right vector
        right = direction ^ self._up

        # Calcaulte the x-y axis translation vector
        translation = right * (- hdelta * factor) + self._up * (- vdelta * factor)

        # Move the Position and Target
        self._position += translation
        self._target += translation

        self._updateProjectionMatrix()

    def dolly( self, delta ):
        """
        Executes a translate operation the z-axis.

        This is equivalent of moving the camera along the z-axis; to reflect the change in view the camera will be translated by the additive inverse of the delta.

        @param delta The translation delta (the change in distance along the direction vector)
        """
        # We need to calculation a ratio of pixels to world units for speed.
        # Get the direction vector (normalized) and the distance.
        direction = self._target - self._position
        distance  = direction.length()
        direction = direction.normalized()

        # Get the view width at the point along the z-axis and build a pixels to unit ratio
        viewwidth = conicwidth(self._fov, distance)
        factor = viewwidth / self._screenminsize

        # Calculate the translation along the direction vector
        translation = direction * (- delta * factor)

        # Move the Position only; the look at point reamins unchanged.
        self._position += translation

        self._updateProjectionMatrix()

    def zoom( self, delta ):
        """
        Executes a zoom operation.

        This is equivalent of zooming into the scene without moving the camera; to reflect the change in view the camera fov will be scaled by the additive inverse of the delta.

        @param delta The fov delta (the change in fov, in degrees)
        @see http://gamedev.stackexchange.com/questions/30357/3d-zooming-technique-to-maintain-the-relative-position-of-an-object-on-screen
        """
        # Clamp the __camera_fov__ (in degrees) to 1 and 180
        self._fov  = sorted((1, self._fov - delta, 180))[1]
        self._viewport = self._generateViewport(self._fov, self._screenwidth, self._screenheight, self._znear)