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 a camera for each update self.shadowCameras = [] for i in xrange(self.maxRegions): shadowCam = Camera("ShadowMapCamera-" + str(i)) shadowCam.setTagStateKey("ShadowPassShader") # 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)
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 a camera for each update self.shadowCameras = [] for i in xrange(self.maxRegions): shadowCam = Camera("ShadowMapCamera-" + str(i)) shadowCam.setTagStateKey("ShadowPassShader") # 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)
def make_pcf_state(self): state = SamplerState() state.set_minfilter(SamplerState.FT_shadow) state.set_magfilter(SamplerState.FT_shadow) return state
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): return [] def registerTagState(self, name, state): """ Registers a new tag state """ state.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.COff)) initialState = state.getState() for camera in self.shadowCameras: camera.node().setTagState(name, initialState) 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 a camera for each update self.shadowCameras = [] for i in xrange(self.maxRegions): shadowCam = Camera("ShadowMapCamera-" + str(i)) shadowCam.setTagStateKey("ShadowPassShader") # 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), }
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): return [] def registerTagState(self, name, state): """ Registers a new tag state """ state.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.COff)) initialState = state.getState() for camera in self.shadowCameras: camera.node().setTagState(name, initialState) 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 a camera for each update self.shadowCameras = [] for i in xrange(self.maxRegions): shadowCam = Camera("ShadowMapCamera-" + str(i)) shadowCam.setTagStateKey("ShadowPassShader") # 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), }
def initialize(self): assert (not self._initialized) assert (self._focal_camera is not None and self._focal_lens is not None) assert (self._parent is not None) if VERBOSE: print "TerrainQuadtree - initialize" t_init_begin = time.time() if VERBOSE: print "TerrainQuadtree - loading materials" from os.path import join, isfile state = SamplerState() state.setWrapU(SamplerState.WMRepeat) state.setWrapV(SamplerState.WMRepeat) # t.setKeepRamImage(False) # t.setMinfilter(SamplerState.FTLinear) state.setMinfilter(self.mipmapMIN) state.setMagfilter(self.mipmapMAG) state.setAnisotropicDegree(8) for material in self._materials: tex0 = join(self._material_path, "{0}_1.png".format(material)) tex1 = join(self._material_path, "{0}_2.png".format(material)) assert (isfile(tex0) and isfile(tex1)) tex0t = loader.loadTexture(tex0) tex1t = loader.loadTexture(tex1) tex0t.setFormat(Texture.FSrgbAlpha) tex1t.setFormat(Texture.FRgba) self._element_node.setShaderInput("mt_{0}_0".format(material), tex0t, state) self._element_node.setShaderInput("mt_{0}_1".format(material), tex1t, state) self._initialized = True self._plane_quadtree.setFocalCamera(self._focal_camera) self._plane_quadtree.setFocalLens(self._focal_lens) self._plane_quadtree.init() if VERBOSE: t_init_end = time.time() t_init = t_init_end - t_init_begin print t_init * 1000.0, "ms to initialize" self.update()
class LightManager(DebugObject): """ This class is internally used by the RenderingPipeline to handle Lights and their Shadows. It stores a list of lights, and updates the required ShadowSources per frame. There are two main update methods: updateLights processes each light and does a basic frustum check. If the light is in the frustum, its ID is passed to the light precompute container (set with setLightingCuller). Also, each shadowSource of the light is checked, and if it reports to be invalid, it's queued to the list of queued shadow updates. updateShadows processes the queued shadow updates and setups everything to render the shadow depth textures to the shadow atlas. Lights can be added with addLight. Notice you cannot change the shadow resolution or wether the light casts shadows after you called addLight. This is because it might already have a position in the atlas, and so the atlas would have to delete it's map, which is not supported (yet). This shouldn't be an issue, as you usually always know before if a light will cast shadows or not. """ def __init__(self, pipeline): """ Creates a new LightManager. It expects a RenderPipeline as parameter. """ DebugObject.__init__(self, "LightManager") self._initArrays() self.pipeline = pipeline self.settings = pipeline.getSettings() # Create arrays to store lights & shadow sources self.lights = [] self.shadowSources = [] self.queuedShadowUpdates = [] self.allLightsArray = ShaderStructArray(Light, self.maxTotalLights) self.updateCallbacks = [] self.cullBounds = None self.shadowScene = Globals.render # Create atlas self.shadowAtlas = ShadowAtlas() self.shadowAtlas.setSize(self.settings.shadowAtlasSize) self.shadowAtlas.create() self.maxShadowMaps = 24 self.maxShadowUpdatesPerFrame = self.settings.maxShadowUpdatesPerFrame self.numShadowUpdatesPTA = PTAInt.emptyArray(1) self.updateShadowsArray = ShaderStructArray( ShadowSource, self.maxShadowUpdatesPerFrame) self.allShadowsArray = ShaderStructArray( ShadowSource, self.maxShadowMaps) # Create shadow compute buffer self._createShadowComputationBuffer() # Create the initial shadow state self.shadowComputeCamera.setTagStateKey("ShadowPassShader") self._createTagStates() self.shadowScene.setTag("ShadowPassShader", "Default") # Create debug overlay self._createDebugTexts() # Disable buffer on start self.shadowComputeTarget.setActive(False) # Bind arrays self.updateShadowsArray.bindTo(self.shadowScene, "updateSources") self.updateShadowsArray.bindTo( self.shadowComputeTarget, "updateSources") # Set initial inputs for target in [self.shadowComputeTarget, self.shadowScene]: target.setShaderInput("numUpdates", self.numShadowUpdatesPTA) self.lightingComputator = None self.lightCuller = None self.skip = 0 self.skipRate = 0 def _createTagStates(self): # Create shadow caster shader self.shadowCasterShader = BetterShader.load( "Shader/DefaultShadowCaster/vertex.glsl", "Shader/DefaultShadowCaster/fragment.glsl", "Shader/DefaultShadowCaster/geometry.glsl") initialState = NodePath("ShadowCasterState") initialState.setShader(self.shadowCasterShader, 30) # initialState.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullNone)) initialState.setAttrib(ColorWriteAttrib.make(ColorWriteAttrib.COff)) self.shadowComputeCamera.setTagState( "Default", initialState.getState()) def _createShadowComputationBuffer(self): """ This creates the internal shadow buffer which also is the shadow atlas. Shadow maps are rendered to this using Viewports (thank you rdb for adding this!). It also setups the base camera which renders the shadow objects, although a custom mvp is passed to the shaders, so the camera is mainly a dummy """ # Create camera showing the whole scene self.shadowComputeCamera = Camera("ShadowComputeCamera") self.shadowComputeCameraNode = self.shadowScene.attachNewNode( self.shadowComputeCamera) self.shadowComputeCamera.getLens().setFov(30, 30) self.shadowComputeCamera.getLens().setNearFar(1.0, 2.0) # Disable culling self.shadowComputeCamera.setBounds(OmniBoundingVolume()) self.shadowComputeCamera.setCullBounds(OmniBoundingVolume()) self.shadowComputeCamera.setFinal(True) self.shadowComputeCameraNode.setPos(0, 0, 1500) self.shadowComputeCameraNode.lookAt(0, 0, 0) self.shadowComputeTarget = RenderTarget("ShadowAtlas") self.shadowComputeTarget.setSize(self.shadowAtlas.getSize()) self.shadowComputeTarget.addDepthTexture() self.shadowComputeTarget.setDepthBits(32) self.shadowComputeTarget.setSource( self.shadowComputeCameraNode, Globals.base.win) self.shadowComputeTarget.prepareSceneRender() # This took me a long time to figure out. If not removing the quad # children, the color and aux buffers will be overridden each frame. # Quite annoying! self.shadowComputeTarget.getQuad().node().removeAllChildren() self.shadowComputeTarget.getInternalRegion().setSort(-200) self.shadowComputeTarget.getInternalRegion().setNumRegions( self.maxShadowUpdatesPerFrame + 1) self.shadowComputeTarget.getInternalRegion().setDimensions(0, (0, 0, 0, 0)) self.shadowComputeTarget.getInternalRegion().disableClears() self.shadowComputeTarget.getInternalBuffer().disableClears() self.shadowComputeTarget.getInternalBuffer().setSort(-300) # We can't clear the depth per viewport. # But we need to clear it in any way, as we still want # z-testing in the buffers. So well, we create a # display region *below* (smaller sort value) each viewport # which has a depth-clear assigned. This is hacky, I know. self.depthClearer = [] for i in range(self.maxShadowUpdatesPerFrame): buff = self.shadowComputeTarget.getInternalBuffer() dr = buff.makeDisplayRegion() dr.setSort(-250) for k in xrange(16): dr.setClearActive(k, True) dr.setClearValue(k, Vec4(0.5,0.5,0.5,1)) dr.setClearDepthActive(True) dr.setClearDepth(1.0) dr.setDimensions(0,0,0,0) dr.setActive(False) self.depthClearer.append(dr) # When using hardware pcf, set the correct filter types if self.settings.useHardwarePCF: self.pcfSampleState = SamplerState() self.pcfSampleState.setMinfilter(SamplerState.FTShadow) self.pcfSampleState.setMagfilter(SamplerState.FTShadow) self.pcfSampleState.setWrapU(SamplerState.WMClamp) self.pcfSampleState.setWrapV(SamplerState.WMClamp) dTex = self.getAtlasTex() dTex.setWrapU(Texture.WMClamp) dTex.setWrapV(Texture.WMClamp) def getAllLights(self): """ Returns all attached lights """ return self.lights def getPCFSampleState(self): """ Returns the pcf sample state used to sample the shadow map """ return self.pcfSampleState def processCallbacks(self): """ Processes all updates from the previous frame """ for update in self.updateCallbacks: update.onUpdated() self.updateCallbacks = [] def _createDebugTexts(self): """ Creates a debug overlay if specified in the pipeline settings """ self.lightsVisibleDebugText = None self.lightsUpdatedDebugText = None if self.settings.displayDebugStats: try: from Code.GUI.FastText import FastText self.lightsVisibleDebugText = FastText(pos=Vec2( Globals.base.getAspectRatio() - 0.1, 0.84), rightAligned=True, color=Vec3(1, 1, 0), size=0.036) self.lightsUpdatedDebugText = FastText(pos=Vec2( Globals.base.getAspectRatio() - 0.1, 0.8), rightAligned=True, color=Vec3(1, 1, 0), size=0.036) except Exception, msg: self.debug( "Overlay is disabled because FastText wasn't loaded")
def _createShadowComputationBuffer(self): """ This creates the internal shadow buffer which also is the shadow atlas. Shadow maps are rendered to this using Viewports (thank you rdb for adding this!). It also setups the base camera which renders the shadow objects, although a custom mvp is passed to the shaders, so the camera is mainly a dummy """ # Create camera showing the whole scene self.shadowComputeCamera = Camera("ShadowComputeCamera") self.shadowComputeCameraNode = self.shadowScene.attachNewNode( self.shadowComputeCamera) self.shadowComputeCamera.getLens().setFov(30, 30) self.shadowComputeCamera.getLens().setNearFar(1.0, 2.0) # Disable culling self.shadowComputeCamera.setBounds(OmniBoundingVolume()) self.shadowComputeCamera.setCullBounds(OmniBoundingVolume()) self.shadowComputeCamera.setFinal(True) self.shadowComputeCameraNode.setPos(0, 0, 1500) self.shadowComputeCameraNode.lookAt(0, 0, 0) self.shadowComputeTarget = RenderTarget("ShadowAtlas") self.shadowComputeTarget.setSize(self.shadowAtlas.getSize()) self.shadowComputeTarget.addDepthTexture() self.shadowComputeTarget.setDepthBits(32) self.shadowComputeTarget.setSource( self.shadowComputeCameraNode, Globals.base.win) self.shadowComputeTarget.prepareSceneRender() # This took me a long time to figure out. If not removing the quad # children, the color and aux buffers will be overridden each frame. # Quite annoying! self.shadowComputeTarget.getQuad().node().removeAllChildren() self.shadowComputeTarget.getInternalRegion().setSort(-200) self.shadowComputeTarget.getInternalRegion().setNumRegions( self.maxShadowUpdatesPerFrame + 1) self.shadowComputeTarget.getInternalRegion().setDimensions(0, (0, 0, 0, 0)) self.shadowComputeTarget.getInternalRegion().disableClears() self.shadowComputeTarget.getInternalBuffer().disableClears() self.shadowComputeTarget.getInternalBuffer().setSort(-300) # We can't clear the depth per viewport. # But we need to clear it in any way, as we still want # z-testing in the buffers. So well, we create a # display region *below* (smaller sort value) each viewport # which has a depth-clear assigned. This is hacky, I know. self.depthClearer = [] for i in range(self.maxShadowUpdatesPerFrame): buff = self.shadowComputeTarget.getInternalBuffer() dr = buff.makeDisplayRegion() dr.setSort(-250) for k in xrange(16): dr.setClearActive(k, True) dr.setClearValue(k, Vec4(0.5,0.5,0.5,1)) dr.setClearDepthActive(True) dr.setClearDepth(1.0) dr.setDimensions(0,0,0,0) dr.setActive(False) self.depthClearer.append(dr) # When using hardware pcf, set the correct filter types if self.settings.useHardwarePCF: self.pcfSampleState = SamplerState() self.pcfSampleState.setMinfilter(SamplerState.FTShadow) self.pcfSampleState.setMagfilter(SamplerState.FTShadow) self.pcfSampleState.setWrapU(SamplerState.WMClamp) self.pcfSampleState.setWrapV(SamplerState.WMClamp) dTex = self.getAtlasTex() dTex.setWrapU(Texture.WMClamp) dTex.setWrapV(Texture.WMClamp)
def initialize(self): assert(not self._initialized) assert(self._focal_camera is not None and self._focal_lens is not None) assert(self._parent is not None) if VERBOSE: print "TerrainQuadtree - initialize" t_init_begin = time.time() if VERBOSE: print "TerrainQuadtree - loading materials" from os.path import join, isfile state = SamplerState() state.setWrapU(SamplerState.WMRepeat) state.setWrapV(SamplerState.WMRepeat) # t.setKeepRamImage(False) # t.setMinfilter(SamplerState.FTLinear) state.setMinfilter(self.mipmapMIN) state.setMagfilter(self.mipmapMAG) state.setAnisotropicDegree(8) for material in self._materials: tex0 = join(self._material_path, "{0}_1.png".format(material)) tex1 = join(self._material_path, "{0}_2.png".format(material)) assert(isfile(tex0) and isfile(tex1)) tex0t = loader.loadTexture(tex0) tex1t = loader.loadTexture(tex1) tex0t.setFormat(Texture.FSrgbAlpha) tex1t.setFormat(Texture.FRgba) self._element_node.setShaderInput("mt_{0}_0".format(material), tex0t, state) self._element_node.setShaderInput("mt_{0}_1".format(material), tex1t, state) self._initialized = True self._plane_quadtree.setFocalCamera(self._focal_camera) self._plane_quadtree.setFocalLens(self._focal_lens) self._plane_quadtree.init() if VERBOSE: t_init_end = time.time() t_init = t_init_end - t_init_begin print t_init * 1000.0, "ms to initialize" self.update()