コード例 #1
0
    def renderQuadInto(self, xsize, ysize, colortex=None, cmode = GraphicsOutput.RTMBindOrCopy, auxtex = None):

        buffer = self.createBuffer("filter-stage", xsize, ysize, colortex, cmode, auxtex)

        if (buffer == None):
            return None

        cm = CardMaker("filter-stage-quad")
        cm.setFrameFullscreenQuad()
        quad = NodePath(cm.generate())
        quad.setDepthTest(0)
        quad.setDepthWrite(0)
        quad.setColor(Vec4(1,0.5,0.5,1))

        quadcamnode = Camera("filter-quad-cam")
        lens = OrthographicLens()
        lens.setFilmSize(2, 2)
        lens.setFilmOffset(0, 0)
        lens.setNearFar(-1000, 1000)
        quadcamnode.setLens(lens)
        quadcam = quad.attachNewNode(quadcamnode)
        
        buffer.getDisplayRegion(0).setCamera(quadcam)
        buffer.getDisplayRegion(0).setActive(1)

        return quad, buffer
コード例 #2
0
 def _makeFullscreenCam(self):
     """ Create a orthographic camera for this buffer """
     bufferCam = Camera("BufferCamera")
     lens = OrthographicLens()
     lens.setFilmSize(2, 2)
     lens.setFilmOffset(0, 0)
     lens.setNearFar(-1000, 1000)
     bufferCam.setLens(lens)
     bufferCam.setCullBounds(OmniBoundingVolume())
     return bufferCam
コード例 #3
0
    def renderQuadInto(self, mul=1, div=1, align=1, depthtex=None, colortex=None, auxtex0=None, auxtex1=None):

        """ Creates an offscreen buffer for an intermediate
        computation. Installs a quad into the buffer.  Returns
        the fullscreen quad.  The size of the buffer is initially
        equal to the size of the main window.  The parameters 'mul',
        'div', and 'align' can be used to adjust that size. """

        texgroup = (depthtex, colortex, auxtex0, auxtex1)

        winx, winy = self.getScaledSize(mul, div, align)
        
        depthbits = bool(depthtex != None)

        buffer = self.createBuffer("filter-stage", winx, winy, texgroup, depthbits)

        if (buffer == None):
            return None

        cm = CardMaker("filter-stage-quad")
        cm.setFrameFullscreenQuad()
        quad = NodePath(cm.generate())
        quad.setDepthTest(0)
        quad.setDepthWrite(0)
        quad.setColor(1, 0.5, 0.5, 1)

        quadcamnode = Camera("filter-quad-cam")
        lens = OrthographicLens()
        lens.setFilmSize(2, 2)
        lens.setFilmOffset(0, 0)
        lens.setNearFar(-1000, 1000)
        quadcamnode.setLens(lens)
        quadcam = quad.attachNewNode(quadcamnode)

        dr = buffer.makeDisplayRegion((0, 1, 0, 1))
        dr.disableClears()
        dr.setCamera(quadcam)
        dr.setActive(True)
        dr.setScissorEnabled(False)

        # This clear stage is important if the buffer is padded, so that
        # any pixels accidentally sampled in the padded region won't
        # be reading from unititialised memory.
        buffer.setClearColor((0, 0, 0, 1))
        buffer.setClearColorActive(True)

        self.buffers.append(buffer)
        self.sizes.append((mul, div, align))
        
        return quad
コード例 #4
0
    def makeCamera(self,
                   win,
                   sort=0,
                   scene=None,
                   displayRegion=(0, 1, 0, 1),
                   stereo=None,
                   aspectRatio=None,
                   clearDepth=0,
                   clearColor=None,
                   lens=None,
                   camName='cam',
                   mask=None,
                   useCamera=None):
        """
        Makes a new 3-d camera associated with the indicated window,
        and creates a display region in the indicated subrectangle.

        If stereo is True, then a stereo camera is created, with a
        pair of DisplayRegions.  If stereo is False, then a standard
        camera is created.  If stereo is None or omitted, a stereo
        camera is created if the window says it can render in stereo.

        If useCamera is not None, it is a NodePath to be used as the
        camera to apply to the window, rather than creating a new
        camera.
        """
        # self.camera is the parent node of all cameras: a node that
        # we can move around to move all cameras as a group.
        if self.camera == None:
            # We make it a ModelNode with the PTLocal flag, so that
            # a wayward flatten operations won't attempt to mangle the
            # camera.
            self.camera = self.render.attachNewNode(ModelNode('camera'))
            self.camera.node().setPreserveTransform(ModelNode.PTLocal)
            builtins.camera = self.camera

            self.mouse2cam.node().setNode(self.camera.node())

        if useCamera:
            # Use the existing camera node.
            cam = useCamera
            camNode = useCamera.node()
            assert (isinstance(camNode, Camera))
            lens = camNode.getLens()
            cam.reparentTo(self.camera)

        else:
            # Make a new Camera node.
            camNode = Camera(camName)
            if lens == None:
                lens = PerspectiveLens()

                if aspectRatio == None:
                    aspectRatio = self.getAspectRatio(win)
                lens.setAspectRatio(aspectRatio)

            cam = self.camera.attachNewNode(camNode)

        if lens != None:
            camNode.setLens(lens)

        if scene != None:
            camNode.setScene(scene)

        if mask != None:
            if (isinstance(mask, int)):
                mask = BitMask32(mask)
            camNode.setCameraMask(mask)

        if self.cam == None:
            self.cam = cam
            self.camNode = camNode
            self.camLens = lens

        self.camList.append(cam)

        # Now, make a DisplayRegion for the camera.
        if stereo is not None:
            if stereo:
                dr = win.makeStereoDisplayRegion(*displayRegion)
            else:
                dr = win.makeMonoDisplayRegion(*displayRegion)
        else:
            dr = win.makeDisplayRegion(*displayRegion)

        dr.setSort(sort)

        dr.disableClears()

        # By default, we do not clear 3-d display regions (the entire
        # window will be cleared, which is normally sufficient).  But
        # we will if clearDepth is specified.
        if clearDepth:
            dr.setClearDepthActive(1)

        if clearColor:
            dr.setClearColorActive(1)
            dr.setClearColor(clearColor)

        dr.setCamera(cam)

        return cam
コード例 #5
0
class ShadowSource(DebugObject, ShaderStructElement):
    """ This class can be seen as a camera. It stores the necessary data to 
    generate and store the shadow map for the assigned lens (like computing the MVP), 
    and also stores information about the shadowmap, like position in the 
    shadow atlas, or resolution. Each ShadowSource has a unique index, 
    which is used by the lights to identify which sources belong to it.
    """

    # Store a global index for assigning unique ids to the instances
    _GlobalShadowIndex = 999

    @classmethod
    def getExposedAttributes(self):
        return {
            "resolution": "int",
            "atlasPos": "vec2",
            "mvp": "mat4",
            "nearPlane": "float",
            "farPlane": "float"
        }

    @classmethod
    def _generateUID(self):
        """ Generates an uid and returns that """
        self._GlobalShadowIndex += 1
        return self._GlobalShadowIndex

    def __init__(self):
        """ Creates a new ShadowSource. After the creation, a lens can be added
        with setupPerspectiveLens or setupOrtographicLens. """
        self.index = self._generateUID()
        DebugObject.__init__(self, "ShadowSource-" + str(self.index))
        ShaderStructElement.__init__(self)

        self.valid = False
        self.camera = Camera("ShadowSource-" + str(self.index))
        self.camera.setActive(False)
        self.cameraNode = NodePath(self.camera)
        self.cameraNode.reparentTo(Globals.render.find("RPCameraDummys"))
        self.cameraNode.hide()
        self.resolution = 512
        self.atlasPos = Vec2(0)
        self.doesHaveAtlasPos = False
        self.sourceIndex = 0
        self.mvp = UnalignedLMatrix4f()
        self.sourceIndex = -1
        self.nearPlane = 0.0
        self.farPlane = 1000.0
        self.converterYUR = None
        self.transforMat = TransformState.makeMat(
            Mat4.convertMat(
                Globals.base.win.getGsg().getInternalCoordinateSystem(),
                CSZupRight))

    def cleanup(self):
        """ Cleans up the shadow source """
        self.cameraNode.removeNode()

    def setFilmSize(self, size_x, size_y):
        """ Sets the film size of the source, this is equivalent to setFilmSize
        on a Lens. """
        self.lens.setFilmSize(size_x, size_y)
        self.rebuildMatrixCache()

    def getLens(self):
        """ Returns the source lens """
        return self.lens

    def getSourceIndex(self):
        """ Returns the assigned source index. The source index is the index
        of the ShadowSource in the ShadowSources array of the assigned
        Light. """
        return self.sourceIndex

    def getUID(self):
        """ Returns the uid of the shadow source """
        return self.index

    def setSourceIndex(self, index):
        """ Sets the source index of this source. This is called by the light,
        as only the light knows at which position this source is in the
        Sources array. """
        self.sourceIndex = index

    def computeMVP(self):
        """ Computes the modelViewProjection matrix for the lens. Actually,
        this is the worldViewProjection matrix, but for convenience it is
        called mvp. """

        self.rebuildMatrixCache()
        projMat = self.converterYUR
        # modelViewMat = self.transforMat.invertCompose(
        modelViewMat = Globals.render.getTransform(self.cameraNode).getMat()
        return UnalignedLMatrix4f(modelViewMat * projMat)

    def assignAtlasPos(self, x, y):
        """ Assigns this source a position in the shadow atlas. This is called
        by the shadow atlas. Coordinates are float from 0 .. 1 """
        self.atlasPos = Vec2(x, y)
        self.doesHaveAtlasPos = True

    def update(self):
        """ Updates the shadow source. Currently only recomputes the mvp and
        triggers an array update """
        self.mvp = self.computeMVP()
        self.onPropertyChanged()

    def getAtlasPos(self):
        """ Returns the assigned atlas pos, if present. Coordinates are float
        from 0 .. 1 """
        return self.atlasPos

    def hasAtlasPos(self):
        """ Returns Whether this ShadowSource has already a position in the
        shadow atlas, or is currently unassigned """
        return self.doesHaveAtlasPos

    def removeFromAtlas(self):
        """ Deletes the atlas coordinates, this gets called by the atlas after the
        Source got removed from the atlas """
        self.doesHaveAtlasPos = False
        self.atlasPos = Vec2(0)

    def setResolution(self, resolution):
        """ Sets the resolution in pixels of this shadow source. Has to be
        a multiple of the tileSize specified in LightManager """
        assert (resolution > 1 and resolution <= 8192)
        self.resolution = resolution

    def getResolution(self):
        """ Returns the resolution of the shadow source in pixels """
        return self.resolution

    def setupPerspectiveLens(self, near=0.1, far=100.0, fov=(90, 90)):
        """ Setups a PerspectiveLens with a given near plane, far plane
        and FoV. The FoV is a tuple in the format (Horizontal FoV, Vertical FoV) """
        self.lens = PerspectiveLens()
        self.lens.setNearFar(near, far)
        self.lens.setFov(fov[0], fov[1])
        self.camera.setLens(self.lens)
        self.nearPlane = near
        self.farPlane = far
        self.rebuildMatrixCache()

    def setLens(self, lens):
        """ Setups the ShadowSource to use an external lens """
        self.lens = lens
        self.camera.setLens(self.lens)
        self.nearPlane = lens.getNear()
        self.farPlane = lens.getFar()
        self.nearPlane = 0.5
        self.farPlane = 50.0
        self.rebuildMatrixCache()

    def setupOrtographicLens(self, near=0.1, far=100.0, filmSize=(512, 512)):
        """ Setups a OrtographicLens with a given near plane, far plane
        and film size. The film size is a tuple in the format (filmWidth, filmHeight)
        in world space. """
        self.lens = OrthographicLens()
        self.lens.setNearFar(near, far)
        self.lens.setFilmSize(*filmSize)
        self.camera.setLens(self.lens)
        self.nearPlane = near
        self.farPlane = far
        self.rebuildMatrixCache()

    def rebuildMatrixCache(self):
        """ Internal method to precompute a part of the MVP to improve performance"""
        self.converterYUR = self.lens.getProjectionMat()

    def setPos(self, pos):
        """ Sets the position of the source in world space """
        self.cameraNode.setPos(pos)

    def getPos(self):
        """ Returns the position of the source in world space """
        return self.cameraNode.getPos()

    def setHpr(self, hpr):
        """ Sets the rotation of the source in world space """
        self.cameraNode.setHpr(hpr)

    def lookAt(self, pos):
        """ Looks at a point (in world space) """
        self.cameraNode.lookAt(pos.x, pos.y, pos.z)

    def invalidate(self):
        """ Invalidates this shadow source, means telling the LightManager
        that the shadow map for this light should be rebuilt. Otherwise it
        won't get refreshed. """
        self.valid = False

    def setValid(self):
        """ The LightManager calls this after the shadow map got updated
        successfully """
        self.valid = True

    def isValid(self):
        """ Returns wether the shadow map is still valid or should be refreshed """
        return self.valid

    def __repr__(self):
        """ Returns a representative string of this instance """
        return "ShadowSource[id=" + str(self.index) + "]"

    def __hash__(self):
        return self.index

    def onUpdated(self):
        """ Gets called when shadow source was updated """
コード例 #6
0
class VoxelizePass(RenderPass):

    """ This pass manages voxelizing the scene from multiple directions to generate
    a 3D voxel grid. It handles the camera setup and provides a simple interface. """

    def __init__(self):
        RenderPass.__init__(self)

    def getID(self):
        return "VoxelizePass"

    def getRequiredInputs(self):
        return {
        }

    def setVoxelGridResolution(self, voxelGridResolution):
        """ Sets the voxel grid resolution, this is the amount of voxels in every
        direction, so the voxel grid will have voxelGridResolution**3 total voxels. """
        self.voxelGridResolution = voxelGridResolution

    def setVoxelGridSize(self, voxelGridSize):
        """ Sets the size of the voxel grid in world space units. This is the
        size going from the mid of the voxel grid, so the effective voxel grid
        will have twice the size specified in voxelGridSize """
        self.voxelGridSize = voxelGridSize

    def setPhotonScaleFactor(self, factor):
        """ Sets the density of the photon grid. A number of 1 means that for
        every bright voxel 1 photon will be spawned. A number of 4 for example
        means that for ever bright voxel 4x4x4 = 64 Photons will be spawned. """
        self.photonScaleFactor = factor

    def setActive(self, active):
        """ Enables and disables this pass """
        self.target.setActive(active)

    def initVoxelStorage(self):
        """ Creates t he 3D Texture to store the voxel generation grid """
        self.voxelGenTex = Texture("VoxelsTemp")
        self.voxelGenTex.setup3dTexture(self.voxelGridResolution.x, self.voxelGridResolution.y, 
                                        self.voxelGridResolution.z, Texture.TInt, Texture.FR32i)

        # Set appropriate filter types
        self.voxelGenTex.setMinfilter(SamplerState.FTNearest)
        self.voxelGenTex.setMagfilter(Texture.FTNearest)
        self.voxelGenTex.setWrapU(Texture.WMClamp)
        self.voxelGenTex.setWrapV(Texture.WMClamp)
        self.voxelGenTex.setWrapW(Texture.WMClamp)
        self.voxelGenTex.setClearColor(Vec4(0))

        # Register texture
        MemoryMonitor.addTexture("Voxel Temp Texture", self.voxelGenTex)

    def getVoxelTex(self):
        """ Returns a handle to the generated voxel texture """
        return self.voxelGenTex

    def clearGrid(self):
        """ Clears the voxel grid """
        self.voxelGenTex.clearImage()

    def create(self):
        # Create voxelize camera
        self.voxelizeCamera = Camera("VoxelizeScene")
        self.voxelizeCamera.setCameraMask(BitMask32.bit(4))
        self.voxelizeCameraNode = Globals.render.attachNewNode(self.voxelizeCamera)
        self.voxelizeLens = OrthographicLens()
        self.voxelizeLens.setFilmSize(self.voxelGridSize.x*2, self.voxelGridSize.y*2)
        self.voxelizeLens.setNearFar(0.0, self.voxelGridSize.x*2)
        self.voxelizeCamera.setLens(self.voxelizeLens)
        self.voxelizeCamera.setTagStateKey("VoxelizePassShader")
        Globals.render.setTag("VoxelizePassShader", "Default")

        # Create voxelize tareet
        self.target = RenderTarget("VoxelizePass")
        self.target.setSize(self.voxelGridResolution.x * self.photonScaleFactor)
        # self.target.setColorWrite(False)
        self.target.addColorTexture()
        self.target.setCreateOverlayQuad(False)
        self.target.setSource(self.voxelizeCameraNode, Globals.base.win)
        self.target.prepareSceneRender()
        self.target.setActive(False)

        self.target.getInternalRegion().setSort(-400)
        self.target.getInternalBuffer().setSort(-399)

    def voxelizeSceneFromDirection(self, gridPos, direction="x"):
        """ Voxelizes the scene from a given direction. This method handles setting 
        the camera position aswell as the near and far plane. If the pass was disabled,
        it also enables this pass.  """
        assert(direction in "x y z".split())
        self.setActive(True)

        if direction == "x":
            self.voxelizeLens.setFilmSize(self.voxelGridSize.y*2, self.voxelGridSize.z*2)
            self.voxelizeLens.setNearFar(0.0, self.voxelGridSize.x*2)
            self.voxelizeCameraNode.setPos(gridPos - Vec3(self.voxelGridSize.x, 0, 0))
            self.voxelizeCameraNode.lookAt(gridPos)
        elif direction == "y":
            self.voxelizeLens.setFilmSize(self.voxelGridSize.x*2, self.voxelGridSize.z*2)
            self.voxelizeLens.setNearFar(0.0, self.voxelGridSize.y*2)
            self.voxelizeCameraNode.setPos(gridPos - Vec3(0, self.voxelGridSize.y, 0))
            self.voxelizeCameraNode.lookAt(gridPos)
        elif direction == "z":
            self.voxelizeLens.setFilmSize(self.voxelGridSize.x*2, self.voxelGridSize.y*2)
            self.voxelizeLens.setNearFar(0.0, self.voxelGridSize.z*2)
            self.voxelizeCameraNode.setPos(gridPos + Vec3(0, 0, self.voxelGridSize.z))
            self.voxelizeCameraNode.lookAt(gridPos)

    def setShaders(self):
        """ Creates the tag state and loades the voxelizer shader """
        voxelizeShader = Shader.load(Shader.SLGLSL, 
            "Shader/GI/Voxelize.vertex",
            "Shader/GI/Voxelize.fragment")

        # Create tag state
        initialState = NodePath("VoxelizerState")
        initialState.setShader(voxelizeShader, 500)
        initialState.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullNone))
        initialState.setDepthWrite(False)
        initialState.setDepthTest(False)
        initialState.setAttrib(DepthTestAttrib.make(DepthTestAttrib.MNone))
        initialState.setShaderInput("giVoxelGenerationTex", self.voxelGenTex)

        # Apply tag state
        self.voxelizeCamera.setTagState("Default", initialState.getState())

        return [voxelizeShader]

    def getOutputs(self):
        return {
        }
コード例 #7
0
ファイル: SpotLight.py プロジェクト: swq0553/RenderPipeline
class SpotLight(Light, DebugObject):

    """ This light type simulates a SpotLight. It has a position
    and an orientation. """

    def __init__(self):
        """ Creates a new spot light. """
        Light.__init__(self)
        DebugObject.__init__(self, "SpotLight")
        self.typeName = "SpotLight"

        self.nearPlane = 0.5
        self.radius = 30.0
        self.spotSize = Vec2(30, 30)

        # Used to compute the MVP
        self.ghostCamera = Camera("PointLight")
        self.ghostCamera.setActive(False)
        self.ghostLens = PerspectiveLens()
        self.ghostLens.setFov(130)
        self.ghostCamera.setLens(self.ghostLens)
        self.ghostCameraNode = NodePath(self.ghostCamera)
        self.ghostCameraNode.reparentTo(Globals.render)
        self.ghostCameraNode.hide()

    def getLightType(self):
        """ Internal method to fetch the type of this light, used by Light """
        return LightType.Spot

    def _updateLens(self):
        """ Internal method which gets called when the lens properties changed """
        for source in self.shadowSources:
            source.rebuildMatrixCache()

    def cleanup(self):
        """ Internal method which gets called when the light got deleted """
        self.ghostCameraNode.removeNode()
        Light.cleanup(self)

    def setFov(self, fov):
        """ Sets the field of view of the spotlight """
        assert(fov > 1 and fov < 180)
        self.ghostLens.setFov(fov)
        self._updateLens()

    def setPos(self, pos):
        """ Sets the position of the spotlight """
        self.ghostCameraNode.setPos(pos)
        Light.setPos(self, pos)

    def lookAt(self, pos):
        """ Makes the spotlight look at the given position """
        self.ghostCameraNode.lookAt(pos)

    def _computeAdditionalData(self):
        """ Internal method to recompute the spotlight MVP """
        self.ghostCameraNode.setPos(self.position)

        projMat = self.ghostLens.getProjectionMat()

        modelViewMat = Globals.render.getTransform(self.ghostCameraNode).getMat()
        self.mvp = modelViewMat * projMat

    def _computeLightBounds(self):
        """ Recomputes the bounds of this light. For a SpotLight, we for now
        use a simple BoundingSphere """
        self.bounds = BoundingSphere(Point3(self.position), self.radius * 2.0)

    def setNearFar(self, near, far):
        """ Sets the near and far plane of the spotlight """
        self.nearPlane = near
        self.radius = far
        self.ghostLens.setNearFar(near, far)
        self._updateLens()

    def _updateDebugNode(self):
        """ Internal method to generate new debug geometry. """
        debugNode = NodePath("SpotLightDebugNode")

        # Create the inner image 
        cm = CardMaker("SpotLightDebug")
        cm.setFrameFullscreenQuad()
        innerNode = NodePath(cm.generate())
        innerNode.setTexture(Globals.loader.loadTexture("Data/GUI/Visualization/SpotLight.png"))
        innerNode.setBillboardPointEye()
        innerNode.reparentTo(debugNode)
        innerNode.setPos(self.position)
        innerNode.setColorScale(1,1,0,1)

        # Create the outer lines
        lineNode = debugNode.attachNewNode("lines")

        currentNodeTransform = render.getTransform(self.ghostCameraNode).getMat()
        currentCamTransform = self.ghostLens.getProjectionMat()
        currentRelativeCamPos = self.ghostCameraNode.getPos(render)
        currentCamBounds = self.ghostLens.makeBounds()
        currentCamBounds.xform(self.ghostCameraNode.getMat(render))

        p = lambda index: currentCamBounds.getPoint(index)

        # Make a circle at the bottom
        frustumBottomCenter = (p(0) + p(1) + p(2) + p(3)) * 0.25
        upVector = (p(0) + p(1)) / 2 - frustumBottomCenter
        rightVector = (p(1) + p(2)) / 2 - frustumBottomCenter
        points = []
        for idx in xrange(64):
            rad = idx / 64.0 * math.pi * 2.0
            pos = upVector * math.sin(rad) + rightVector * math.cos(rad)
            pos += frustumBottomCenter
            points.append(pos)
        frustumLine = self._createDebugLine(points, True)
        frustumLine.setColorScale(1,1,0,1)
        frustumLine.reparentTo(lineNode)


        # Create frustum lines which connect the origin to the bottom circle
        pointArrays = [
            [self.position, frustumBottomCenter + upVector],
            [self.position, frustumBottomCenter - upVector],
            [self.position, frustumBottomCenter + rightVector],
            [self.position, frustumBottomCenter - rightVector],
        ]

        for pointArray in pointArrays:
            frustumLine = self._createDebugLine(pointArray, False)
            frustumLine.setColorScale(1,1,0,1)
            frustumLine.reparentTo(lineNode)

        # Create line which is in the direction of the spot light
        startPoint = (p(0) + p(1) + p(2) + p(3)) * 0.25
        endPoint = (p(4) + p(5) + p(6) + p(7)) * 0.25
        line = self._createDebugLine([startPoint, endPoint], False)
        line.setColorScale(1,1,1,1)
        line.reparentTo(lineNode)

        # Remove the old debug node
        self.debugNode.node().removeAllChildren()

        # Attach the new debug node
        debugNode.reparentTo(self.debugNode)
        # self.debugNode.flattenStrong()

    def _initShadowSources(self):
        """ Internal method to init the shadow sources """
        source = ShadowSource()
        source.setResolution(self.shadowResolution)
        source.setLens(self.ghostLens)
        self._addShadowSource(source)

    def _updateShadowSources(self):
        """ Recomputes the position of the shadow source """
        self.shadowSources[0].setPos(self.position)
        self.shadowSources[0].setHpr(self.ghostCameraNode.getHpr())

    def __repr__(self):
        """ Generates a string representation of this instance """
        return "SpotLight[]"
コード例 #8
0
ファイル: lightbase.py プロジェクト: pbattaglia/scenesim
    def make_camera(self, output, sort=0, dr_dims=(0, 1, 0, 1),
                    aspect_ratio=None, clear_depth=False, clear_color=None,
                    lens=None, cam_name="camera0", mask=None):
        """
        Makes a new 3-d camera associated with the indicated window,
        and creates a display region in the indicated subrectangle.

        If stereo is True, then a stereo camera is created, with a
        pair of DisplayRegions.  If stereo is False, then a standard
        camera is created.  If stereo is None or omitted, a stereo
        camera is created if the window says it can render in stereo.

        If useCamera is not None, it is a NodePath to be used as the
        camera to apply to the window, rather than creating a new
        camera.

        Args:
            output (GraphicsOutput): Output object.

        Keyword Args:
            sort (int): Sort order.
            dr_dims (Iterable, 4): DisplayRegion dimensions.
            aspect_ratio (float): Aspect ratio.
            clear_depth (bool): Indicator to clear depth buffer.
            clear_color (bool): Indicator to clear color buffer.
            lens (Lens): Lens object.
            cam_name (str): Window name.
            mask (BitMask32): Bit mask that indicates which objects to render.

        Return:
            (NodePath): Camera nodepath.

        """

        # self.cameras is the parent node of all cameras: a node that
        # we can move around to move all cameras as a group.
        if self.cameras is None:
            # We make it a ModelNode with the PTLocal flag, so that a
            # wayward flatten operations won't attempt to mangle the
            # camera.
            self.cameras = self.root.attachNewNode(ModelNode("cameras"))
            self.cameras.node().setPreserveTransform(ModelNode.PTLocal)

        # Make a new Camera node.
        cam_node = Camera(cam_name)
        if lens is None:
            lens = PerspectiveLens()
            if aspect_ratio is None:
                aspect_ratio = self.get_aspect_ratio(output)
            lens.setAspectRatio(aspect_ratio)
            lens.setNear(0.1)
            lens.setFar(1000.0)
        if lens is not None:
            cam_node.setLens(lens)
        camera = self.cameras.attachNewNode(cam_node)
        # Masks out part of scene from camera
        if mask is not None:
            if (isinstance(mask, int)):
                mask = BitMask32(mask)
            cam_node.setCameraMask(mask)
        # Make a display region
        dr = output.makeDisplayRegion(*dr_dims)
        # By default, we do not clear 3-d display regions (the entire
        # window will be cleared, which is normally sufficient).  But
        # we will if clearDepth is specified.
        if clear_depth:
            dr.setClearDepthActive(1)
        if clear_color:
            dr.setClearColorActive(1)
            dr.setClearColor(clear_color)
        dr.setSort(sort)
        dr.setCamera(camera)
        dr.setActive(True)
        return camera
コード例 #9
0
class ShadowSource(DebugObject):

    _GlobalShadowIndex = 1000

    @classmethod
    def getExposedAttributes(self):
        return {
            "resolution": "int",
            "atlasPos": "vec2",
            "mvp": "mat4",
            "nearPlane": "float",
            "farPlane": "float"
        }

    def __init__(self):
        DebugObject.__init__(self, "ShadowSource")
        self.valid = False
        ShadowSource._GlobalShadowIndex += 1
        self.index = ShadowSource._GlobalShadowIndex
        self.camera = Camera("ShadowSource-" + str(self.index))
        self.cameraNode = NodePath(self.camera)
        self.cameraNode.reparentTo(render)
        # self.camera.showFrustum()
        self.resolution = 1024
        self.atlasPos = Vec2(0)
        self.doesHaveAtlasPos = False
        self.sourceIndex = 0
        self.mvp = Mat4()
        self.sourceIndex = -1
        self.nearPlane = 0.0
        self.farPlane = 1000.0

    def getSourceIndex(self):
        return self.sourceIndex

    def getUid(self):
        return self.index

    def __repr__(self):
        return "ShadowSource[id=" + str(self.index) + "]"

    def setSourceIndex(self, index):
        # self.debug("Assigning index", index)
        self.sourceIndex = index

    def computeMVP(self):
        projMat = Mat4.convertMat(
            CSYupRight,
            self.lens.getCoordinateSystem()) * self.lens.getProjectionMat()
        transformMat = TransformState.makeMat(
            Mat4.convertMat(base.win.getGsg().getInternalCoordinateSystem(),
                            CSZupRight))
        modelViewMat = transformMat.invertCompose(
            render.getTransform(self.cameraNode)).getMat()
        self.mvp = UnalignedLMatrix4f(modelViewMat * projMat)

    def assignAtlasPos(self, x, y):
        # self.debug("Assigning atlas pos", x, "/", y)
        self.atlasPos = Vec2(x, y)
        self.doesHaveAtlasPos = True

    def update(self):
        self.computeMVP()

    def getAtlasPos(self):
        return self.atlasPos

    def hasAtlasPos(self):
        return self.doesHaveAtlasPos

    def removeFromAtlas(self):
        self.doesHaveAtlasPos = False
        self.atlasPos = Vec2(0)

    def setResolution(self, resolution):
        self.resolution = resolution

    def getResolution(self):
        return self.resolution

    def setupPerspectiveLens(self, near=0.1, far=100.0, fov=(90, 90)):
        self.lens = PerspectiveLens()
        self.lens.setNearFar(near, far)
        self.lens.setFov(fov[0], fov[1])
        self.camera.setLens(self.lens)
        self.nearPlane = near
        self.farPlane = far

    def setPos(self, pos):
        self.cameraNode.setPos(pos)

    def setHpr(self, hpr):
        self.cameraNode.setHpr(hpr)

    def lookAt(self, pos):
        self.cameraNode.lookAt(pos.x, pos.y, pos.z)

    def invalidate(self):
        self.valid = False

    def setValid(self):
        self.valid = True

    def isValid(self):
        return self.valid
コード例 #10
0
    def renderSceneInto(self,
                        depthtex=None,
                        colortex=None,
                        auxtex=None,
                        auxbits=0,
                        textures=None,
                        fbprops=None,
                        clamping=None):
        """ Causes the scene to be rendered into the supplied textures
        instead of into the original window.  Puts a fullscreen quad
        into the original window to show the render-to-texture results.
        Returns the quad.  Normally, the caller would then apply a
        shader to the quad.

        To elaborate on how this all works:

        * An offscreen buffer is created.  It is set up to mimic
          the original display region - it is the same size,
          uses the same clear colors, and contains a DisplayRegion
          that uses the original camera.

        * A fullscreen quad and an orthographic camera to render
          that quad are both created.  The original camera is
          removed from the original window, and in its place, the
          orthographic quad-camera is installed.

        * The fullscreen quad is textured with the data from the
          offscreen buffer.  A shader is applied that tints the
          results pink.

        * Automatic shader generation NOT enabled.
          If you have a filter that depends on a render target from
          the auto-shader, you either need to set an auto-shader
          attrib on the main camera or scene, or, you need to provide
          these outputs in your own shader.

        * All clears are disabled on the original display region.
          If the display region fills the whole window, then clears
          are disabled on the original window as well.  It is
          assumed that rendering the full-screen quad eliminates
          the need to do clears.

        Hence, the original window which used to contain the actual
        scene, now contains a pink-tinted quad with a texture of the
        scene.  It is assumed that the user will replace the shader
        on the quad with a more interesting filter. """

        if textures:
            colortex = textures.get("color", None)
            depthtex = textures.get("depth", None)
            auxtex = textures.get("aux", None)
            auxtex0 = textures.get("aux0", auxtex)
            auxtex1 = textures.get("aux1", None)
        else:
            auxtex0 = auxtex
            auxtex1 = None

        if colortex is None:
            colortex = Texture("filter-base-color")
            colortex.setWrapU(Texture.WMClamp)
            colortex.setWrapV(Texture.WMClamp)

        texgroup = (depthtex, colortex, auxtex0, auxtex1)

        # Choose the size of the offscreen buffer.

        (winx, winy) = self.getScaledSize(1, 1, 1)
        if fbprops is not None:
            buffer = self.createBuffer("filter-base",
                                       winx,
                                       winy,
                                       texgroup,
                                       fbprops=fbprops)
        else:
            buffer = self.createBuffer("filter-base", winx, winy, texgroup)

        if buffer is None:
            return None

        cm = CardMaker("filter-base-quad")
        cm.setFrameFullscreenQuad()
        quad = NodePath(cm.generate())
        quad.setDepthTest(0)
        quad.setDepthWrite(0)
        quad.setTexture(colortex)
        quad.setColor(1, 0.5, 0.5, 1)

        cs = NodePath("dummy")
        cs.setState(self.camstate)
        # Do we really need to turn on the Shader Generator?
        #cs.setShaderAuto()
        if auxbits:
            cs.setAttrib(AuxBitplaneAttrib.make(auxbits))
        if clamping is False:
            # Disables clamping in the shader generator.
            cs.setAttrib(LightRampAttrib.make_identity())
        self.camera.node().setInitialState(cs.getState())

        quadcamnode = Camera("filter-quad-cam")
        lens = OrthographicLens()
        lens.setFilmSize(2, 2)
        lens.setFilmOffset(0, 0)
        lens.setNearFar(-1000, 1000)
        quadcamnode.setLens(lens)
        quadcam = quad.attachNewNode(quadcamnode)

        self.region.setCamera(quadcam)

        self.setStackedClears(buffer, self.rclears, self.wclears)
        if auxtex0:
            buffer.setClearActive(GraphicsOutput.RTPAuxRgba0, 1)
            buffer.setClearValue(GraphicsOutput.RTPAuxRgba0,
                                 (0.5, 0.5, 1.0, 0.0))
        if auxtex1:
            buffer.setClearActive(GraphicsOutput.RTPAuxRgba1, 1)
        self.region.disableClears()
        if self.isFullscreen():
            self.win.disableClears()

        dr = buffer.makeDisplayRegion()
        dr.disableClears()
        dr.setCamera(self.camera)
        dr.setActive(1)

        self.buffers.append(buffer)
        self.sizes.append((1, 1, 1))

        return quad
コード例 #11
0
class VoxelizePass(RenderPass):

    """ This pass manages voxelizing the scene from multiple directions to generate
    a 3D voxel grid. It handles the camera setup and provides a simple interface. """

    def __init__(self, pipeline):
        RenderPass.__init__(self)
        self.pipeline = pipeline

    def getID(self):
        return "VoxelizePass"

    def getRequiredInputs(self):
        return {
            # Lighting
            "renderedLightsBuffer": "Variables.renderedLightsBuffer",
            "lights": "Variables.allLights",
            "shadowAtlasPCF": "ShadowScenePass.atlasPCF",
            "shadowAtlas": "ShadowScenePass.atlas",
            "shadowSources": "Variables.allShadowSources",
            "directionToFace": "Variables.directionToFaceLookup",
            "cameraPosition": "Variables.cameraPosition",
            "mainCam": "Variables.mainCam",
            "mainRender": "Variables.mainRender",
        }

    def setVoxelGridResolution(self, voxelGridResolution):
        """ Sets the voxel grid resolution, this is the amount of voxels in every
        direction, so the voxel grid will have voxelGridResolution**3 total voxels. """
        self.voxelGridResolution = voxelGridResolution

    def setVoxelGridSize(self, voxelGridSize):
        """ Sets the size of the voxel grid in world space units. This is the
        size going from the mid of the voxel grid, so the effective voxel grid
        will have twice the size specified in voxelGridSize """
        self.voxelGridSize = voxelGridSize

    def setGridResolutionMultiplier(self, factor):
        """ Sets the density of the voxel grid. """
        self.gridResolutionMultiplier = factor

    def setActive(self, active):
        """ Enables and disables this pass """
        if hasattr(self, "target"):
            self.target.setActive(active)

    def getVoxelTex(self):
        """ Returns a handle to the generated voxel texture """
        return self.voxelGenTex

    def clearGrid(self):
        """ Clears the voxel grid """
        self.voxelGenTex.clearImage()

    def create(self):
        # Create voxelize camera
        self.voxelizeCamera = Camera("VoxelizeCamera")
        self.voxelizeCamera.setCameraMask(BitMask32.bit(4))
        self.voxelizeCameraNode = Globals.render.attachNewNode(self.voxelizeCamera)
        self.voxelizeLens = OrthographicLens()
        self.voxelizeLens.setFilmSize(self.voxelGridSize * 2, self.voxelGridSize * 2)
        self.voxelizeLens.setNearFar(0.0, self.voxelGridSize * 2)
        self.voxelizeCamera.setLens(self.voxelizeLens)
        self.voxelizeCamera.setTagStateKey("VoxelizePassShader")
        Globals.render.setTag("VoxelizePassShader", "Default")

        # Create voxelize tareet
        self.target = RenderTarget("VoxelizePass")
        self.target.setSize(self.voxelGridResolution * self.gridResolutionMultiplier)

        if self.pipeline.settings.useDebugAttachments:
            self.target.addColorTexture()
        else:
            self.target.setColorWrite(False)

        self.target.setCreateOverlayQuad(False)
        self.target.setSource(self.voxelizeCameraNode, Globals.base.win)
        self.target.prepareSceneRender()
        self.target.setActive(False)

        # self.target.getInternalRegion().setSort(-400)
        # self.target.getInternalBuffer().setSort(-399)

    def voxelizeSceneFromDirection(self, gridPos, direction="x"):
        """ Voxelizes the scene from a given direction. This method handles setting 
        the camera position aswell as the near and far plane. If the pass was disabled,
        it also enables this pass.  """
        assert direction in ["x", "y", "z"]
        self.setActive(True)

        if direction == "x":
            self.voxelizeLens.setFilmSize(self.voxelGridSize * 2, self.voxelGridSize * 2)
            self.voxelizeLens.setNearFar(0.0, self.voxelGridSize * 2)
            self.voxelizeCameraNode.setPos(gridPos - Vec3(self.voxelGridSize, 0, 0))
            self.voxelizeCameraNode.lookAt(gridPos)
        elif direction == "y":
            self.voxelizeLens.setFilmSize(self.voxelGridSize * 2, self.voxelGridSize * 2)
            self.voxelizeLens.setNearFar(0.0, self.voxelGridSize * 2)
            self.voxelizeCameraNode.setPos(gridPos - Vec3(0, self.voxelGridSize, 0))
            self.voxelizeCameraNode.lookAt(gridPos)
        elif direction == "z":
            self.voxelizeLens.setFilmSize(self.voxelGridSize * 2, self.voxelGridSize * 2)
            self.voxelizeLens.setNearFar(0.0, self.voxelGridSize * 2)
            self.voxelizeCameraNode.setPos(gridPos + Vec3(0, 0, self.voxelGridSize))
            self.voxelizeCameraNode.lookAt(gridPos)

    def setShaders(self):
        """ Creates the tag state and loades the voxelizer shader """
        self.registerTagState("Default", NodePath("DefaultVoxelizeState"))
        return []

    def registerTagState(self, name, state):
        """ Registers a new tag state """
        state.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullNone))
        state.setDepthWrite(False)
        state.setDepthTest(False)
        state.setAttrib(DepthTestAttrib.make(DepthTestAttrib.MNone))
        state.setShaderInput("voxelizeCam", self.voxelizeCameraNode)
        self.voxelizeCamera.setTagState(name, state.getState())

    def setShaderInput(self, *args):
        Globals.base.render.setShaderInput(*args)

    def getOutputs(self):
        return {}
コード例 #12
0
class Viewport(QtWidgets.QWidget, DirectObject):

    ClearColor = LEGlobals.vec3GammaToLinear(Vec4(0.361, 0.361, 0.361, 1.0))

    def __init__(self, vpType, window, doc):
        DirectObject.__init__(self)
        QtWidgets.QWidget.__init__(self, window)
        self.doc = doc
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.setMouseTracking(True)

        self.qtWindow = None
        self.qtWidget = None

        self.window = window
        self.type = vpType

        self.spec = VIEWPORT_SPECS[self.type]

        self.lens = None
        self.camNode = None
        self.camera = None
        self.cam = None
        self.win = None
        self.displayRegion = None
        self.mouseWatcher = None
        self.mouseWatcherNp = None
        self.buttonThrower = None
        self.clickRay = None
        self.clickNode = None
        self.clickNp = None
        self.clickQueue = None
        self.tickTask = None
        self.zoom = 1.0
        self.gizmo = None
        self.inputDevice = None
        self.mouseAndKeyboard = None
        self.lastRenderTime = 0.0
        self.enabled = False
        self.needsUpdate = True

        # 2D stuff copied from ShowBase :(
        self.camera2d = None
        self.cam2d = None
        self.render2d = None
        self.aspect2d = None
        self.a2dBackground = None
        self.a2dTop = None
        self.a2dBottom = None
        self.a2dLeft = None
        self.a2dRight = None
        self.a2dTopCenter = None
        self.a2dTopCenterNs = None
        self.a2dBottomCenter = None
        self.a2dBottomCenterNs = None
        self.a2dRightCenter = None
        self.a2dRightCenterNs = None
        self.a2dTopLeft = None
        self.a2dTopLeftNs = None
        self.a2dTopRight = None
        self.a2dTopRightNs = None
        self.a2dBottomLeft = None
        self.a2dBottomLeftNs = None
        self.a2dBottomRight = None
        self.a2dBottomRightNs = None
        self.__oldAspectRatio = None

        self.gridRoot = self.doc.render.attachNewNode("gridRoot")
        self.gridRoot.setLightOff(1)
        #self.gridRoot.setBSPMaterial("phase_14/materials/unlit.mat")
        #self.gridRoot.setDepthWrite(False)
        self.gridRoot.setBin("background", 0)
        self.gridRoot.hide(~self.getViewportMask())

        self.grid = None

    def updateView(self, now=False):
        if now:
            self.renderView()
        else:
            self.needsUpdate = True

    def getGizmoAxes(self):
        raise NotImplementedError

    def getMouseRay(self, collRay=False):
        ray = CollisionRay()
        ray.setFromLens(self.camNode, self.getMouse())
        if collRay:
            return ray
        else:
            return Ray(ray.getOrigin(), ray.getDirection())

    def hasMouse(self):
        return self.mouseWatcher.hasMouse()

    def getMouse(self):
        if self.mouseWatcher.hasMouse():
            return self.mouseWatcher.getMouse()
        return Point2(0, 0)

    def is3D(self):
        return self.type == VIEWPORT_3D

    def is2D(self):
        return self.type != VIEWPORT_3D

    def makeGrid(self):
        raise NotImplementedError

    def getViewportMask(self):
        return BitMask32.bit(self.type)

    def getViewportFullMask(self):
        return self.getViewportMask()

    def makeLens(self):
        raise NotImplementedError

    def getGridAxes(self):
        raise NotImplementedError

    def expand(self, point):
        return point

    def initialize(self):
        self.lens = self.makeLens()
        self.camera = self.doc.render.attachNewNode(
            ModelNode("viewportCameraParent"))
        self.camNode = Camera("viewportCamera")
        self.camNode.setLens(self.lens)
        self.camNode.setCameraMask(self.getViewportMask())
        self.cam = self.camera.attachNewNode(self.camNode)

        winprops = WindowProperties.getDefault()
        winprops.setParentWindow(int(self.winId()))
        winprops.setForeground(False)
        winprops.setUndecorated(True)

        gsg = self.doc.gsg

        output = base.graphicsEngine.makeOutput(
            base.pipe, "viewportOutput", 0, FrameBufferProperties.getDefault(),
            winprops,
            (GraphicsPipe.BFFbPropsOptional | GraphicsPipe.BFRequireWindow),
            gsg)

        self.qtWindow = QtGui.QWindow.fromWinId(
            output.getWindowHandle().getIntHandle())
        self.qtWidget = QtWidgets.QWidget.createWindowContainer(
            self.qtWindow, self, QtCore.Qt.WindowDoesNotAcceptFocus
            | QtCore.Qt.WindowTransparentForInput
            | QtCore.Qt.WindowStaysOnBottomHint
            | QtCore.Qt.BypassWindowManagerHint | QtCore.Qt.SubWindow)  #,
        #(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowDoesNotAcceptFocus
        #| QtCore.Qt.WindowTransparentForInput | QtCore.Qt.BypassWindowManagerHint
        #| QtCore.Qt.SubWindow | QtCore.Qt.WindowStaysOnBottomHint))
        self.qtWidget.setFocusPolicy(QtCore.Qt.NoFocus)

        self.inputDevice = output.getInputDevice(0)

        assert output is not None, "Unable to create viewport output!"

        dr = output.makeDisplayRegion()
        dr.disableClears()
        dr.setCamera(self.cam)
        self.displayRegion = dr

        output.disableClears()
        output.setClearColor(Viewport.ClearColor)
        output.setClearColorActive(True)
        output.setClearDepthActive(True)
        output.setActive(True)

        self.win = output

        # keep track of the mouse in this viewport
        mak = MouseAndKeyboard(self.win, 0, "mouse")
        mouse = base.dataRoot.attachNewNode(mak)
        self.mouseAndKeyboard = mouse
        self.mouseWatcher = MouseWatcher()
        self.mouseWatcher.setDisplayRegion(self.displayRegion)
        mw = mouse.attachNewNode(self.mouseWatcher)
        self.mouseWatcherNp = mw

        # listen for keyboard and mouse events in this viewport
        bt = ButtonThrower("kbEvents")
        bt.setButtonDownEvent("btndown")
        bt.setButtonUpEvent("btnup")
        mods = ModifierButtons()
        mods.addButton(KeyboardButton.shift())
        mods.addButton(KeyboardButton.control())
        mods.addButton(KeyboardButton.alt())
        mods.addButton(KeyboardButton.meta())
        bt.setModifierButtons(mods)
        self.buttonThrower = mouse.attachNewNode(bt)

        # collision objects for clicking on objects from this viewport
        self.clickRay = CollisionRay()
        self.clickNode = CollisionNode("viewportClickRay")
        self.clickNode.addSolid(self.clickRay)
        self.clickNp = NodePath(self.clickNode)
        self.clickQueue = CollisionHandlerQueue()

        self.setupRender2d()
        self.setupCamera2d()

        self.gizmo = ViewportGizmo(self)

        self.doc.viewportMgr.addViewport(self)

        self.makeGrid()

    def cleanup(self):
        self.grid.cleanup()
        self.grid = None
        self.gridRoot.removeNode()
        self.gridRoot = None

        self.lens = None
        self.camNode = None
        self.cam.removeNode()
        self.cam = None
        self.camera.removeNode()
        self.camera = None
        self.spec = None
        self.doc = None
        self.type = None
        self.window = None
        self.zoom = None
        self.gizmo.cleanup()
        self.gizmo = None
        self.clickNp.removeNode()
        self.clickNp = None
        self.clickQueue.clearEntries()
        self.clickQueue = None
        self.clickNode = None
        self.clickRay = None
        self.buttonThrower.removeNode()
        self.buttonThrower = None
        self.inputDevice = None
        self.mouseWatcherNp.removeNode()
        self.mouseWatcherNp = None
        self.mouseWatcher = None
        self.mouseAndKeyboard.removeNode()
        self.mouseAndKeyboard = None
        self.win.removeAllDisplayRegions()
        self.displayRegion = None
        base.graphicsEngine.removeWindow(self.win)
        self.win = None

        self.camera2d.removeNode()
        self.camera2d = None
        self.cam2d = None

        self.render2d.removeNode()
        self.render2d = None

        self.a2dBackground = None
        self.a2dTop = None
        self.a2dBottom = None
        self.a2dLeft = None
        self.a2dRight = None
        self.aspect2d = None
        self.a2dTopCenter = None
        self.a2dTopCenterNs = None
        self.a2dBottomCenter = None
        self.a2dBottomCenterNs = None
        self.a2dLeftCenter = None
        self.a2dLeftCenterNs = None
        self.a2dRightCenter = None
        self.a2dRightCenterNs = None

        self.a2dTopLeft = None
        self.a2dTopLeftNs = None
        self.a2dTopRight = None
        self.a2dTopRightNs = None
        self.a2dBottomLeft = None
        self.a2dBottomLeftNs = None
        self.a2dBottomRight = None
        self.a2dBottomRightNs = None
        self.__oldAspectRatio = None

        self.qtWindow.deleteLater()
        self.qtWidget.deleteLater()
        self.qtWindow = None
        self.qtWidget = None

        self.deleteLater()

    def keyPressEvent(self, event):
        button = LEUtils.keyboardButtonFromQtKey(event.key())
        if button:
            self.inputDevice.buttonDown(button)

    def keyReleaseEvent(self, event):
        button = LEUtils.keyboardButtonFromQtKey(event.key())
        if button:
            self.inputDevice.buttonUp(button)

    def enterEvent(self, event):
        # Give ourselves focus.
        self.setFocus()
        QtWidgets.QWidget.enterEvent(self, event)

    def mouseMoveEvent(self, event):
        self.inputDevice.setPointerInWindow(event.pos().x(), event.pos().y())
        QtWidgets.QWidget.mouseMoveEvent(self, event)

    def leaveEvent(self, event):
        self.clearFocus()
        self.inputDevice.setPointerOutOfWindow()
        self.inputDevice.focusLost()
        QtWidgets.QWidget.leaveEvent(self, event)

    def mousePressEvent(self, event):
        btn = event.button()
        if btn == QtCore.Qt.LeftButton:
            self.inputDevice.buttonDown(MouseButton.one())
        elif btn == QtCore.Qt.MiddleButton:
            self.inputDevice.buttonDown(MouseButton.two())
        elif btn == QtCore.Qt.RightButton:
            self.inputDevice.buttonDown(MouseButton.three())
        QtWidgets.QWidget.mousePressEvent(self, event)

    def mouseReleaseEvent(self, event):
        btn = event.button()
        if btn == QtCore.Qt.LeftButton:
            self.inputDevice.buttonUp(MouseButton.one())
        elif btn == QtCore.Qt.MiddleButton:
            self.inputDevice.buttonUp(MouseButton.two())
        elif btn == QtCore.Qt.RightButton:
            self.inputDevice.buttonUp(MouseButton.three())
        QtWidgets.QWidget.mouseReleaseEvent(self, event)

    def wheelEvent(self, event):
        ang = event.angleDelta().y()
        if ang > 0:
            self.inputDevice.buttonDown(MouseButton.wheelUp())
            self.inputDevice.buttonUp(MouseButton.wheelUp())
        else:
            self.inputDevice.buttonDown(MouseButton.wheelDown())
            self.inputDevice.buttonUp(MouseButton.wheelDown())
        QtWidgets.QWidget.wheelEvent(self, event)

    def getAspectRatio(self):
        return self.win.getXSize() / self.win.getYSize()

    def setupRender2d(self):
        ## This is the root of the 2-D scene graph.
        self.render2d = NodePath("viewport-render2d")

        # Set up some overrides to turn off certain properties which
        # we probably won't need for 2-d objects.

        # It's probably important to turn off the depth test, since
        # many 2-d objects will be drawn over each other without
        # regard to depth position.

        # We used to avoid clearing the depth buffer before drawing
        # render2d, but nowadays we clear it anyway, since we
        # occasionally want to put 3-d geometry under render2d, and
        # it's simplest (and seems to be easier on graphics drivers)
        # if the 2-d scene has been cleared first.

        self.render2d.setDepthTest(0)
        self.render2d.setDepthWrite(0)
        self.render2d.setMaterialOff(1)
        self.render2d.setTwoSided(1)

        self.aspect2d = self.render2d.attachNewNode("viewport-aspect2d")

        aspectRatio = self.getAspectRatio()
        self.aspect2d.setScale(1.0 / aspectRatio, 1.0, 1.0)

        self.a2dBackground = self.aspect2d.attachNewNode("a2dBackground")

        ## The Z position of the top border of the aspect2d screen.
        self.a2dTop = 1.0
        ## The Z position of the bottom border of the aspect2d screen.
        self.a2dBottom = -1.0
        ## The X position of the left border of the aspect2d screen.
        self.a2dLeft = -aspectRatio
        ## The X position of the right border of the aspect2d screen.
        self.a2dRight = aspectRatio

        self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
        self.a2dTopCenterNs = self.aspect2d.attachNewNode("a2dTopCenterNS")
        self.a2dBottomCenter = self.aspect2d.attachNewNode("a2dBottomCenter")
        self.a2dBottomCenterNs = self.aspect2d.attachNewNode(
            "a2dBottomCenterNS")
        self.a2dLeftCenter = self.aspect2d.attachNewNode("a2dLeftCenter")
        self.a2dLeftCenterNs = self.aspect2d.attachNewNode("a2dLeftCenterNS")
        self.a2dRightCenter = self.aspect2d.attachNewNode("a2dRightCenter")
        self.a2dRightCenterNs = self.aspect2d.attachNewNode("a2dRightCenterNS")

        self.a2dTopLeft = self.aspect2d.attachNewNode("a2dTopLeft")
        self.a2dTopLeftNs = self.aspect2d.attachNewNode("a2dTopLeftNS")
        self.a2dTopRight = self.aspect2d.attachNewNode("a2dTopRight")
        self.a2dTopRightNs = self.aspect2d.attachNewNode("a2dTopRightNS")
        self.a2dBottomLeft = self.aspect2d.attachNewNode("a2dBottomLeft")
        self.a2dBottomLeftNs = self.aspect2d.attachNewNode("a2dBottomLeftNS")
        self.a2dBottomRight = self.aspect2d.attachNewNode("a2dBottomRight")
        self.a2dBottomRightNs = self.aspect2d.attachNewNode("a2dBottomRightNS")

        # Put the nodes in their places
        self.a2dTopCenter.setPos(0, 0, self.a2dTop)
        self.a2dTopCenterNs.setPos(0, 0, self.a2dTop)
        self.a2dBottomCenter.setPos(0, 0, self.a2dBottom)
        self.a2dBottomCenterNs.setPos(0, 0, self.a2dBottom)
        self.a2dLeftCenter.setPos(self.a2dLeft, 0, 0)
        self.a2dLeftCenterNs.setPos(self.a2dLeft, 0, 0)
        self.a2dRightCenter.setPos(self.a2dRight, 0, 0)
        self.a2dRightCenterNs.setPos(self.a2dRight, 0, 0)

        self.a2dTopLeft.setPos(self.a2dLeft, 0, self.a2dTop)
        self.a2dTopLeftNs.setPos(self.a2dLeft, 0, self.a2dTop)
        self.a2dTopRight.setPos(self.a2dRight, 0, self.a2dTop)
        self.a2dTopRightNs.setPos(self.a2dRight, 0, self.a2dTop)
        self.a2dBottomLeft.setPos(self.a2dLeft, 0, self.a2dBottom)
        self.a2dBottomLeftNs.setPos(self.a2dLeft, 0, self.a2dBottom)
        self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
        self.a2dBottomRightNs.setPos(self.a2dRight, 0, self.a2dBottom)

    def setupCamera2d(self,
                      sort=10,
                      displayRegion=(0, 1, 0, 1),
                      coords=(-1, 1, -1, 1)):
        dr = self.win.makeMonoDisplayRegion(*displayRegion)
        dr.setSort(10)

        # Enable clearing of the depth buffer on this new display
        # region (see the comment in setupRender2d, above).
        dr.setClearDepthActive(1)

        # Make any texture reloads on the gui come up immediately.
        dr.setIncompleteRender(False)

        left, right, bottom, top = coords

        # Now make a new Camera node.
        cam2dNode = Camera('cam2d')

        lens = OrthographicLens()
        lens.setFilmSize(right - left, top - bottom)
        lens.setFilmOffset((right + left) * 0.5, (top + bottom) * 0.5)
        lens.setNearFar(-1000, 1000)
        cam2dNode.setLens(lens)

        # self.camera2d is the analog of self.camera, although it's
        # not as clear how useful it is.
        self.camera2d = self.render2d.attachNewNode('camera2d')

        camera2d = self.camera2d.attachNewNode(cam2dNode)
        dr.setCamera(camera2d)

        self.cam2d = camera2d

        return camera2d

    def mouse1Up(self):
        pass

    def mouse1Down(self):
        pass

    def mouse2Up(self):
        pass

    def mouse2Down(self):
        pass

    def mouse3Up(self):
        pass

    def mouse3Down(self):
        pass

    def mouseEnter(self):
        self.updateView()

    def mouseExit(self):
        pass

    def mouseMove(self):
        pass

    def wheelUp(self):
        pass

    def wheelDown(self):
        pass

    def shouldRender(self):
        if not self.enabled:
            return False

        now = globalClock.getRealTime()
        if self.lastRenderTime != 0:
            elapsed = now - self.lastRenderTime
            if elapsed <= 0:
                return False

            frameRate = 1 / elapsed
            if frameRate > 100.0:
                # Never render faster than 100Hz
                return False

        return self.needsUpdate

    def renderView(self):
        self.lastRenderTime = globalClock.getRealTime()
        self.needsUpdate = False
        #self.win.setActive(1)
        base.requestRender()

    def tick(self):
        if self.shouldRender():
            self.renderView()
        else:
            pass
            #self.win.setActive(0)

    def getViewportName(self):
        return self.spec.name

    def getViewportCenterPixels(self):
        return LPoint2i(self.win.getXSize() // 2, self.win.getYSize() // 2)

    def centerCursor(self, cursor):
        center = self.getViewportCenterPixels()
        cursor.setPos(
            self.mapToGlobal(QtCore.QPoint(self.width() / 2,
                                           self.height() / 2)))
        self.inputDevice.setPointerInWindow(center.x, center.y)

    def viewportToWorld(self, viewport, vec=False):
        front = Point3()
        back = Point3()
        self.lens.extrude(viewport, front, back)
        world = (front + back) / 2

        worldMat = self.cam.getMat(render)
        if vec:
            world = worldMat.xformVec(world)
        else:
            world = worldMat.xformPoint(world)

        return world

    def worldToViewport(self, world):
        # move into local camera space
        invMat = Mat4(self.cam.getMat(render))
        invMat.invertInPlace()

        local = invMat.xformPoint(world)

        point = Point2()
        self.lens.project(local, point)

        return point

    def zeroUnusedCoordinate(self, vec):
        pass

    def click(self, mask, queue=None, traverser=None, root=None):
        if not self.mouseWatcher.hasMouse():
            return None

        if not queue:
            queue = self.clickQueue

        self.clickRay.setFromLens(self.camNode, self.mouseWatcher.getMouse())
        self.clickNode.setFromCollideMask(mask)
        self.clickNode.setIntoCollideMask(BitMask32.allOff())
        self.clickNp.reparentTo(self.cam)
        queue.clearEntries()
        if not traverser:
            base.clickTraverse(self.clickNp, queue)
        else:
            if not root:
                root = self.doc.render
            traverser.addCollider(self.clickNp, queue)
            traverser.traverse(root)
            traverser.removeCollider(self.clickNp)
        queue.sortEntries()
        self.clickNp.reparentTo(NodePath())

        return queue.getEntries()

    def fixRatio(self, size=None):
        if not self.lens:
            return

        if size is None:
            aspectRatio = self.win.getXSize() / self.win.getYSize()
        else:
            if size.y > 0:
                aspectRatio = size.x / size.y
            else:
                aspectRatio = 1.0

        if self.is2D():
            zoomFactor = (1.0 / self.zoom) * 100.0
            self.lens.setFilmSize(zoomFactor * aspectRatio, zoomFactor)
        else:
            self.lens.setAspectRatio(aspectRatio)

        if aspectRatio != self.__oldAspectRatio:
            self.__oldAspectRatio = aspectRatio
            # Fix up some anything that depends on the aspectRatio
            if aspectRatio < 1:
                # If the window is TALL, lets expand the top and bottom
                self.aspect2d.setScale(1.0, aspectRatio, aspectRatio)
                self.a2dTop = 1.0 / aspectRatio
                self.a2dBottom = -1.0 / aspectRatio
                self.a2dLeft = -1
                self.a2dRight = 1.0
            else:
                # If the window is WIDE, lets expand the left and right
                self.aspect2d.setScale(1.0 / aspectRatio, 1.0, 1.0)
                self.a2dTop = 1.0
                self.a2dBottom = -1.0
                self.a2dLeft = -aspectRatio
                self.a2dRight = aspectRatio

            # Reposition the aspect2d marker nodes
            self.a2dTopCenter.setPos(0, 0, self.a2dTop)
            self.a2dTopCenterNs.setPos(0, 0, self.a2dTop)
            self.a2dBottomCenter.setPos(0, 0, self.a2dBottom)
            self.a2dBottomCenterNs.setPos(0, 0, self.a2dBottom)
            self.a2dLeftCenter.setPos(self.a2dLeft, 0, 0)
            self.a2dLeftCenterNs.setPos(self.a2dLeft, 0, 0)
            self.a2dRightCenter.setPos(self.a2dRight, 0, 0)
            self.a2dRightCenterNs.setPos(self.a2dRight, 0, 0)

            self.a2dTopLeft.setPos(self.a2dLeft, 0, self.a2dTop)
            self.a2dTopLeftNs.setPos(self.a2dLeft, 0, self.a2dTop)
            self.a2dTopRight.setPos(self.a2dRight, 0, self.a2dTop)
            self.a2dTopRightNs.setPos(self.a2dRight, 0, self.a2dTop)
            self.a2dBottomLeft.setPos(self.a2dLeft, 0, self.a2dBottom)
            self.a2dBottomLeftNs.setPos(self.a2dLeft, 0, self.a2dBottom)
            self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
            self.a2dBottomRightNs.setPos(self.a2dRight, 0, self.a2dBottom)

    def resizeEvent(self, event):
        if not self.win:
            return

        newsize = LVector2i(event.size().width(), event.size().height())
        self.qtWidget.resize(newsize[0], newsize[1])
        self.qtWidget.move(0, 0)

        #props = WindowProperties()
        #props.setSize(newsize)
        #props.setOrigin(0, 0)
        #self.win.requestProperties(props)

        self.fixRatio(newsize)

        self.onResize(newsize)

        self.updateView()

    def onResize(self, newsize):
        pass

    def draw(self):
        pass

    def enable(self):
        # Render to the viewport
        self.win.setActive(True)
        self.enabled = True

    def disable(self):
        # Don't render to the viewport
        self.win.setActive(False)
        self.enabled = False
コード例 #13
0
 def renderSceneInto(self,
                     depthtex=None,
                     colortex=None,
                     auxtex=None,
                     auxbits=0,
                     textures=None,
                     fbprops=None,
                     clamping=None):
     """
     overload direct.filters.FilterManager.renderSceneInto
     :param depthtex:
     :param colortex:
     :param auxtex:
     :param auxbits:
     :param textures:
     :param fbprops:
     :param clamping:
     :return:
     """
     if (textures):
         colortex = textures.get("color", None)
         depthtex = textures.get("depth", None)
         auxtex = textures.get("aux", None)
         auxtex0 = textures.get("aux0", auxtex)
         auxtex1 = textures.get("aux1", None)
     else:
         auxtex0 = auxtex
         auxtex1 = None
     if (colortex == None):
         colortex = Texture("filter-base-color")
         colortex.setWrapU(Texture.WMClamp)
         colortex.setWrapV(Texture.WMClamp)
     texgroup = (depthtex, colortex, auxtex0, auxtex1)
     # Choose the size of the offscreen buffer.
     (winx, winy) = self.getScaledSize(1, 1, 1)
     if fbprops is not None:
         buffer = self.createBuffer("filter-base",
                                    winx,
                                    winy,
                                    texgroup,
                                    fbprops=fbprops)
     else:
         buffer = self.createBuffer("filter-base", winx, winy, texgroup)
     if (buffer == None):
         return None
     cm = CardMaker("filter-base-quad")
     cm.setFrameFullscreenQuad()
     quad = NodePath(cm.generate())
     quad.setDepthTest(0)
     quad.setDepthWrite(0)
     quad.setTexture(colortex)
     quad.setColor(1, 0.5, 0.5, 1)
     cs = NodePath("dummy")
     cs.setState(self.camstate)
     # Do we really need to turn on the Shader Generator?
     # cs.setShaderAuto()
     if (auxbits):
         cs.setAttrib(AuxBitplaneAttrib.make(auxbits))
     if clamping is False:
         # Disables clamping in the shader generator.
         cs.setAttrib(LightRampAttrib.make_identity())
     self.camera.node().setInitialState(cs.getState())
     quadcamnode = Camera("filter-quad-cam")
     lens = OrthographicLens()
     lens.setFilmSize(2, 2)
     lens.setFilmOffset(0, 0)
     lens.setNearFar(-1000, 1000)
     quadcamnode.setLens(lens)
     quadcam = quad.attachNewNode(quadcamnode)
     self.region.setCamera(quadcam)
     self.setStackedClears(buffer, self.rclears, self.wclears)
     if (auxtex0):
         buffer.setClearActive(GraphicsOutput.RTPAuxRgba0, 1)
         buffer.setClearValue(GraphicsOutput.RTPAuxRgba0,
                              (0.5, 0.5, 1.0, 0.0))
     if (auxtex1):
         buffer.setClearActive(GraphicsOutput.RTPAuxRgba1, 1)
     self.region.disableClears()
     if (self.isFullscreen()):
         self.win.disableClears()
     dr = buffer.makeDisplayRegion()
     dr.disableClears()
     dr.setCamera(self.camera)
     dr.setActive(1)
     self.buffers.append(buffer)
     self.sizes.append((1, 1, 1))
     return quad
コード例 #14
0
    def renderSceneInto(self, depthtex=None, colortex=None, auxtex=None, auxbits=0, textures=None):

        """ Causes the scene to be rendered into the supplied textures
        instead of into the original window.  Puts a fullscreen quad
        into the original window to show the render-to-texture results.
        Returns the quad.  Normally, the caller would then apply a
        shader to the quad.

        To elaborate on how this all works:

        * An offscreen buffer is created.  It is set up to mimic
          the original display region - it is the same size,
          uses the same clear colors, and contains a DisplayRegion
          that uses the original camera.

        * A fullscreen quad and an orthographic camera to render
          that quad are both created.  The original camera is
          removed from the original window, and in its place, the
          orthographic quad-camera is installed.

        * The fullscreen quad is textured with the data from the
          offscreen buffer.  A shader is applied that tints the
          results pink.

        * Automatic shader generation NOT enabled.
          If you have a filter that depends on a render target from
          the auto-shader, you either need to set an auto-shader
          attrib on the main camera or scene, or, you need to provide
          these outputs in your own shader.

        * All clears are disabled on the original display region.
          If the display region fills the whole window, then clears
          are disabled on the original window as well.  It is
          assumed that rendering the full-screen quad eliminates
          the need to do clears.

        Hence, the original window which used to contain the actual
        scene, now contains a pink-tinted quad with a texture of the
        scene.  It is assumed that the user will replace the shader
        on the quad with a more interesting filter. """

        if (textures):
            colortex = textures.get("color", None)
            depthtex = textures.get("depth", None)
            auxtex = textures.get("aux", None)
            auxtex0 = textures.get("aux0", auxtex)
            auxtex1 = textures.get("aux1", None)
        else:
            auxtex0 = auxtex
            auxtex1 = None

        if (colortex == None):
            colortex = Texture("filter-base-color")
            colortex.setWrapU(Texture.WMClamp)
            colortex.setWrapV(Texture.WMClamp)

        texgroup = (depthtex, colortex, auxtex0, auxtex1)

        # Choose the size of the offscreen buffer.

        (winx, winy) = self.getScaledSize(1,1,1)
        buffer = self.createBuffer("filter-base", winx, winy, texgroup)

        if (buffer == None):
            return None

        cm = CardMaker("filter-base-quad")
        cm.setFrameFullscreenQuad()
        quad = NodePath(cm.generate())
        quad.setDepthTest(0)
        quad.setDepthWrite(0)
        quad.setTexture(colortex)
        quad.setColor(1, 0.5, 0.5, 1)

        cs = NodePath("dummy")
        cs.setState(self.camstate)
        # Do we really need to turn on the Shader Generator?
        #cs.setShaderAuto()
        if (auxbits):
            cs.setAttrib(AuxBitplaneAttrib.make(auxbits))
        self.camera.node().setInitialState(cs.getState())

        quadcamnode = Camera("filter-quad-cam")
        lens = OrthographicLens()
        lens.setFilmSize(2, 2)
        lens.setFilmOffset(0, 0)
        lens.setNearFar(-1000, 1000)
        quadcamnode.setLens(lens)
        quadcam = quad.attachNewNode(quadcamnode)
        
        self.region.setCamera(quadcam)

        self.setStackedClears(buffer, self.rclears, self.wclears)
        if (auxtex0):
            buffer.setClearActive(GraphicsOutput.RTPAuxRgba0, 1)
            buffer.setClearValue(GraphicsOutput.RTPAuxRgba0, (0.5, 0.5, 1.0, 0.0))
        if (auxtex1):
            buffer.setClearActive(GraphicsOutput.RTPAuxRgba1, 1)
        self.region.disableClears()
        if (self.isFullscreen()):
            self.win.disableClears()

        dr = buffer.makeDisplayRegion()
        dr.disableClears()
        dr.setCamera(self.camera)
        dr.setActive(1)

        self.buffers.append(buffer)
        self.sizes.append((1, 1, 1))

        return quad
コード例 #15
0
class GlobalIllumination(DebugObject):
    """ This class handles the global illumination processing. It is still
    experimental, and thus not commented. """

    updateEnabled = False

    def __init__(self, pipeline):
        DebugObject.__init__(self, "GlobalIllumnination")
        self.pipeline = pipeline

        self.targetCamera = Globals.base.cam
        self.targetSpace = Globals.base.render

        self.voxelBaseResolution = 512 * 4
        self.voxelGridSizeWS = Vec3(50, 50, 20)
        self.voxelGridResolution = LVecBase3i(512, 512, 128)
        self.targetLight = None
        self.helperLight = None
        self.ptaGridPos = PTALVecBase3f.emptyArray(1)
        self.gridPos = Vec3(0)

    @classmethod
    def setUpdateEnabled(self, enabled):
        self.updateEnabled = enabled

    def setTargetLight(self, light):
        """ Sets the sun light which is the main source of GI """

        if light._getLightType() != LightType.Directional:
            self.error("setTargetLight expects a directional light!")
            return

        self.targetLight = light
        self._createHelperLight()

    def _prepareVoxelScene(self):
        """ Creates the internal buffer to voxelize the scene on the fly """
        self.voxelizeScene = Globals.render
        self.voxelizeCamera = Camera("VoxelizeScene")
        self.voxelizeCameraNode = self.voxelizeScene.attachNewNode(
            self.voxelizeCamera)
        self.voxelizeLens = OrthographicLens()
        self.voxelizeLens.setFilmSize(self.voxelGridSizeWS.x * 2,
                                      self.voxelGridSizeWS.y * 2)
        self.voxelizeLens.setNearFar(0.0, self.voxelGridSizeWS.x * 2)
        self.voxelizeCamera.setLens(self.voxelizeLens)
        self.voxelizeCamera.setTagStateKey("VoxelizePassShader")

        self.targetSpace.setTag("VoxelizePassShader", "Default")

        self.voxelizeCameraNode.setPos(0, 0, 0)
        self.voxelizeCameraNode.lookAt(0, 0, 0)

        self.voxelizeTarget = RenderTarget("DynamicVoxelization")
        self.voxelizeTarget.setSize(self.voxelBaseResolution)
        # self.voxelizeTarget.addDepthTexture()
        # self.voxelizeTarget.addColorTexture()
        # self.voxelizeTarget.setColorBits(16)
        self.voxelizeTarget.setSource(self.voxelizeCameraNode,
                                      Globals.base.win)
        self.voxelizeTarget.prepareSceneRender()

        self.voxelizeTarget.getQuad().node().removeAllChildren()
        self.voxelizeTarget.getInternalRegion().setSort(-400)
        self.voxelizeTarget.getInternalBuffer().setSort(-399)

        # for tex in [self.voxelizeTarget.getColorTexture()]:
        #     tex.setWrapU(Texture.WMClamp)
        #     tex.setWrapV(Texture.WMClamp)
        #     tex.setMinfilter(Texture.FTNearest)
        #     tex.setMagfilter(Texture.FTNearest)

        voxelSize = Vec3(
            self.voxelGridSizeWS.x * 2.0 / self.voxelGridResolution.x,
            self.voxelGridSizeWS.y * 2.0 / self.voxelGridResolution.y,
            self.voxelGridSizeWS.z * 2.0 / self.voxelGridResolution.z)

        self.targetSpace.setShaderInput("dv_gridSize",
                                        self.voxelGridSizeWS * 2)
        self.targetSpace.setShaderInput("dv_voxelSize", voxelSize)
        self.targetSpace.setShaderInput("dv_gridResolution",
                                        self.voxelGridResolution)

    def _createVoxelizeState(self):
        """ Creates the tag state and loades the voxelizer shader """
        self.voxelizeShader = BetterShader.load("Shader/GI/Voxelize.vertex",
                                                "Shader/GI/Voxelize.fragment"
                                                # "Shader/GI/Voxelize.geometry"
                                                )

        initialState = NodePath("VoxelizerState")
        initialState.setShader(self.voxelizeShader, 50)
        initialState.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullNone))
        initialState.setDepthWrite(False)
        initialState.setDepthTest(False)
        initialState.setAttrib(DepthTestAttrib.make(DepthTestAttrib.MNone))

        initialState.setShaderInput("dv_dest_tex", self.voxelGenTex)

        self.voxelizeCamera.setTagState("Default", initialState.getState())

    def _createHelperLight(self):
        """ Creates the helper light. We can't use the main directional light
        because it uses PSSM, so we need an extra shadow map """
        self.helperLight = GIHelperLight()
        self.helperLight.setPos(Vec3(50, 50, 100))
        self.helperLight.setShadowMapResolution(512)
        self.helperLight.setFilmSize(
            math.sqrt((self.voxelGridSizeWS.x**2) * 2) * 2)
        self.helperLight.setCastsShadows(True)
        self.pipeline.addLight(self.helperLight)

        self.targetSpace.setShaderInput(
            "dv_uv_size",
            float(self.helperLight.shadowResolution) /
            self.pipeline.settings.shadowAtlasSize)
        self.targetSpace.setShaderInput(
            "dv_atlas",
            self.pipeline.getLightManager().getAtlasTex())

        self._updateGridPos()

    def setup(self):
        """ Setups everything for the GI to work """

        # if self.pipeline.settings.useHardwarePCF:
        #     self.fatal(
        #         "Global Illumination does not work in combination with PCF!")
        #     return

        self._prepareVoxelScene()

        # Create 3D Texture to store the voxel generation grid
        self.voxelGenTex = Texture("VoxelsTemp")
        self.voxelGenTex.setup3dTexture(self.voxelGridResolution.x,
                                        self.voxelGridResolution.y,
                                        self.voxelGridResolution.z,
                                        Texture.TInt, Texture.FR32i)
        self.voxelGenTex.setMinfilter(Texture.FTLinearMipmapLinear)
        self.voxelGenTex.setMagfilter(Texture.FTLinear)

        # Create 3D Texture which is a copy of the voxel generation grid but
        # stable, as the generation grid is updated part by part
        self.voxelStableTex = Texture("VoxelsStable")
        self.voxelStableTex.setup3dTexture(self.voxelGridResolution.x,
                                           self.voxelGridResolution.y,
                                           self.voxelGridResolution.z,
                                           Texture.TFloat, Texture.FRgba8)
        self.voxelStableTex.setMinfilter(Texture.FTLinearMipmapLinear)
        self.voxelStableTex.setMagfilter(Texture.FTLinear)

        for prepare in [self.voxelGenTex, self.voxelStableTex]:
            prepare.setMagfilter(Texture.FTLinear)
            prepare.setMinfilter(Texture.FTLinearMipmapLinear)
            prepare.setWrapU(Texture.WMBorderColor)
            prepare.setWrapV(Texture.WMBorderColor)
            prepare.setWrapW(Texture.WMBorderColor)
            prepare.setBorderColor(Vec4(0, 0, 0, 0))

        self.voxelGenTex.setMinfilter(Texture.FTNearest)
        self.voxelGenTex.setMagfilter(Texture.FTNearest)
        self.voxelGenTex.setWrapU(Texture.WMClamp)
        self.voxelGenTex.setWrapV(Texture.WMClamp)
        self.voxelGenTex.setWrapW(Texture.WMClamp)

        # self.voxelStableTex.generateRamMipmapImages()

        self._createVoxelizeState()

        self.clearTextureNode = NodePath("ClearTexture")
        self.copyTextureNode = NodePath("CopyTexture")
        self.generateMipmapsNode = NodePath("GenerateMipmaps")
        self.convertGridNode = NodePath("ConvertGrid")

        self.reloadShader()

    def _generateMipmaps(self, tex):
        """ Generates all mipmaps for a 3D texture, using a gaussian function """

        pstats_GenerateMipmaps.start()
        currentMipmap = 0
        computeSize = LVecBase3i(self.voxelGridResolution)
        self.generateMipmapsNode.setShaderInput("source", tex)
        self.generateMipmapsNode.setShaderInput("pixelSize",
                                                1.0 / computeSize.x)

        while computeSize.z > 1:
            computeSize /= 2
            self.generateMipmapsNode.setShaderInput("sourceMipmap",
                                                    LVecBase3i(currentMipmap))
            self.generateMipmapsNode.setShaderInput("currentMipmapSize",
                                                    LVecBase3i(computeSize))
            self.generateMipmapsNode.setShaderInput("dest", tex, False, True,
                                                    -1, currentMipmap + 1)
            self._executeShader(self.generateMipmapsNode,
                                (computeSize.x + 7) / 8,
                                (computeSize.y + 7) / 8,
                                (computeSize.z + 7) / 8)
            currentMipmap += 1

        pstats_GenerateMipmaps.stop()

    def _createCleanShader(self):
        shader = BetterShader.loadCompute("Shader/GI/ClearTexture.compute")
        self.clearTextureNode.setShader(shader)

    def _createConvertShader(self):
        shader = BetterShader.loadCompute("Shader/GI/ConvertGrid.compute")
        self.convertGridNode.setShader(shader)

    def _createGenerateMipmapsShader(self):
        shader = BetterShader.loadCompute("Shader/GI/GenerateMipmaps.compute")
        self.generateMipmapsNode.setShader(shader)

    def reloadShader(self):
        self._createCleanShader()
        self._createGenerateMipmapsShader()
        self._createConvertShader()
        self._createVoxelizeState()
        self.frameIndex = 0

    def _clear3DTexture(self, tex, clearVal=None):
        """ Clears a 3D Texture to <clearVal> """
        if clearVal is None:
            clearVal = Vec4(0)

        self.clearTextureNode.setShaderInput("target", tex, False, True, -1, 0)
        self.clearTextureNode.setShaderInput("clearValue", clearVal)

        self._executeShader(self.clearTextureNode, (tex.getXSize() + 7) / 8,
                            (tex.getYSize() + 7) / 8, (tex.getZSize() + 7) / 8)

    def _updateGridPos(self):

        snap = 32.0
        stepSizeX = float(self.voxelGridSizeWS.x * 2.0) / float(
            self.voxelGridResolution.x) * snap
        stepSizeY = float(self.voxelGridSizeWS.y * 2.0) / float(
            self.voxelGridResolution.y) * snap
        stepSizeZ = float(self.voxelGridSizeWS.z * 2.0) / float(
            self.voxelGridResolution.z) * snap

        self.gridPos = self.targetCamera.getPos(self.targetSpace)
        self.gridPos.x -= self.gridPos.x % stepSizeX
        self.gridPos.y -= self.gridPos.y % stepSizeY
        self.gridPos.z -= self.gridPos.z % stepSizeZ

    def process(self):
        if self.targetLight is None:
            self.fatal("The GI cannot work without a target light! Set one "
                       "with setTargetLight() first!")

        if not self.updateEnabled:
            self.voxelizeTarget.setActive(False)
            return

        direction = self.targetLight.getDirection()

        # time.sleep(0.4)

        if self.frameIndex == 0:
            # Find out cam pos

            self.targetSpace.setShaderInput(
                "dv_uv_start", self.helperLight.shadowSources[0].getAtlasPos())

            self.voxelizeTarget.setActive(True)
            # self.voxelizeTarget.setActive(False)

            self.voxelizeLens.setFilmSize(self.voxelGridSizeWS.y * 2,
                                          self.voxelGridSizeWS.z * 2)
            self.voxelizeLens.setNearFar(0.0, self.voxelGridSizeWS.x * 2)

            self.targetSpace.setShaderInput(
                "dv_mvp", Mat4(self.helperLight.shadowSources[0].mvp))
            self.targetSpace.setShaderInput(
                "dv_gridStart", self.gridPos - self.voxelGridSizeWS)
            self.targetSpace.setShaderInput(
                "dv_gridEnd", self.gridPos + self.voxelGridSizeWS)
            self.targetSpace.setShaderInput("dv_lightdir", direction)

            # Clear textures
            self._clear3DTexture(self.voxelGenTex, Vec4(0, 0, 0, 0))

            # Voxelize from x axis
            self.voxelizeCameraNode.setPos(self.gridPos -
                                           Vec3(self.voxelGridSizeWS.x, 0, 0))
            self.voxelizeCameraNode.lookAt(self.gridPos)
            self.targetSpace.setShaderInput("dv_direction", LVecBase3i(0))

        elif self.frameIndex == 1:
            # Voxelize from y axis

            # self.voxelizeTarget.setActive(False)

            self.voxelizeLens.setFilmSize(self.voxelGridSizeWS.x * 2,
                                          self.voxelGridSizeWS.z * 2)
            self.voxelizeLens.setNearFar(0.0, self.voxelGridSizeWS.y * 2)

            self.voxelizeCameraNode.setPos(self.gridPos -
                                           Vec3(0, self.voxelGridSizeWS.y, 0))
            self.voxelizeCameraNode.lookAt(self.gridPos)
            self.targetSpace.setShaderInput("dv_direction", LVecBase3i(1))

        elif self.frameIndex == 2:

            # self.voxelizeTarget.setActive(False)
            # Voxelize from z axis
            self.voxelizeLens.setFilmSize(self.voxelGridSizeWS.x * 2,
                                          self.voxelGridSizeWS.y * 2)
            self.voxelizeLens.setNearFar(0.0, self.voxelGridSizeWS.z * 2)

            self.voxelizeCameraNode.setPos(self.gridPos +
                                           Vec3(0, 0, self.voxelGridSizeWS.z))
            self.voxelizeCameraNode.lookAt(self.gridPos)
            self.targetSpace.setShaderInput("dv_direction", LVecBase3i(2))

        elif self.frameIndex == 3:

            self.voxelizeTarget.setActive(False)

            # Copy the cache to the actual texture
            self.convertGridNode.setShaderInput("src", self.voxelGenTex)
            self.convertGridNode.setShaderInput("dest", self.voxelStableTex)
            self._executeShader(self.convertGridNode,
                                (self.voxelGridResolution.x + 7) / 8,
                                (self.voxelGridResolution.y + 7) / 8,
                                (self.voxelGridResolution.z + 7) / 8)

            # Generate the mipmaps
            self._generateMipmaps(self.voxelStableTex)

            self.helperLight.setPos(self.gridPos)
            self.helperLight.setDirection(direction)

            # We are done now, update the inputs
            self.ptaGridPos[0] = Vec3(self.gridPos)
            self._updateGridPos()

        self.frameIndex += 1
        self.frameIndex = self.frameIndex % 5

    def bindTo(self, node, prefix):
        """ Binds all required shader inputs to a target to compute / display
        the global illumination """

        normFactor = Vec3(
            1.0,
            float(self.voxelGridResolution.y) /
            float(self.voxelGridResolution.x) * self.voxelGridSizeWS.y /
            self.voxelGridSizeWS.x,
            float(self.voxelGridResolution.z) /
            float(self.voxelGridResolution.x) * self.voxelGridSizeWS.z /
            self.voxelGridSizeWS.x)
        node.setShaderInput(prefix + ".gridPos", self.ptaGridPos)
        node.setShaderInput(prefix + ".gridHalfSize", self.voxelGridSizeWS)
        node.setShaderInput(prefix + ".gridResolution",
                            self.voxelGridResolution)
        node.setShaderInput(prefix + ".voxels", self.voxelStableTex)
        node.setShaderInput(prefix + ".voxelNormFactor", normFactor)
        node.setShaderInput(prefix + ".geometry", self.voxelStableTex)

    def _executeShader(self, node, threadsX, threadsY, threadsZ=1):
        """ Executes a compute shader, fetching the shader attribute from a NodePath """
        sattr = node.getAttrib(ShaderAttrib)
        Globals.base.graphicsEngine.dispatchCompute(
            (threadsX, threadsY, threadsZ), sattr, Globals.base.win.get_gsg())
コード例 #16
0
class VoxelizePass(RenderPass):
    """ This pass manages voxelizing the scene from multiple directions to generate
    a 3D voxel grid. It handles the camera setup and provides a simple interface. """
    def __init__(self, pipeline):
        RenderPass.__init__(self)
        self.pipeline = pipeline

    def getID(self):
        return "VoxelizePass"

    def getRequiredInputs(self):
        return {

            # Lighting
            "renderedLightsBuffer": "Variables.renderedLightsBuffer",
            "lights": "Variables.allLights",
            "shadowAtlasPCF": "ShadowScenePass.atlasPCF",
            "shadowAtlas": "ShadowScenePass.atlas",
            "shadowSources": "Variables.allShadowSources",
            "directionToFace": "Variables.directionToFaceLookup",
            "cameraPosition": "Variables.cameraPosition",
            "mainCam": "Variables.mainCam",
            "mainRender": "Variables.mainRender",
        }

    def setVoxelGridResolution(self, voxelGridResolution):
        """ Sets the voxel grid resolution, this is the amount of voxels in every
        direction, so the voxel grid will have voxelGridResolution**3 total voxels. """
        self.voxelGridResolution = voxelGridResolution

    def setVoxelGridSize(self, voxelGridSize):
        """ Sets the size of the voxel grid in world space units. This is the
        size going from the mid of the voxel grid, so the effective voxel grid
        will have twice the size specified in voxelGridSize """
        self.voxelGridSize = voxelGridSize

    def setGridResolutionMultiplier(self, factor):
        """ Sets the density of the voxel grid. """
        self.gridResolutionMultiplier = factor

    def setActive(self, active):
        """ Enables and disables this pass """
        if hasattr(self, "target"):
            self.target.setActive(active)

    def getVoxelTex(self):
        """ Returns a handle to the generated voxel texture """
        return self.voxelGenTex

    def clearGrid(self):
        """ Clears the voxel grid """
        self.voxelGenTex.clearImage()

    def create(self):
        # Create voxelize camera
        self.voxelizeCamera = Camera("VoxelizeCamera")
        self.voxelizeCamera.setCameraMask(BitMask32.bit(4))
        self.voxelizeCameraNode = Globals.render.attachNewNode(
            self.voxelizeCamera)
        self.voxelizeLens = OrthographicLens()
        self.voxelizeLens.setFilmSize(self.voxelGridSize * 2,
                                      self.voxelGridSize * 2)
        self.voxelizeLens.setNearFar(0.0, self.voxelGridSize * 2)
        self.voxelizeCamera.setLens(self.voxelizeLens)
        self.voxelizeCamera.setTagStateKey("VoxelizePassShader")
        Globals.render.setTag("VoxelizePassShader", "Default")

        # Create voxelize tareet
        self.target = RenderTarget("VoxelizePass")
        self.target.setSize(self.voxelGridResolution *
                            self.gridResolutionMultiplier)

        if self.pipeline.settings.useDebugAttachments:
            self.target.addColorTexture()
        else:
            self.target.setColorWrite(False)

        self.target.setCreateOverlayQuad(False)
        self.target.setSource(self.voxelizeCameraNode, Globals.base.win)
        self.target.prepareSceneRender()
        self.target.setActive(False)

        # self.target.getInternalRegion().setSort(-400)
        # self.target.getInternalBuffer().setSort(-399)

    def voxelizeSceneFromDirection(self, gridPos, direction="x"):
        """ Voxelizes the scene from a given direction. This method handles setting 
        the camera position aswell as the near and far plane. If the pass was disabled,
        it also enables this pass.  """
        assert (direction in ["x", "y", "z"])
        self.setActive(True)

        if direction == "x":
            self.voxelizeLens.setFilmSize(self.voxelGridSize * 2,
                                          self.voxelGridSize * 2)
            self.voxelizeLens.setNearFar(0.0, self.voxelGridSize * 2)
            self.voxelizeCameraNode.setPos(gridPos -
                                           Vec3(self.voxelGridSize, 0, 0))
            self.voxelizeCameraNode.lookAt(gridPos)
        elif direction == "y":
            self.voxelizeLens.setFilmSize(self.voxelGridSize * 2,
                                          self.voxelGridSize * 2)
            self.voxelizeLens.setNearFar(0.0, self.voxelGridSize * 2)
            self.voxelizeCameraNode.setPos(gridPos -
                                           Vec3(0, self.voxelGridSize, 0))
            self.voxelizeCameraNode.lookAt(gridPos)
        elif direction == "z":
            self.voxelizeLens.setFilmSize(self.voxelGridSize * 2,
                                          self.voxelGridSize * 2)
            self.voxelizeLens.setNearFar(0.0, self.voxelGridSize * 2)
            self.voxelizeCameraNode.setPos(gridPos +
                                           Vec3(0, 0, self.voxelGridSize))
            self.voxelizeCameraNode.lookAt(gridPos)

    def setShaders(self):
        """ Creates the tag state and loades the voxelizer shader """
        self.registerTagState("Default", NodePath("DefaultVoxelizeState"))
        return []

    def registerTagState(self, name, state):
        """ Registers a new tag state """
        state.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullNone))
        state.setDepthWrite(False)
        state.setDepthTest(False)
        state.setAttrib(DepthTestAttrib.make(DepthTestAttrib.MNone))
        state.setShaderInput("voxelizeCam", self.voxelizeCameraNode)
        self.voxelizeCamera.setTagState(name, state.getState())

    def setShaderInput(self, *args):
        Globals.base.render.setShaderInput(*args)

    def getOutputs(self):
        return {}
コード例 #17
0
class ShadowSource(DebugObject, ShaderStructElement):

    """ This class can be seen as a camera. It stores the necessary
    data to generate and store the shadow map for the assigned lens
    (like computing the MVP), and also stores information about the
    shadowmap, like position in the shadow atlas, or resolution. Each
    ShadowSource has a unique index, which is used by the LightClass
    to identify which sources belong to it.

    TODO: Support OrtographicLens
    """

    # Store a global index for assigning unique ids to the instances
    _GlobalShadowIndex = 1000

    @classmethod
    def getExposedAttributes(self):
        return {
            "resolution": "int",
            "atlasPos": "vec2",
            "mvp": "mat4",
            "nearPlane": "float",
            "farPlane": "float"
        }

    @classmethod
    def _generateUID(self):
        """ Generates an uid and returns that """
        self._GlobalShadowIndex += 1
        return self._GlobalShadowIndex

    def __init__(self):
        """ Creates a new ShadowSource. After the creation, a lens can be added
        with setupPerspectiveLens. """
        self.index = self._generateUID()

        DebugObject.__init__(self, "ShadowSource-" + str(self.index))
        ShaderStructElement.__init__(self)

        self.valid = False
        self.camera = Camera("ShadowSource-" + str(self.index))
        self.cameraNode = NodePath(self.camera)
        self.cameraNode.reparentTo(Globals.render)
        self.resolution = 1024
        self.atlasPos = Vec2(0)
        self.doesHaveAtlasPos = False
        self.sourceIndex = 0
        self.mvp = Mat4()
        self.sourceIndex = -1
        self.nearPlane = 0.0
        self.farPlane = 1000.0
        self.converterYUR = None
        

    def getSourceIndex(self):
        """ Returns the assigned source index. The source index is the index
        of the ShadowSource in the ShadowSources array of the assigned
        Light. """
        return self.sourceIndex

    def getUid(self):
        """ Returns the uid of the light """
        return self.index

    def setSourceIndex(self, index):
        """ Sets the source index of this source. This is called by the light,
        as only the light knows at which position this source is in the
        Sources array. """
        self.sourceIndex = index

    def computeMVP(self):
        """ Computes the modelViewProjection matrix for the lens. Actually,
        this is the worldViewProjection matrix, but for convenience it is
        called mvp. """
        projMat = self.converterYUR
        transformMat = TransformState.makeMat(
            Mat4.convertMat(Globals.base.win.getGsg().getInternalCoordinateSystem(),
                            CSZupRight))
        modelViewMat = transformMat.invertCompose(
            Globals.render.getTransform(self.cameraNode)).getMat()
        self.mvp = UnalignedLMatrix4f(modelViewMat * projMat)

    def assignAtlasPos(self, x, y):
        """ Assigns this source a position in the shadow atlas. This is called
        by the shadow atlas. Coordinates are float from 0 .. 1 """
        self.atlasPos = Vec2(x, y)
        self.doesHaveAtlasPos = True

    def update(self):
        """ Updates the shadow source. Currently only recomputes the mvp. """
        self.computeMVP()

    def getAtlasPos(self):
        """ Returns the assigned atlas pos, if present. Coordinates are float
        from 0 .. 1 """
        return self.atlasPos

    def hasAtlasPos(self):
        """ Returns wheter this ShadowSource has already a position in the
        shadow atlas """
        return self.doesHaveAtlasPos

    def removeFromAtlas(self):
        """ Deletes the atlas coordinates, called by the atlas after the
        Source got removed from the atlas """
        self.doesHaveAtlasPos = False
        self.atlasPos = Vec2(0)

    def setResolution(self, resolution):
        """ Sets the resolution in pixels of this shadow source. Has to be
        a multiple of the tileSize specified in LightManager """
        assert(resolution > 1 and resolution <= 8192)
        self.resolution = resolution

    def getResolution(self):
        """ Returns the resolution of the shadow source in pixels """
        return self.resolution

    def setupPerspectiveLens(self, near=0.1, far=100.0, fov=(90, 90)):
        """ Setups a PerspectiveLens with a given nearPlane, farPlane
        and FoV. The FoV is a tuple in the format
        (Horizontal FoV, Vertical FoV) """
        # self.debug("setupPerspectiveLens(",near,",",far,",",fov,")")
        self.lens = PerspectiveLens()
        self.lens.setNearFar(near, far)
        self.lens.setFov(fov[0], fov[1])
        self.camera.setLens(self.lens)
        self.nearPlane = near
        self.farPlane = far
        self.rebuildMatrixCache()

    def setupOrtographicLens(self, near=0.1, far=100.0, filmSize=(512, 512)):
        """ Setups a OrtographicLens with a given nearPlane, farPlane
        and filmSize. The filmSize is a tuple in the format
        (filmWidth, filmHeight) in world space. """
        # self.debug("setupOrtographicLens(",near,",",far,",",filmSize,")")
        self.lens = OrtographicLens()
        self.lens.setNearFar(near, far)
        self.lens.setFilmSize(*filmSize)
        self.camera.setLens(self.lens)
        self.nearPlane = near
        self.farPlane = far
        self.rebuildMatrixCache()

    def rebuildMatrixCache(self):
        """ Computes values frequently used to compute the mvp """
        self.converterYUR = Mat4.convertMat(CSYupRight, self.lens.getCoordinateSystem()) * self.lens.getProjectionMat()

    def setPos(self, pos):
        """ Sets the position in world space """
        self.cameraNode.setPos(pos)

    def setHpr(self, hpr):
        """ Sets the rotation in world space """
        self.cameraNode.setHpr(hpr)

    def lookAt(self, pos):
        """ Looks at a point (in world space) """
        self.cameraNode.lookAt(pos.x, pos.y, pos.z)

    def invalidate(self):
        """ Invalidates this shadow source, means telling the LightManager
        that the shadow map for this light should be rebuilt. Otherwise it
        won't get refreshed """
        self.valid = False

    def setValid(self):
        """ The LightManager calls this after the shadow map got updated
        successfully """
        self.valid = True

    def isValid(self):
        """ Returns wether the shadow map is still valid or should
        be refreshed """
        return self.valid

    def __repr__(self):
        """ Returns a representative string of this instance """
        return "ShadowSource[id=" + str(self.index) + "]"
コード例 #18
0
ファイル: playerBase.py プロジェクト: grimfang/Paintball
    def __init__(self):
        # Player Model setup
        self.player = Actor("Player",
                            {"Run":"Player-Run",
                            "Sidestep":"Player-Sidestep",
                            "Idle":"Player-Idle"})
        self.player.setBlend(frameBlend = True)
        self.player.setPos(0, 0, 0)
        self.player.pose("Idle", 0)
        self.player.reparentTo(render)
        self.player.hide()

        self.footstep = base.audio3d.loadSfx('footstep.ogg')
        self.footstep.setLoop(True)
        base.audio3d.attachSoundToObject(self.footstep, self.player)

        # Create a brush to paint on the texture
        splat = PNMImage("../data/Splat.png")
        self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1)

        CamMask = BitMask32.bit(0)
        AvBufMask = BitMask32.bit(1)
        self.avbuf = None
        if base.win:
            self.avbufTex = Texture('avbuf')
            self.avbuf = base.win.makeTextureBuffer('avbuf', 256, 256, self.avbufTex, True)
            cam = Camera('avbuf')
            cam.setLens(base.camNode.getLens())
            self.avbufCam = base.cam.attachNewNode(cam)
            dr = self.avbuf.makeDisplayRegion()
            dr.setCamera(self.avbufCam)
            self.avbuf.setActive(False)
            self.avbuf.setClearColor((1, 0, 0, 1))
            cam.setCameraMask(AvBufMask)
            base.camNode.setCameraMask(CamMask)

            # avbuf renders everything it sees with the gradient texture.
            tex = loader.loadTexture('gradient.png')
            np = NodePath('np')
            np.setTexture(tex, 100)
            np.setColor((1, 1, 1, 1), 100)
            np.setColorScaleOff(100)
            np.setTransparency(TransparencyAttrib.MNone, 100)
            np.setLightOff(100)
            cam.setInitialState(np.getState())
            #render.hide(AvBufMask)

        # Setup a texture stage to paint on the player
        self.paintTs = TextureStage('paintTs')
        self.paintTs.setMode(TextureStage.MDecal)
        self.paintTs.setSort(10)
        self.paintTs.setPriority(10)

        self.tex = Texture('paint_av_%s'%id(self))

        # Setup a PNMImage that will hold the paintable texture of the player
        self.imageSizeX = 64
        self.imageSizeY = 64
        self.p = PNMImage(self.imageSizeX, self.imageSizeY, 4)
        self.p.fill(1)
        self.p.alphaFill(0)
        self.tex.load(self.p)
        self.tex.setWrapU(self.tex.WMClamp)
        self.tex.setWrapV(self.tex.WMClamp)

        # Apply the paintable texture to the avatar
        self.player.setTexture(self.paintTs, self.tex)

        # team
        self.playerTeam = ""
        # A lable that will display the players team
        self.lblTeam = DirectLabel(
            scale = 1,
            pos = (0, 0, 3),
            frameColor = (0, 0, 0, 0),
            text = "TEAM",
            text_align = TextNode.ACenter,
            text_fg = (0,0,0,1))
        self.lblTeam.reparentTo(self.player)
        self.lblTeam.setBillboardPointEye()

        # basic player values
        self.maxHits = 3
        self.currentHits = 0
        self.isOut = False

        self.TorsorControl = self.player.controlJoint(None,"modelRoot","Torsor")

        # setup the collision detection
        # wall and object collision
        self.playerSphere = CollisionSphere(0, 0, 1, 1)
        self.playerCollision = self.player.attachNewNode(CollisionNode("playerCollision%d"%id(self)))
        self.playerCollision.node().addSolid(self.playerSphere)
        base.pusher.addCollider(self.playerCollision, self.player)
        base.cTrav.addCollider(self.playerCollision, base.pusher)
        # foot (walk) collision
        self.playerFootRay = self.player.attachNewNode(CollisionNode("playerFootCollision%d"%id(self)))
        self.playerFootRay.node().addSolid(CollisionRay(0, 0, 2, 0, 0, -1))
        self.playerFootRay.node().setIntoCollideMask(0)
        self.lifter = CollisionHandlerFloor()
        self.lifter.addCollider(self.playerFootRay, self.player)
        base.cTrav.addCollider(self.playerFootRay, self.lifter)

        # Player weapon setup
        self.gunAttach = self.player.exposeJoint(None, "modelRoot", "WeaponSlot_R")
        self.color = LPoint3f(1, 1, 1)
        self.gun = Gun(id(self))
        self.gun.reparentTo(self.gunAttach)
        self.gun.hide()
        self.gun.setColor(self.color)

        self.hud = None

        # Player controls setup
        self.keyMap = {"left":0, "right":0, "forward":0, "backward":0}
        # screen sizes
        self.winXhalf = base.win.getXSize() / 2
        self.winYhalf = base.win.getYSize() / 2
        self.mouseSpeedX = 0.1
        self.mouseSpeedY = 0.1
        # AI controllable variables
        self.AIP = 0.0
        self.AIH = 0.0

        self.movespeed = 5.0

        self.userControlled = False

        self.accept("Bulet-hit-playerCollision%d" % id(self), self.hit)
        self.accept("window-event", self.recalcAspectRatio)
コード例 #19
0
    def renderQuadInto(self,
                       name="filter-stage",
                       mul=1,
                       div=1,
                       align=1,
                       depthtex=None,
                       colortex=None,
                       auxtex0=None,
                       auxtex1=None,
                       fbprops=None):
        """ Creates an offscreen buffer for an intermediate
        computation. Installs a quad into the buffer.  Returns
        the fullscreen quad.  The size of the buffer is initially
        equal to the size of the main window.  The parameters 'mul',
        'div', and 'align' can be used to adjust that size. """

        texgroup = (depthtex, colortex, auxtex0, auxtex1)

        winx, winy = self.getScaledSize(mul, div, align)

        depthbits = int(depthtex is not None)

        if fbprops is not None:
            buffer = self.createBuffer(name,
                                       winx,
                                       winy,
                                       texgroup,
                                       depthbits,
                                       fbprops=fbprops)
        else:
            buffer = self.createBuffer(name, winx, winy, texgroup, depthbits)

        if buffer is None:
            return None

        cm = CardMaker("filter-stage-quad")
        cm.setFrameFullscreenQuad()
        quad = NodePath(cm.generate())
        quad.setDepthTest(0)
        quad.setDepthWrite(0)
        quad.setColor(1, 0.5, 0.5, 1)

        quadcamnode = Camera("filter-quad-cam")
        lens = OrthographicLens()
        lens.setFilmSize(2, 2)
        lens.setFilmOffset(0, 0)
        lens.setNearFar(-1000, 1000)
        quadcamnode.setLens(lens)
        quadcam = quad.attachNewNode(quadcamnode)

        dr = buffer.makeDisplayRegion((0, 1, 0, 1))
        dr.disableClears()
        dr.setCamera(quadcam)
        dr.setActive(True)
        dr.setScissorEnabled(False)

        # This clear stage is important if the buffer is padded, so that
        # any pixels accidentally sampled in the padded region won't
        # be reading from unititialised memory.
        buffer.setClearColor((0, 0, 0, 1))
        buffer.setClearColorActive(True)

        self.buffers.append(buffer)
        self.sizes.append((mul, div, align))

        return quad
コード例 #20
0
class CreditsReel(object):
    '''
    Creates a Panda scene that's independent of the main render tree, so that
    the credits can be displayed in a smaller display region within the main
    screen.
    '''
    def __init__(self, app):
        self.app = app
        self.do = DirectObject()

        self.running = False
        self.displayRegion = None
        self.root = NodePath('creditsRender')
        self.camera = Camera('creditsCam')
        self.cameraNP = NodePath(self.camera)

        # Set parameters to match those of render2d
        self.root.setDepthTest(0)
        self.root.setDepthWrite(0)
        self.root.setMaterialOff(1)
        self.root.setTwoSided(1)

        self.aspect2d = self.root  # self.root.attachNewNode('creditsAspect')

        lens = OrthographicLens()
        lens.setFilmSize(2, 2)
        lens.setFilmOffset(0, 0)
        lens.setNearFar(-1000, 1000)
        self.camera.setLens(lens)

        self.cameraNP.reparentTo(self.root)

        self.scrollTask = None
        self.lastTime = None
        self.creditsFileLoaded = False

    def loadCreditsFileIfNeeded(self):
        if self.creditsFileLoaded:
            return

        filePath = getPath(startupMenu, 'credits3d.txt')
        with codecs.open(filePath, 'rU', encoding='utf-8') as f:
            creditsLines = f.read().splitlines()

        y = 0
        for line in creditsLines:
            if line.startswith('!!'):
                font = self.app.fonts.creditsH1
                line = line[len('!!'):]
            elif line.startswith('!'):
                font = self.app.fonts.creditsH2
                line = line[len('!'):]
            else:
                font = self.app.fonts.creditsFont

            lineHeight = font.getPandaLineHeight(self.app)
            node = font.makeOnscreenText(
                self.app,
                text=line or ' ',  # Prevents .getNumRows() bug
                fg=self.app.theme.colours.mainMenuColour,
                align=TextNode.ACenter,
                pos=(0, y - lineHeight),
                parent=self.aspect2d,
                wordwrap=28,
            )
            y -= lineHeight * (node.textNode.getNumRows() + 0.2)

        self.creditsFileLoaded = True

    def stop(self):
        if not self.running:
            return
        self.running = False
        self.do.ignoreAll()

        if self.scrollTask is not None:
            self.app.panda.taskMgr.remove(self.scrollTask)
            self.scrollTask = None

        if self.displayRegion is not None:
            self.displayRegion.setActive(False)

    def start(self):
        self.cameraNP.setPos((0, 0, 0))
        if self.running:
            return
        self.running = True

        self.loadCreditsFileIfNeeded()

        if self.scrollTask is None:
            self.scrollTask = self.app.panda.taskMgr.add(
                self.updateCredits, 'creditsLoop')
            self.lastTime = self.scrollTask.time

        if self.displayRegion is None:
            self.displayRegion = self.app.panda.win.makeDisplayRegion()
            self.displayRegion.setSort(5)
            self.displayRegion.setClearDepthActive(1)
            self.displayRegion.setIncompleteRender(False)
            self.displayRegion.setCamera(self.cameraNP)

        self.displayRegion.setActive(True)
        self.do.accept('aspectRatioChanged', self.aspectRatioChanged)
        self.aspectRatioChanged()

    def aspectRatioChanged(self):
        # Scaling from -1 to +1
        idealTop = 0.66
        idealBottom = -0.74

        aspectRatio = self.app.panda.getAspectRatio()
        top = idealTop * min(aspectRatio * 3. / 4, 1)
        bottom = idealBottom * min(aspectRatio * 3. / 4, 1)

        self.displayRegion.setDimensions(0, 1, 0.5 * (1 + bottom),
                                         0.5 * (1 + top))

        windowRatio = 2 * aspectRatio / (top - bottom)

        self.cameraNP.setScale(windowRatio * 3. / 4, 1.0, 1.0)

    def updateCredits(self, task):
        deltaT = task.time - self.lastTime
        self.lastTime = task.time

        z = self.cameraNP.getZ()
        z -= deltaT * CREDITS_SCROLL_SPEED
        self.cameraNP.setZ(z)
        return Task.cont