Esempio n. 1
0
    def canvasToWorld(self, xpos, ypos):
        """Transform the given x/y canvas coordinates into the display
        coordinate system.
        """

        b = self.__displayCtx.bounds
        width, height = self.GetSize()

        # The first step is to invert the mouse
        # coordinates w.r.t. the viewport.
        #
        # The canvas x axis corresponds to
        # (-xhalf, xhalf), and the canvas y
        # corresponds to (-yhalf, yhalf) -
        # see routines.show3D.
        xlen, ylen = glroutines.adjust(b.xlen, b.ylen, width, height)
        xhalf = 0.5 * xlen
        yhalf = 0.5 * ylen

        # Pixels to viewport coordinates
        xpos = xlen * (xpos / float(width)) - xhalf
        ypos = ylen * (ypos / float(height)) - yhalf

        # The second step is to transform from
        # viewport coords into model-view coords.
        # This is easy - transform by the inverse
        # MV matrix.
        #
        # z=-1 because the camera is offset by 1
        # on the depth axis (see __setViewport).
        pos = np.array([xpos, ypos, -1])
        xform = transform.invert(self.__viewMat)
        pos = transform.transform(pos, xform)

        return pos
Esempio n. 2
0
    def updateVertices(self, *a):
        """Called by :meth:`__init__`, and when certain display properties
        change. (Re-)generates the mesh vertices, indices and normals (if
        being displayed in 3D). They are stored as attributes called
        ``vertices``, ``indices``, and ``normals`` respectively.
        """

        overlay = self.overlay
        vertices = overlay.vertices
        indices = overlay.indices
        normals = self.overlay.vnormals
        xform = self.opts.getCoordSpaceTransform()

        if not np.all(np.isclose(xform, np.eye(4))):
            vertices = transform.transform(vertices, xform)

            if self.threedee:
                nmat = transform.invert(xform).T
                normals = transform.transform(normals, nmat, vector=True)

        self.vertices = np.array(vertices, dtype=np.float32)
        self.indices = np.array(indices.flatten(), dtype=np.uint32)

        if self.threedee:
            self.normals = np.array(normals, dtype=np.float32)
Esempio n. 3
0
    def draw3D(self, *args, **kwargs):
        """Calls the version dependent ``draw3D`` function. """

        opts = self.opts
        w, h = self.canvas.GetSize()
        res = self.opts.resolution / 100.0
        w = int(np.ceil(w * res))
        h = int(np.ceil(h * res))

        # Initialise and resize
        # the offscreen textures
        for rt in [self.renderTexture1, self.renderTexture2]:
            if rt.getSize() != (w, h):
                rt.setSize(w, h)

            rt.bindAsRenderTarget()
            gl.glClearColor(0, 0, 0, 0)
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
            rt.unbindAsRenderTarget()

        if opts.resolution != 100:
            gl.glViewport(0, 0, w, h)

        # Do the render. Even though we're
        # drawing off-screen,  we need to
        # enable depth-testing, otherwise
        # depth values will not get written
        # to the depth buffer!
        with glroutines.enabled((gl.GL_DEPTH_TEST, gl.GL_CULL_FACE)):
            gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL)
            gl.glFrontFace(gl.GL_CCW)
            gl.glCullFace(gl.GL_BACK)
            fslgl.glvolume_funcs.draw3D(self, *args, **kwargs)

        # renderTexture1 should now
        # contain the final result -
        # draw it to the screen.
        verts = np.array([[-1, -1, 0], [-1, 1, 0], [1, -1, 0], [1, -1, 0],
                          [-1, 1, 0], [1, 1, 0]],
                         dtype=np.float32)

        invproj = transform.invert(self.canvas.getProjectionMatrix())
        verts = transform.transform(verts, invproj)

        if opts.resolution != 100:
            w, h = self.canvas.GetSize()
            gl.glViewport(0, 0, w, h)

        with glroutines.enabled((gl.GL_DEPTH_TEST)):
            self.renderTexture1.draw(verts, useDepth=True)
Esempio n. 4
0
def draw(self, glType, vertices, indices=None, normals=None, vdata=None):
    """Called for 3D meshes, and :attr:`.MeshOpts.vertexData` is not
    ``None``. Loads and runs the shader program.


    :arg glType:   The OpenGL primitive type.

    :arg vertices: ``(n, 3)`` array containing the line vertices to draw.

    :arg indices:  Indices into the ``vertices`` array. If not provided,
                   ``glDrawArrays`` is used.

    :arg normals:  Vertex normals.

    :arg vdata:    ``(n, )`` array containing data for each vertex.
    """

    shader = self.activeShader

    if normals is not None: shader.setAtt('normal', normals)
    if vdata is not None: shader.setAtt('vertexData', vdata.reshape(-1, 1))

    if normals is not None:

        # NOTE You are assuming here that the canvas
        #      view matrix is the GL model view matrix.
        normalMatrix = self.canvas.viewMatrix
        normalMatrix = transform.invert(normalMatrix).T

        shader.setVertParam('normalMatrix', normalMatrix)

    shader.loadAtts()

    nvertices = vertices.shape[0]
    vertices = vertices.ravel('C')

    with glroutines.enabled((gl.GL_VERTEX_ARRAY)):
        gl.glVertexPointer(3, gl.GL_FLOAT, 0, vertices)

        if indices is None:
            gl.glDrawArrays(glType, 0, nvertices)
        else:
            gl.glDrawElements(glType, indices.shape[0], gl.GL_UNSIGNED_INT,
                              indices.ravel('C'))
Esempio n. 5
0
    def __setViewport(self):
        """Called by :meth:`_draw`. Configures the viewport and calculates
        the model-view trasformation matrix.

        :returns: ``True`` if the viewport was successfully configured,
                  ``False`` otherwise.
        """

        width, height = self.GetScaledSize()
        b = self.__displayCtx.bounds
        blo = [b.xlo, b.ylo, b.zlo]
        bhi = [b.xhi, b.yhi, b.zhi]
        zoom = self.opts.zoom / 100.0

        if width == 0 or height == 0:
            return False

        # We allow one dimension to be
        # flat, so we can display 2D
        # meshes (e.g. flattened surfaces)
        if np.sum(np.isclose(blo, bhi)) > 1:
            return False

        # Generate the view and projection matrices
        self.__genViewMatrix(width, height)
        projmat, viewport = glroutines.ortho(blo, bhi, width, height, zoom)
        self.__projMat = projmat
        self.__viewport = viewport
        self.__invViewProjMat = transform.concat(self.__projMat,
                                                 self.__viewMat)
        self.__invViewProjMat = transform.invert(self.__invViewProjMat)

        gl.glViewport(0, 0, width, height)
        gl.glMatrixMode(gl.GL_PROJECTION)
        gl.glLoadMatrixf(self.__projMat.ravel('F'))
        gl.glMatrixMode(gl.GL_MODELVIEW)
        gl.glLoadIdentity()

        return True
Esempio n. 6
0
    def calculateRayCastSettings(self, view=None, proj=None):
        """Calculates various parameters required for 3D ray-cast rendering
        (see the :class:`.GLVolume` class).


        :arg view: Transformation matrix which transforms from model
                   coordinates to view coordinates (i.e. the GL view matrix).


        :arg proj: Transformation matrix which transforms from view coordinates
                   to normalised device coordinates (i.e. the GL projection
                   matrix).

        Returns a tuple containing:

          - A vector defining the amount by which to move along a ray in a
            single iteration of the ray-casting algorithm. This can be added
            directly to the volume texture coordinates.

          - A transformation matrix which transforms from image texture
            coordinates into the display coordinate system.

        .. note:: This method will raise an error if called on a
                  ``GLImageObject`` which is managing an overlay that is not
                  associated with a :class:`.Volume3DOpts` instance.
        """

        if view is None: view = np.eye(4)
        if proj is None: proj = np.eye(4)

        # In GL, the camera position
        # is initially pointing in
        # the -z direction.
        eye = [0, 0, -1]
        target = [0, 0, 1]

        # We take this initial camera
        # configuration, and transform
        # it by the inverse modelview
        # matrix
        t2dmat = self.getTransform('texture', 'display')
        xform = transform.concat(view, t2dmat)
        ixform = transform.invert(xform)

        eye = transform.transform(eye, ixform, vector=True)
        target = transform.transform(target, ixform, vector=True)

        # Direction that the 'camera' is
        # pointing, normalied to unit length
        cdir = transform.normalise(eye - target)

        # Calculate the length of one step
        # along the camera direction in a
        # single iteration of the ray-cast
        # loop. Multiply by sqrt(3) so that
        # the maximum number of steps will
        # be reached across the longest axis
        # of the image texture cube.
        rayStep = np.sqrt(3) * cdir / self.getNumSteps()

        # A transformation matrix which can
        # transform image texture coordinates
        # into the corresponding screen
        # (normalised device) coordinates.
        # This allows the fragment shader to
        # convert an image texture coordinate
        # into a relative depth value.
        #
        # The projection matrix puts depth into
        # [-1, 1], but we want it in [0, 1]
        zscale = transform.scaleOffsetXform([1, 1, 0.5], [0, 0, 0.5])
        xform = transform.concat(zscale, proj, xform)

        return rayStep, xform
Esempio n. 7
0
    def draw3D(self, *args, **kwargs):
        """Calls the version dependent ``draw3D`` function. """

        opts = self.opts
        w, h = self.canvas.GetScaledSize()
        res = self.opts.resolution / 100.0
        sw = int(np.ceil(w * res))
        sh = int(np.ceil(h * res))

        # Initialise and resize
        # the offscreen textures
        for rt in [self.renderTexture1, self.renderTexture2]:
            if rt.getSize() != (sw, sh):
                rt.setSize(sw, sh)

            with rt.bound():
                gl.glClearColor(0, 0, 0, 0)
                gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)

        if opts.resolution != 100:
            gl.glViewport(0, 0, sw, sh)

        # Do the render. Even though we're
        # drawing off-screen,  we need to
        # enable depth-testing, otherwise
        # depth values will not get written
        # to the depth buffer!
        #
        # The glvolume_funcs.draw3D function
        # will put the final render into
        # renderTexture1
        with glroutines.enabled((gl.GL_DEPTH_TEST, gl.GL_CULL_FACE)):
            gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL)
            gl.glFrontFace(gl.GL_CCW)
            gl.glCullFace(gl.GL_BACK)
            fslgl.glvolume_funcs.draw3D(self, *args, **kwargs)

        # Apply smoothing if needed. If smoothing
        # is enabled, the final final render will
        # be in renderTexture2
        if opts.smoothing > 0:
            self.smoothFilter.set(offsets=[1.0 / sw, 1.0 / sh])
            self.smoothFilter.osApply(self.renderTexture1, self.renderTexture2)

        # We now have the final result
        # - draw it to the screen.
        verts = np.array([[-1, -1, 0], [-1, 1, 0], [1, -1, 0], [1, -1, 0],
                          [-1, 1, 0], [1, 1, 0]],
                         dtype=np.float32)

        invproj = transform.invert(self.canvas.projectionMatrix)
        verts = transform.transform(verts, invproj)

        if opts.resolution != 100:
            gl.glViewport(0, 0, w, h)

        with glroutines.enabled(gl.GL_DEPTH_TEST):

            # If smoothing was not applied, rt1
            # contains the final render. Otherwise,
            # rt2 contains the final render, but rt1
            # contains the depth information. So we
            # need to # temporarily replace rt2.depth
            # with rt1.depth.
            if opts.smoothing > 0:
                src = self.renderTexture2
                olddep = self.renderTexture2.depthTexture
                dep = self.renderTexture1.depthTexture
            else:
                src = self.renderTexture1
                olddep = self.renderTexture1.depthTexture
                dep = olddep

            src.depthTexture = dep
            src.draw(verts, useDepth=True)
            src.depthTexture = olddep
Esempio n. 8
0
    def __setupTransforms(self):
        """Calculates transformation matrices between all of the possible
        spaces in which the overlay may be displayed.

        These matrices are accessible via the :meth:`getTransform` method.
        """

        image = self.overlay
        shape = np.array(image.shape[:3])

        voxToIdMat = np.eye(4)
        voxToPixdimMat = np.diag(list(image.pixdim[:3]) + [1.0])
        voxToPixFlipMat = image.voxToScaledVoxMat
        voxToWorldMat = image.voxToWorldMat
        voxToWorldMat = transform.concat(self.displayXform, voxToWorldMat)
        ds = self.displayCtx.displaySpace

        # The reference transforms depend on the value of
        # displaySpace
        if ds == 'world':
            voxToRefMat = voxToWorldMat
        elif ds is self.overlay:
            voxToRefMat = voxToPixFlipMat
        else:
            voxToRefMat = transform.concat(ds.voxToScaledVoxMat,
                                           ds.worldToVoxMat, voxToWorldMat)

        # When going from voxels to textures,
        # we add 0.5 to centre the voxel (see
        # the note on coordinate systems at
        # the top of this file).
        voxToTexMat = transform.scaleOffsetXform(tuple(1.0 / shape),
                                                 tuple(0.5 / shape))

        idToVoxMat = transform.invert(voxToIdMat)
        idToPixdimMat = transform.concat(voxToPixdimMat, idToVoxMat)
        idToPixFlipMat = transform.concat(voxToPixFlipMat, idToVoxMat)
        idToWorldMat = transform.concat(voxToWorldMat, idToVoxMat)
        idToRefMat = transform.concat(voxToRefMat, idToVoxMat)
        idToTexMat = transform.concat(voxToTexMat, idToVoxMat)

        pixdimToVoxMat = transform.invert(voxToPixdimMat)
        pixdimToIdMat = transform.concat(voxToIdMat, pixdimToVoxMat)
        pixdimToPixFlipMat = transform.concat(voxToPixFlipMat, pixdimToVoxMat)
        pixdimToWorldMat = transform.concat(voxToWorldMat, pixdimToVoxMat)
        pixdimToRefMat = transform.concat(voxToRefMat, pixdimToVoxMat)
        pixdimToTexMat = transform.concat(voxToTexMat, pixdimToVoxMat)

        pixFlipToVoxMat = transform.invert(voxToPixFlipMat)
        pixFlipToIdMat = transform.concat(voxToIdMat, pixFlipToVoxMat)
        pixFlipToPixdimMat = transform.concat(voxToPixdimMat, pixFlipToVoxMat)
        pixFlipToWorldMat = transform.concat(voxToWorldMat, pixFlipToVoxMat)
        pixFlipToRefMat = transform.concat(voxToRefMat, pixFlipToVoxMat)
        pixFlipToTexMat = transform.concat(voxToTexMat, pixFlipToVoxMat)

        worldToVoxMat = transform.invert(voxToWorldMat)
        worldToIdMat = transform.concat(voxToIdMat, worldToVoxMat)
        worldToPixdimMat = transform.concat(voxToPixdimMat, worldToVoxMat)
        worldToPixFlipMat = transform.concat(voxToPixFlipMat, worldToVoxMat)
        worldToRefMat = transform.concat(voxToRefMat, worldToVoxMat)
        worldToTexMat = transform.concat(voxToTexMat, worldToVoxMat)

        refToVoxMat = transform.invert(voxToRefMat)
        refToIdMat = transform.concat(voxToIdMat, refToVoxMat)
        refToPixdimMat = transform.concat(voxToPixdimMat, refToVoxMat)
        refToPixFlipMat = transform.concat(voxToPixFlipMat, refToVoxMat)
        refToWorldMat = transform.concat(voxToWorldMat, refToVoxMat)
        refToTexMat = transform.concat(voxToTexMat, refToVoxMat)

        texToVoxMat = transform.invert(voxToTexMat)
        texToIdMat = transform.concat(voxToIdMat, texToVoxMat)
        texToPixdimMat = transform.concat(voxToPixdimMat, texToVoxMat)
        texToPixFlipMat = transform.concat(voxToPixFlipMat, texToVoxMat)
        texToWorldMat = transform.concat(voxToWorldMat, texToVoxMat)
        texToRefMat = transform.concat(voxToRefMat, texToVoxMat)

        self.__xforms['id', 'id'] = np.eye(4)
        self.__xforms['id', 'pixdim'] = idToPixdimMat
        self.__xforms['id', 'pixdim-flip'] = idToPixFlipMat
        self.__xforms['id', 'affine'] = idToWorldMat
        self.__xforms['id', 'reference'] = idToRefMat
        self.__xforms['id', 'texture'] = idToTexMat

        self.__xforms['pixdim', 'pixdim'] = np.eye(4)
        self.__xforms['pixdim', 'id'] = pixdimToIdMat
        self.__xforms['pixdim', 'pixdim-flip'] = pixdimToPixFlipMat
        self.__xforms['pixdim', 'affine'] = pixdimToWorldMat
        self.__xforms['pixdim', 'reference'] = pixdimToRefMat
        self.__xforms['pixdim', 'texture'] = pixdimToTexMat

        self.__xforms['pixdim-flip', 'pixdim-flip'] = np.eye(4)
        self.__xforms['pixdim-flip', 'id'] = pixFlipToIdMat
        self.__xforms['pixdim-flip', 'pixdim'] = pixFlipToPixdimMat
        self.__xforms['pixdim-flip', 'affine'] = pixFlipToWorldMat
        self.__xforms['pixdim-flip', 'reference'] = pixFlipToRefMat
        self.__xforms['pixdim-flip', 'texture'] = pixFlipToTexMat

        self.__xforms['affine', 'affine'] = np.eye(4)
        self.__xforms['affine', 'id'] = worldToIdMat
        self.__xforms['affine', 'pixdim'] = worldToPixdimMat
        self.__xforms['affine', 'pixdim-flip'] = worldToPixFlipMat
        self.__xforms['affine', 'reference'] = worldToRefMat
        self.__xforms['affine', 'texture'] = worldToTexMat

        self.__xforms['reference', 'reference'] = np.eye(4)
        self.__xforms['reference', 'id'] = refToIdMat
        self.__xforms['reference', 'pixdim'] = refToPixdimMat
        self.__xforms['reference', 'pixdim-flip'] = refToPixFlipMat
        self.__xforms['reference', 'affine'] = refToWorldMat
        self.__xforms['reference', 'texture'] = refToTexMat

        self.__xforms['texture', 'texture'] = np.eye(4)
        self.__xforms['texture', 'id'] = texToIdMat
        self.__xforms['texture', 'pixdim'] = texToPixdimMat
        self.__xforms['texture', 'pixdim-flip'] = texToPixFlipMat
        self.__xforms['texture', 'affine'] = texToWorldMat
        self.__xforms['texture', 'reference'] = texToRefMat