class ShadowScenePass(RenderPass): """ This pass manages rendering the scene from the perspective of the shadow sources to generate the shadow maps. It also handles creating and managing the different regions of the shadow atlas, aswell as the initial state of all cameras assigned to the regions """ def __init__(self): RenderPass.__init__(self) self.maxRegions = 8 self.shadowScene = Globals.base.render def setMaxRegions(self, maxRegions): """ Sets the maximum amount of regions the atlas has. This is usually equal to the maximum number of shadow updates per frame """ self.maxRegions = maxRegions def getID(self): return "ShadowScenePass" def getRequiredInputs(self): return { "numUpdates": "Variables.numShadowUpdates", "updateSources": "Variables.shadowUpdateSources" } def setShaders(self): casterShader = Shader.load(Shader.SLGLSL, "Shader/DefaultShaders/ShadowCasting/vertex.glsl", "Shader/DefaultShaders/ShadowCasting/fragment.glsl") initialState = NodePath("ShadowCasterState") initialState.setShader(casterShader, 100) initialState.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.COff)) for camera in self.shadowCameras: camera.node().setTagState("Default", initialState.getState()) casterShaderTransparent = Shader.load(Shader.SLGLSL, "Shader/DefaultShaders/TransparentShadowCasting/vertex.glsl", "Shader/DefaultShaders/TransparentShadowCasting/fragment.glsl") initialState = NodePath("ShadowCasterStateTransparent") initialState.setShader(casterShaderTransparent, 100) initialState.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.COff)) for camera in self.shadowCameras: camera.node().setTagState("Transparent", initialState.getState()) return [casterShader, casterShaderTransparent] def setSize(self, size): """ Sets the shadow atlas size """ self.size = size def setActiveRegionCount(self, activeCount): """ Sets the number of active regions, disabling all other regions. If the count is less than 1, completely disables the pass """ if activeCount < 1: self.target.setActive(False) for region in self.renderRegions: region.setActive(False) else: self.target.setActive(True) for index, region in enumerate(self.renderRegions): if index < activeCount: region.setActive(True) pass else: region.setActive(False) def setRegionDimensions(self, index, l, r, b, t): """ Sets the dimensions of the n-th region to the given dimensions """ self.renderRegions[index].setDimensions(l, r, b, t) def getRegionCamera(self, index): """ Returns the camera of the n-th region """ return self.shadowCameras[index] def create(self): # Create the atlas target self.target = RenderTarget("ShadowAtlas") self.target.setSize(self.size) self.target.addDepthTexture() self.target.setDepthBits(32) self.target.setColorWrite(False) self.target.setCreateOverlayQuad(False) # self.target.setActive(False) self.target.setSource( NodePath(Camera("tmp")), Globals.base.win) self.target.prepareSceneRender() self.target.setClearDepth(False) # Set the appropriate filter modes dTex = self.target.getDepthTexture() dTex.setWrapU(SamplerState.WMClamp) dTex.setWrapV(SamplerState.WMClamp) # Remove the default postprocess quad # self.target.getQuad().node().removeAllChildren() # self.target.getInternalRegion().setSort(-200) self.target.getInternalRegion().disableClears() self.target.getInternalBuffer().disableClears() # self.target.getInternalBuffer().setSort(-300) # Create default initial state initialState = NodePath("InitialState") initialState.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.COff)) # Create a camera for each update self.shadowCameras = [] for i in xrange(self.maxRegions): shadowCam = Camera("ShadowComputeCamera") shadowCam.setTagStateKey("ShadowPassShader") shadowCam.setInitialState(initialState.getState()) shadowCam.setCameraMask(BitMask32.bit(3)) shadowCamNode = self.shadowScene.attachNewNode(shadowCam) self.shadowCameras.append(shadowCamNode) # Create regions self.renderRegions = [] buff = self.target.getInternalBuffer() for i in xrange(self.maxRegions): dr = buff.makeDisplayRegion() dr.setSort(1000) dr.setClearDepthActive(True) dr.setClearDepth(1.0) # dr.setClearColorActive(False) # dr.setClearColor(Vec4(1,1,1,1)) dr.setCamera(self.shadowCameras[i]) dr.setActive(False) self.renderRegions.append(dr) self.pcfSampleState = SamplerState() self.pcfSampleState.setMinfilter(SamplerState.FTShadow) self.pcfSampleState.setMagfilter(SamplerState.FTShadow) self.pcfSampleState.setWrapU(SamplerState.WMClamp) self.pcfSampleState.setWrapV(SamplerState.WMClamp) # Globals.render.setTag("ShadowPassShader", "Default") def setShaderInput(self, name, val, *args): self.shadowScene.setShaderInput(name, val, *args) def getOutputs(self): return { "ShadowScenePass.atlas": lambda: self.target.getDepthTexture(), "ShadowScenePass.atlasPCF": lambda: (self.target.getDepthTexture(), self.pcfSampleState), }