def makeFilterBuffer(srcbuffer, name, sort, prog): blurBuffer=base.win.makeTextureBuffer(name, 512, 512) blurBuffer.setSort(sort) blurBuffer.setClearColor(Vec4(1,0,0,1)) blurCamera=base.makeCamera2d(blurBuffer) blurScene=NodePath("new Scene") blurCamera.node().setScene(blurScene) shader = Shader.load(prog) card = srcbuffer.getTextureCard() card.reparentTo(blurScene) card.setShader(shader) return blurBuffer
def makeFilterBuffer(srcbuffer, name, sort, prog): blurBuffer = base.win.makeTextureBuffer(name, 512, 512) blurBuffer.setSort(sort) blurBuffer.setClearColor(Vec4(1, 0, 0, 1)) blurCamera = base.makeCamera2d(blurBuffer) blurScene = NodePath("new Scene") blurCamera.node().setScene(blurScene) shader = Shader.load(prog) card = srcbuffer.getTextureCard() card.reparentTo(blurScene) card.setShader(shader) return blurBuffer
def __init__(self): base.disableMouse() base.setBackgroundColor(0, 0, 0) camera.setPos(0, -50, 0) # Check video card capabilities. if (base.win.getGsg().getSupportsBasicShaders() == 0): addTitle( "Glow Filter: Video driver reports that shaders are not supported." ) return # Post the instructions self.title = addTitle("Panda3D: Tutorial - Glow Filter") self.inst1 = addInstructions(0.95, "ESC: Quit") self.inst2 = addInstructions(0.90, "Space: Toggle Glow Filter On/Off") self.inst3 = addInstructions(0.85, "Enter: Toggle Running/Spinning") self.inst4 = addInstructions(0.80, "V: View the render-to-texture results") #create the shader that will determime what parts of the scene will glow glowShader=Shader.load(os.path.join(PANDA_SHADER_PATH, \ "samples/glow/glow_shader.sha")) # load our model self.tron = Actor() self.tron.loadModel("models/samples/glow/tron") self.tron.loadAnims({"running": "models/samples/glow/tron_anim"}) self.tron.reparentTo(render) self.interval = self.tron.hprInterval(60, Point3(360, 0, 0)) self.interval.loop() self.isRunning = False #put some lighting on the tron model dlight = DirectionalLight('dlight') alight = AmbientLight('alight') dlnp = render.attachNewNode(dlight) alnp = render.attachNewNode(alight) dlight.setColor(Vec4(1.0, 0.7, 0.2, 1)) alight.setColor(Vec4(0.2, 0.2, 0.2, 1)) dlnp.setHpr(0, -60, 0) render.setLight(dlnp) render.setLight(alnp) # create the glow buffer. This buffer renders like a normal scene, # except that only the glowing materials should show up nonblack. glowBuffer = base.win.makeTextureBuffer("Glow scene", 512, 512) glowBuffer.setSort(-3) glowBuffer.setClearColor(Vec4(0, 0, 0, 1)) # We have to attach a camera to the glow buffer. The glow camera # must have the same frustum as the main camera. As long as the aspect # ratios match, the rest will take care of itself. glowCamera = base.makeCamera(glowBuffer, lens=base.cam.node().getLens()) # Tell the glow camera to use the glow shader tempnode = NodePath(PandaNode("temp node")) tempnode.setShader(glowShader) glowCamera.node().setInitialState(tempnode.getState()) # set up the pipeline: from glow scene to blur x to blur y to main window. blurXBuffer=makeFilterBuffer(glowBuffer, "Blur X", -2, \ os.path.join(PANDA_SHADER_PATH, "samples/glow/glow_xblur.sha")) blurYBuffer=makeFilterBuffer(blurXBuffer, "Blur Y", -1, \ os.path.join(PANDA_SHADER_PATH, "samples/glow/glow_yblur.sha")) self.finalcard = blurYBuffer.getTextureCard() self.finalcard.reparentTo(render2d) self.finalcard.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd)) # Panda contains a built-in viewer that lets you view the results of # your render-to-texture operations. This code configures the viewer. self.accept("v", base.bufferViewer.toggleEnable) self.accept("V", base.bufferViewer.toggleEnable) base.bufferViewer.setPosition("llcorner") base.bufferViewer.setLayout("hline") base.bufferViewer.setCardSize(0.652, 0) # event handling self.accept("space", self.toggleGlow) self.accept("enter", self.toggleDisplay) self.accept("escape", sys.exit, [0]) self.glowOn = True
def __init__(self): base.disableMouse() camera.setPos(0, -50, 0) # Check video card capabilities. if (base.win.getGsg().getSupportsBasicShaders() == 0): addTitle( "Toon Shader: Video driver reports that shaders are not supported." ) return # Post the instructions. self.title = addTitle( "Panda3D: Tutorial - Toon Shading with Normals-Based Inking") self.inst1 = addInstructions(0.95, "ESC: Quit") self.inst2 = addInstructions( 0.90, "Up/Down: Increase/Decrease Line Thickness") self.inst3 = addInstructions( 0.85, "Left/Right: Decrease/Increase Line Darkness") self.inst4 = addInstructions(0.80, "V: View the render-to-texture results") # This shader's job is to render the model with discrete lighting # levels. The lighting calculations built into the shader assume # a single nonattenuating point light. tempnode = NodePath(PandaNode("temp node")) tempnode.setShader(Shader.load(os.path.join(PANDA_SHADER_PATH, \ "samples/cartoon/cartoon_lighting.sha"))) base.cam.node().setInitialState(tempnode.getState()) # This is the object that represents the single "light", as far # the shader is concerned. It's not a real Panda3D LightNode, but # the shader doesn't care about that. light = render.attachNewNode("light") light.setPos(30, -50, 0) # this call puts the light's nodepath into the render state. # this enables the shader to access this light by name. render.setShaderInput("light", light) # The "normals buffer" will contain a picture of the model colorized # so that the color of the model is a representation of the model's # normal at that point. normalsBuffer = base.win.makeTextureBuffer("normalsBuffer", 0, 0) normalsBuffer.setClearColor(Vec4(0.5, 0.5, 0.5, 1)) self.normalsBuffer = normalsBuffer normalsCamera = base.makeCamera(normalsBuffer, lens=base.cam.node().getLens()) normalsCamera.node().setScene(render) tempnode = NodePath(PandaNode("temp node")) tempnode.setShader(Shader.load(os.path.join(PANDA_SHADER_PATH, \ "samples/cartoon/cartoon_normal.sha"))) normalsCamera.node().setInitialState(tempnode.getState()) #what we actually do to put edges on screen is apply them as a texture to #a transparent screen-fitted card drawnScene = normalsBuffer.getTextureCard() drawnScene.setTransparency(1) drawnScene.setColor(1, 1, 1, 0) drawnScene.reparentTo(render2d) self.drawnScene = drawnScene # this shader accepts, as input, the picture from the normals buffer. # it compares each adjacent pixel, looking for discontinuities. # wherever a discontinuity exists, it emits black ink. self.separation = 0.001 self.cutoff = 0.3 inkGen=Shader.load(os.path.join(PANDA_SHADER_PATH, \ "samples/cartoon/cartoon_ink.sha")) drawnScene.setShader(inkGen) drawnScene.setShaderInput("separation", Vec4(self.separation, 0, self.separation, 0)) drawnScene.setShaderInput( "cutoff", Vec4(self.cutoff, self.cutoff, self.cutoff, self.cutoff)) # Panda contains a built-in viewer that lets you view the results of # your render-to-texture operations. This code configures the viewer. self.accept("v", base.bufferViewer.toggleEnable) self.accept("V", base.bufferViewer.toggleEnable) base.bufferViewer.setPosition("llcorner") # Load a dragon model and animate it. self.character = Actor() self.character.loadModel('models/samples/cartoon/nik_dragon') self.character.reparentTo(render) self.character.loadAnims({'win': 'models/samples/cartoon/nik_dragon'}) self.character.loop('win') self.character.hprInterval(15, Point3(360, 0, 0)).loop() # these allow you to change cartooning parameters in realtime self.accept("escape", sys.exit, [0]) self.accept("arrow_up", self.increaseSeparation) self.accept("arrow_down", self.decreaseSeparation) self.accept("arrow_left", self.increaseCutoff) self.accept("arrow_right", self.decreaseCutoff)
def __init__(self): # Preliminary capabilities check. if (base.win.getGsg().getSupportsBasicShaders()==0): self.t=addTitle("Firefly Demo: Video driver reports that shaders are not supported.") return if (base.win.getGsg().getSupportsDepthTexture()==0): self.t=addTitle("Firefly Demo: Video driver reports that depth textures are not supported.") return # This algorithm uses two offscreen buffers, one of which has # an auxiliary bitplane, and the offscreen buffers share a single # depth buffer. This is a heck of a complicated buffer setup. self.modelbuffer = self.makeFBO("model buffer",1) self.lightbuffer = self.makeFBO("light buffer",0) # Creation of a high-powered buffer can fail, if the graphics card # doesn't support the necessary OpenGL extensions. if (self.modelbuffer == None) or (self.lightbuffer == None): self.t=addTitle("Toon Shader: Video driver does not support multiple render targets") return # Create four render textures: depth, normal, albedo, and final. # attach them to the various bitplanes of the offscreen buffers. self.texDepth = Texture() self.texDepth.setFormat(Texture.FDepthStencil) self.texAlbedo = Texture() self.texNormal = Texture() self.texFinal = Texture() self.modelbuffer.addRenderTexture(self.texDepth, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPDepthStencil) self.modelbuffer.addRenderTexture(self.texAlbedo, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPColor) self.modelbuffer.addRenderTexture(self.texNormal, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPAuxRgba0) self.lightbuffer.addRenderTexture(self.texFinal, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPColor) # Set the near and far clipping planes. base.cam.node().getLens().setNear(50.0) base.cam.node().getLens().setFar(500.0) lens = base.cam.node().getLens() # This algorithm uses three cameras: one to render the models into the # model buffer, one to render the lights into the light buffer, and # one to render "plain" stuff (non-deferred shaded) stuff into the light # buffer. Each camera has a bitmask to identify it. self.modelMask = 1 self.lightMask = 2 self.plainMask = 4 self.modelcam=base.makeCamera(self.modelbuffer, lens=lens, scene=render, mask=self.modelMask) self.lightcam=base.makeCamera(self.lightbuffer, lens=lens, scene=render, mask=self.lightMask) self.plaincam=base.makeCamera(self.lightbuffer, lens=lens, scene=render, mask=self.plainMask) # Panda's main camera is not used. base.cam.node().setActive(0) # Take explicit control over the order in which the three # buffers are rendered. self.modelbuffer.setSort(1) self.lightbuffer.setSort(2) base.win.setSort(3) # Within the light buffer, control the order of the two cams. self.lightcam.node().getDisplayRegion(0).setSort(1) self.plaincam.node().getDisplayRegion(0).setSort(2) # By default, panda usually clears the screen before every # camera and before every window. Tell it not to do that. # Then, tell it specifically when to clear and what to clear. self.modelcam.node().getDisplayRegion(0).disableClears() self.lightcam.node().getDisplayRegion(0).disableClears() self.plaincam.node().getDisplayRegion(0).disableClears() base.cam.node().getDisplayRegion(0).disableClears() base.cam2d.node().getDisplayRegion(0).disableClears() self.modelbuffer.disableClears() base.win.disableClears() self.modelbuffer.setClearColorActive(1) self.modelbuffer.setClearDepthActive(1) self.lightbuffer.setClearColorActive(1) self.lightbuffer.setClearColor(Vec4(0,0,0,1)) # Miscellaneous stuff. base.disableMouse() base.camera.setPos(-9.112,-211.077,46.951) base.camera.setHpr(0, -7.5, 2.4) base.setBackgroundColor(Vec4(0,0,0,0)) random.seed() # Calculate the projection parameters for the final shader. # The math here is too complex to explain in an inline comment, # I've put in a full explanation into the HTML intro. proj = base.cam.node().getLens().getProjectionMat() proj_x = 0.5 * proj.getCell(3,2) / proj.getCell(0,0) proj_y = 0.5 * proj.getCell(3,2) proj_z = 0.5 * proj.getCell(3,2) / proj.getCell(2,1) proj_w = -0.5 - 0.5*proj.getCell(1,2) # Configure the render state of the model camera. tempnode = NodePath(PandaNode("temp node")) tempnode.setAttrib(AlphaTestAttrib.make(RenderAttrib.MGreaterEqual, 0.5)) tempnode.setShader(Shader.load(os.path.join(PANDA_SHADER_PATH, \ "samples/fireflies/fireflies_model.sha"))) tempnode.setAttrib(DepthTestAttrib.make(RenderAttrib.MLessEqual)) self.modelcam.node().setInitialState(tempnode.getState()) # Configure the render state of the light camera. tempnode = NodePath(PandaNode("temp node")) tempnode.setShader(Shader.load(os.path.join(PANDA_SHADER_PATH, \ "samples/fireflies/fireflies_lighting.sha"))) tempnode.setShaderInput("texnormal",self.texNormal) tempnode.setShaderInput("texalbedo",self.texAlbedo) tempnode.setShaderInput("texdepth",self.texDepth) tempnode.setShaderInput("proj",Vec4(proj_x,proj_y,proj_z,proj_w)) tempnode.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OOne, ColorBlendAttrib.OOne)) tempnode.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullCounterClockwise)) # The next line causes problems on Linux. #tempnode.setAttrib(DepthTestAttrib.make(RenderAttrib.MGreaterEqual)) tempnode.setAttrib(DepthWriteAttrib.make(DepthWriteAttrib.MOff)) self.lightcam.node().setInitialState(tempnode.getState()) # Configure the render state of the plain camera. rs = RenderState.makeEmpty() self.plaincam.node().setInitialState(rs) # Clear any render attribs on the root node. This is necessary # because by default, panda assigns some attribs to the root # node. These default attribs will override the # carefully-configured render attribs that we just attached # to the cameras. The simplest solution is to just clear # them all out. render.setState(RenderState.makeEmpty()) # My artist created a model in which some of the polygons # don't have textures. This confuses the shader I wrote. # This little hack guarantees that everything has a texture. white = loader.loadTexture("models/samples/fireflies/white.jpg") render.setTexture(white,0) # Create two subroots, to help speed cull traversal. self.lightroot = NodePath(PandaNode("lightroot")) self.lightroot.reparentTo(render) self.modelroot = NodePath(PandaNode("modelroot")) self.modelroot.reparentTo(render) self.lightroot.hide(BitMask32(self.modelMask)) self.modelroot.hide(BitMask32(self.lightMask)) self.modelroot.hide(BitMask32(self.plainMask)) # Load the model of a forest. Make it visible to the model camera. self.forest=NodePath(PandaNode("Forest Root")) self.forest.reparentTo(render) loader.loadModel( \ "models/samples/fireflies/background").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage01").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage02").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage03").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage04").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage05").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage06").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage07").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage08").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage09").reparentTo(self.forest) self.forest.hide(BitMask32(self.lightMask | self.plainMask)) # Cause the final results to be rendered into the main window on a card. cm = CardMaker("card") cm.setFrameFullscreenQuad() self.card = render2d.attachNewNode(cm.generate()) self.card.setTexture(self.texFinal) # Post the instructions. self.title = addTitle("Panda3D: Tutorial - Fireflies using Deferred Shading") self.inst1 = addInstructions(0.95,"ESC: Quit") self.inst2 = addInstructions(0.90,"Up/Down: More / Fewer Fireflies (Count: unknown)") self.inst3 = addInstructions(0.85,"Right/Left: Bigger / Smaller Fireflies (Radius: unknown)") self.inst4 = addInstructions(0.80,"V: View the render-to-texture results") # Panda contains a built-in viewer that lets you view the results of # your render-to-texture operations. This code configures the viewer. base.bufferViewer.setPosition("llcorner") base.bufferViewer.setCardSize(0,0.40) base.bufferViewer.setLayout("vline") self.toggleCards() self.toggleCards() # Firefly parameters self.fireflies = [] self.sequences = [] self.scaleseqs = [] self.glowspheres = [] self.fireflysize = 1.0 self.spheremodel = loader.loadModel("models/misc/sphere.flt") self.setFireflySize(25.0) while (len(self.fireflies)<5): self.addFirefly() self.updateReadout() # these allow you to change parameters in realtime self.accept("escape", sys.exit, [0]) self.accept("arrow_up", self.incFireflyCount, [1.1111111]) self.accept("arrow_down", self.decFireflyCount, [0.9000000]) self.accept("arrow_right", self.setFireflySize, [1.1111111]) self.accept("arrow_left", self.setFireflySize, [0.9000000]) self.accept("v", self.toggleCards) self.accept("V", self.toggleCards) self.nextadd = 0 taskMgr.add(self.spawnTask, "spawner")
def __init__(self): base.disableMouse() camera.setPos(0, -50, 0) # Check video card capabilities. if (base.win.getGsg().getSupportsBasicShaders() == 0): addTitle("Toon Shader: Video driver reports that shaders are not supported.") return # Post the instructions. self.title = addTitle("Panda3D: Tutorial - Toon Shading with Normals-Based Inking") self.inst1 = addInstructions(0.95,"ESC: Quit") self.inst2 = addInstructions(0.90,"Up/Down: Increase/Decrease Line Thickness") self.inst3 = addInstructions(0.85,"Left/Right: Decrease/Increase Line Darkness") self.inst4 = addInstructions(0.80,"V: View the render-to-texture results") # This shader's job is to render the model with discrete lighting # levels. The lighting calculations built into the shader assume # a single nonattenuating point light. tempnode = NodePath(PandaNode("temp node")) tempnode.setShader(Shader.load(os.path.join(PANDA_SHADER_PATH, \ "samples/cartoon/cartoon_lighting.sha"))) base.cam.node().setInitialState(tempnode.getState()) # This is the object that represents the single "light", as far # the shader is concerned. It's not a real Panda3D LightNode, but # the shader doesn't care about that. light = render.attachNewNode("light") light.setPos(30,-50,0) # this call puts the light's nodepath into the render state. # this enables the shader to access this light by name. render.setShaderInput("light", light) # The "normals buffer" will contain a picture of the model colorized # so that the color of the model is a representation of the model's # normal at that point. normalsBuffer=base.win.makeTextureBuffer("normalsBuffer", 0, 0) normalsBuffer.setClearColor(Vec4(0.5,0.5,0.5,1)) self.normalsBuffer=normalsBuffer normalsCamera=base.makeCamera(normalsBuffer, lens=base.cam.node().getLens()) normalsCamera.node().setScene(render) tempnode = NodePath(PandaNode("temp node")) tempnode.setShader(Shader.load(os.path.join(PANDA_SHADER_PATH, \ "samples/cartoon/cartoon_normal.sha"))) normalsCamera.node().setInitialState(tempnode.getState()) #what we actually do to put edges on screen is apply them as a texture to #a transparent screen-fitted card drawnScene=normalsBuffer.getTextureCard() drawnScene.setTransparency(1) drawnScene.setColor(1,1,1,0) drawnScene.reparentTo(render2d) self.drawnScene = drawnScene # this shader accepts, as input, the picture from the normals buffer. # it compares each adjacent pixel, looking for discontinuities. # wherever a discontinuity exists, it emits black ink. self.separation = 0.001 self.cutoff = 0.3 inkGen=Shader.load(os.path.join(PANDA_SHADER_PATH, \ "samples/cartoon/cartoon_ink.sha")) drawnScene.setShader(inkGen) drawnScene.setShaderInput("separation", Vec4(self.separation,0,self.separation,0)); drawnScene.setShaderInput("cutoff", Vec4(self.cutoff,self.cutoff,self.cutoff,self.cutoff)); # Panda contains a built-in viewer that lets you view the results of # your render-to-texture operations. This code configures the viewer. self.accept("v", base.bufferViewer.toggleEnable) self.accept("V", base.bufferViewer.toggleEnable) base.bufferViewer.setPosition("llcorner") # Load a dragon model and animate it. self.character=Actor() self.character.loadModel('models/samples/cartoon/nik_dragon') self.character.reparentTo(render) self.character.loadAnims({'win': 'models/samples/cartoon/nik_dragon'}) self.character.loop('win') self.character.hprInterval(15, Point3(360, 0,0)).loop() # these allow you to change cartooning parameters in realtime self.accept("escape", sys.exit, [0]) self.accept("arrow_up", self.increaseSeparation) self.accept("arrow_down", self.decreaseSeparation) self.accept("arrow_left", self.increaseCutoff) self.accept("arrow_right", self.decreaseCutoff)
def reconfigure(self, fullrebuild, changed): """ Reconfigure is called whenever any configuration change is made. """ configuration = self.configuration if (fullrebuild): self.cleanup() if (len(configuration) == 0): return auxbits = 0 needtex = {} needtex["color"] = True if (configuration.has_key("CartoonInk")): needtex["aux"] = True auxbits |= AuxBitplaneAttrib.ABOAuxNormal if (configuration.has_key("Bloom")): needtex["bloom0"] = True needtex["bloom1"] = True needtex["bloom2"] = True needtex["bloom3"] = True auxbits |= AuxBitplaneAttrib.ABOGlow if (configuration.has_key("ViewGlow")): auxbits |= AuxBitplaneAttrib.ABOGlow for tex in needtex: self.textures[tex] = Texture("scene-" + tex) self.textures[tex].setWrapU(Texture.WMClamp) self.textures[tex].setWrapV(Texture.WMClamp) needtexpix = True self.finalQuad = self.manager.renderSceneInto( textures=self.textures, auxbits=auxbits) if (self.finalQuad == None): self.cleanup() return False if (configuration.has_key("Bloom")): bloomconf = configuration["Bloom"] bloom0 = self.textures["bloom0"] bloom1 = self.textures["bloom1"] bloom2 = self.textures["bloom2"] bloom3 = self.textures["bloom3"] if (bloomconf.size == "large"): scale = 8 downsampler = "filter_down4.sha" elif (bloomconf.size == "medium"): scale = 4 downsampler = "filter_copy.sha" else: scale = 2 downsampler = "filter_copy.sha" self.bloom.append( self.manager.renderQuadInto(colortex=bloom0, div=2, align=scale)) self.bloom.append( self.manager.renderQuadInto(colortex=bloom1, div=scale, align=scale)) self.bloom.append( self.manager.renderQuadInto(colortex=bloom2, div=scale, align=scale)) self.bloom.append( self.manager.renderQuadInto(colortex=bloom3, div=scale, align=scale)) self.bloom[0].setShaderInput("src", self.textures["color"]) self.bloom[0].setShader(self.loadShader("filter_bloomi.sha")) self.bloom[1].setShaderInput("src", bloom0) self.bloom[1].setShader(self.loadShader(downsampler)) self.bloom[2].setShaderInput("src", bloom1) self.bloom[2].setShader(self.loadShader("filter_bloomx.sha")) self.bloom[3].setShaderInput("src", bloom2) self.bloom[3].setShader(self.loadShader("filter_bloomy.sha")) text = "//Cg\n" text += "void vshader(float4 vtx_position : POSITION,\n" text += " out float4 l_position : POSITION,\n" text += " uniform float4 texpad_txcolor,\n" text += " uniform float4 texpix_txcolor,\n" text += " out float4 l_texcoordC : TEXCOORD0,\n" if (configuration.has_key("CartoonInk")): text += " uniform float4 texpad_txaux,\n" text += " uniform float4 texpix_txaux,\n" text += " out float4 l_texcoordN : TEXCOORD1,\n" if (configuration.has_key("Bloom")): text += " uniform float4 texpad_txbloom3,\n" text += " out float4 l_texcoordB : TEXCOORD2,\n" text += " uniform float4x4 mat_modelproj)\n" text += "{\n" text += " l_position=mul(mat_modelproj, vtx_position);\n" text += " l_texcoordC=(vtx_position.xzxz * texpad_txcolor) + texpad_txcolor;\n" if (configuration.has_key("CartoonInk")): text += " l_texcoordN=(vtx_position.xzxz * texpad_txaux) + texpad_txaux;\n" if (configuration.has_key("Bloom")): text += " l_texcoordB=(vtx_position.xzxz * texpad_txbloom3) + texpad_txbloom3;\n" if (configuration.has_key("HalfPixelShift")): text += " l_texcoordC+=texpix_txcolor*0.5;\n" if (configuration.has_key("CartoonInk")): text += " l_texcoordN+=texpix_txaux*0.5;\n" text += "}\n" text += "void fshader(\n" text += "float4 l_texcoordC : TEXCOORD0,\n" text += "uniform float4 texpix_txcolor,\n" if (configuration.has_key("CartoonInk")): text += "float4 l_texcoordN : TEXCOORD1,\n" text += "uniform float4 texpix_txaux,\n" if (configuration.has_key("Bloom")): text += "float4 l_texcoordB : TEXCOORD2,\n" for key in self.textures: text += "uniform sampler2D k_tx" + key + ",\n" if (configuration.has_key("CartoonInk")): text += "uniform float4 k_cartoonseparation,\n" if (configuration.has_key("VolumetricLighting")): text += "uniform float4 k_casterpos,\n" text += "uniform float4 k_vlparams,\n" text += "out float4 o_color : COLOR)\n" text += "{\n" text += " o_color = tex2D(k_txcolor, l_texcoordC.xy);\n" if (configuration.has_key("CartoonInk")): text += CARTOON_BODY if (configuration.has_key("Bloom")): text += "o_color = saturate(o_color);\n" text += "float4 bloom = 0.5*tex2D(k_txbloom3, l_texcoordB.xy);\n" text += "o_color = 1-((1-bloom)*(1-o_color));\n" if (configuration.has_key("ViewGlow")): text += "o_color.r = o_color.a;\n" if (configuration.has_key("VolumetricLighting")): text += "float decay = 1.0f;\n" text += "float2 curcoord = l_texcoordC.xy;\n" text += "float2 lightdir = curcoord - k_casterpos.xy;\n" text += "lightdir *= k_vlparams.y;\n" text += "half4 sample = tex2D(k_txcolor, curcoord);\n" text += "float3 vlcolor = sample.rgb * sample.a;\n" text += "for (int i = 0; i < k_vlparams.x; i++) {\n" text += " curcoord -= lightdir;\n" text += " sample = tex2D(k_txcolor, curcoord);\n" text += " sample *= sample.a * decay;//*weight\n" text += " vlcolor += sample.rgb;\n" text += " decay *= k_vlparams.z;\n" text += "}\n" text += "o_color += float4(vlcolor * k_vlparams.w, 1);\n" if (configuration.has_key("Inverted")): text += "o_color = float4(1, 1, 1, 1) - o_color;\n" text += "}\n" self.finalQuad.setShader(Shader.make(text)) for tex in self.textures: self.finalQuad.setShaderInput("tx" + tex, self.textures[tex]) if (changed == "CartoonInk") or fullrebuild: if (configuration.has_key("CartoonInk")): separation = configuration["CartoonInk"] self.finalQuad.setShaderInput( "cartoonseparation", Vec4(separation, 0, separation, 0)) if (changed == "Bloom") or fullrebuild: if (configuration.has_key("Bloom")): bloomconf = configuration["Bloom"] intensity = bloomconf.intensity * 3.0 self.bloom[0].setShaderInput("blend", bloomconf.blendx, bloomconf.blendy, bloomconf.blendz, bloomconf.blendw * 2.0) self.bloom[0].setShaderInput( "trigger", bloomconf.mintrigger, 1.0 / (bloomconf.maxtrigger - bloomconf.mintrigger), 0.0, 0.0) self.bloom[0].setShaderInput("desat", bloomconf.desat) self.bloom[3].setShaderInput("intensity", intensity, intensity, intensity, intensity) if (changed == "VolumetricLighting") or fullrebuild: if (configuration.has_key("VolumetricLighting")): config = configuration["VolumetricLighting"] tcparam = config.density / float(config.numsamples) self.finalQuad.setShaderInput("vlparams", config.numsamples, tcparam, config.decay, config.exposure) self.update() return True
def loadShader(self, name): fn = os.path.join(PANDA_SHADER_PATH, name) fn = Filename.fromOsSpecific(fn) fn.makeTrueCase() return Shader.load(fn)
def __init__(self): base.disableMouse() base.setBackgroundColor(0,0,0) camera.setPos(0,-50,0) # Check video card capabilities. if (base.win.getGsg().getSupportsBasicShaders() == 0): addTitle("Glow Filter: Video driver reports that shaders are not supported.") return # Post the instructions self.title = addTitle("Panda3D: Tutorial - Glow Filter") self.inst1 = addInstructions(0.95,"ESC: Quit") self.inst2 = addInstructions(0.90,"Space: Toggle Glow Filter On/Off") self.inst3 = addInstructions(0.85,"Enter: Toggle Running/Spinning") self.inst4 = addInstructions(0.80,"V: View the render-to-texture results") #create the shader that will determime what parts of the scene will glow glowShader=Shader.load(os.path.join(PANDA_SHADER_PATH, \ "samples/glow/glow_shader.sha")) # load our model self.tron=Actor() self.tron.loadModel("models/samples/glow/tron") self.tron.loadAnims({"running":"models/samples/glow/tron_anim"}) self.tron.reparentTo(render) self.interval = self.tron.hprInterval(60,Point3(360,0,0)) self.interval.loop() self.isRunning=False #put some lighting on the tron model dlight = DirectionalLight('dlight') alight = AmbientLight('alight') dlnp = render.attachNewNode(dlight) alnp = render.attachNewNode(alight) dlight.setColor(Vec4(1.0, 0.7, 0.2, 1)) alight.setColor(Vec4(0.2, 0.2, 0.2, 1)) dlnp.setHpr(0, -60, 0) render.setLight(dlnp) render.setLight(alnp) # create the glow buffer. This buffer renders like a normal scene, # except that only the glowing materials should show up nonblack. glowBuffer=base.win.makeTextureBuffer("Glow scene", 512, 512) glowBuffer.setSort(-3) glowBuffer.setClearColor(Vec4(0,0,0,1)) # We have to attach a camera to the glow buffer. The glow camera # must have the same frustum as the main camera. As long as the aspect # ratios match, the rest will take care of itself. glowCamera=base.makeCamera(glowBuffer, lens=base.cam.node().getLens()) # Tell the glow camera to use the glow shader tempnode = NodePath(PandaNode("temp node")) tempnode.setShader(glowShader) glowCamera.node().setInitialState(tempnode.getState()) # set up the pipeline: from glow scene to blur x to blur y to main window. blurXBuffer=makeFilterBuffer(glowBuffer, "Blur X", -2, \ os.path.join(PANDA_SHADER_PATH, "samples/glow/glow_xblur.sha")) blurYBuffer=makeFilterBuffer(blurXBuffer, "Blur Y", -1, \ os.path.join(PANDA_SHADER_PATH, "samples/glow/glow_yblur.sha")) self.finalcard = blurYBuffer.getTextureCard() self.finalcard.reparentTo(render2d) self.finalcard.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd)) # Panda contains a built-in viewer that lets you view the results of # your render-to-texture operations. This code configures the viewer. self.accept("v", base.bufferViewer.toggleEnable) self.accept("V", base.bufferViewer.toggleEnable) base.bufferViewer.setPosition("llcorner") base.bufferViewer.setLayout("hline") base.bufferViewer.setCardSize(0.652,0) # event handling self.accept("space", self.toggleGlow) self.accept("enter", self.toggleDisplay) self.accept("escape", sys.exit, [0]) self.glowOn=True;
def __init__(self): # Preliminary capabilities check. if (base.win.getGsg().getSupportsBasicShaders() == 0): self.t = addTitle( "Firefly Demo: Video driver reports that shaders are not supported." ) return if (base.win.getGsg().getSupportsDepthTexture() == 0): self.t = addTitle( "Firefly Demo: Video driver reports that depth textures are not supported." ) return # This algorithm uses two offscreen buffers, one of which has # an auxiliary bitplane, and the offscreen buffers share a single # depth buffer. This is a heck of a complicated buffer setup. self.modelbuffer = self.makeFBO("model buffer", 1) self.lightbuffer = self.makeFBO("light buffer", 0) # Creation of a high-powered buffer can fail, if the graphics card # doesn't support the necessary OpenGL extensions. if (self.modelbuffer == None) or (self.lightbuffer == None): self.t = addTitle( "Toon Shader: Video driver does not support multiple render targets" ) return # Create four render textures: depth, normal, albedo, and final. # attach them to the various bitplanes of the offscreen buffers. self.texDepth = Texture() self.texDepth.setFormat(Texture.FDepthStencil) self.texAlbedo = Texture() self.texNormal = Texture() self.texFinal = Texture() self.modelbuffer.addRenderTexture(self.texDepth, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPDepthStencil) self.modelbuffer.addRenderTexture(self.texAlbedo, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPColor) self.modelbuffer.addRenderTexture(self.texNormal, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPAuxRgba0) self.lightbuffer.addRenderTexture(self.texFinal, GraphicsOutput.RTMBindOrCopy, GraphicsOutput.RTPColor) # Set the near and far clipping planes. base.cam.node().getLens().setNear(50.0) base.cam.node().getLens().setFar(500.0) lens = base.cam.node().getLens() # This algorithm uses three cameras: one to render the models into the # model buffer, one to render the lights into the light buffer, and # one to render "plain" stuff (non-deferred shaded) stuff into the light # buffer. Each camera has a bitmask to identify it. self.modelMask = 1 self.lightMask = 2 self.plainMask = 4 self.modelcam = base.makeCamera(self.modelbuffer, lens=lens, scene=render, mask=self.modelMask) self.lightcam = base.makeCamera(self.lightbuffer, lens=lens, scene=render, mask=self.lightMask) self.plaincam = base.makeCamera(self.lightbuffer, lens=lens, scene=render, mask=self.plainMask) # Panda's main camera is not used. base.cam.node().setActive(0) # Take explicit control over the order in which the three # buffers are rendered. self.modelbuffer.setSort(1) self.lightbuffer.setSort(2) base.win.setSort(3) # Within the light buffer, control the order of the two cams. self.lightcam.node().getDisplayRegion(0).setSort(1) self.plaincam.node().getDisplayRegion(0).setSort(2) # By default, panda usually clears the screen before every # camera and before every window. Tell it not to do that. # Then, tell it specifically when to clear and what to clear. self.modelcam.node().getDisplayRegion(0).disableClears() self.lightcam.node().getDisplayRegion(0).disableClears() self.plaincam.node().getDisplayRegion(0).disableClears() base.cam.node().getDisplayRegion(0).disableClears() base.cam2d.node().getDisplayRegion(0).disableClears() self.modelbuffer.disableClears() base.win.disableClears() self.modelbuffer.setClearColorActive(1) self.modelbuffer.setClearDepthActive(1) self.lightbuffer.setClearColorActive(1) self.lightbuffer.setClearColor(Vec4(0, 0, 0, 1)) # Miscellaneous stuff. base.disableMouse() base.camera.setPos(-9.112, -211.077, 46.951) base.camera.setHpr(0, -7.5, 2.4) base.setBackgroundColor(Vec4(0, 0, 0, 0)) random.seed() # Calculate the projection parameters for the final shader. # The math here is too complex to explain in an inline comment, # I've put in a full explanation into the HTML intro. proj = base.cam.node().getLens().getProjectionMat() proj_x = 0.5 * proj.getCell(3, 2) / proj.getCell(0, 0) proj_y = 0.5 * proj.getCell(3, 2) proj_z = 0.5 * proj.getCell(3, 2) / proj.getCell(2, 1) proj_w = -0.5 - 0.5 * proj.getCell(1, 2) # Configure the render state of the model camera. tempnode = NodePath(PandaNode("temp node")) tempnode.setAttrib( AlphaTestAttrib.make(RenderAttrib.MGreaterEqual, 0.5)) tempnode.setShader(Shader.load(os.path.join(PANDA_SHADER_PATH, \ "samples/fireflies/fireflies_model.sha"))) tempnode.setAttrib(DepthTestAttrib.make(RenderAttrib.MLessEqual)) self.modelcam.node().setInitialState(tempnode.getState()) # Configure the render state of the light camera. tempnode = NodePath(PandaNode("temp node")) tempnode.setShader(Shader.load(os.path.join(PANDA_SHADER_PATH, \ "samples/fireflies/fireflies_lighting.sha"))) tempnode.setShaderInput("texnormal", self.texNormal) tempnode.setShaderInput("texalbedo", self.texAlbedo) tempnode.setShaderInput("texdepth", self.texDepth) tempnode.setShaderInput("proj", Vec4(proj_x, proj_y, proj_z, proj_w)) tempnode.setAttrib( ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OOne, ColorBlendAttrib.OOne)) tempnode.setAttrib( CullFaceAttrib.make(CullFaceAttrib.MCullCounterClockwise)) # The next line causes problems on Linux. #tempnode.setAttrib(DepthTestAttrib.make(RenderAttrib.MGreaterEqual)) tempnode.setAttrib(DepthWriteAttrib.make(DepthWriteAttrib.MOff)) self.lightcam.node().setInitialState(tempnode.getState()) # Configure the render state of the plain camera. rs = RenderState.makeEmpty() self.plaincam.node().setInitialState(rs) # Clear any render attribs on the root node. This is necessary # because by default, panda assigns some attribs to the root # node. These default attribs will override the # carefully-configured render attribs that we just attached # to the cameras. The simplest solution is to just clear # them all out. render.setState(RenderState.makeEmpty()) # My artist created a model in which some of the polygons # don't have textures. This confuses the shader I wrote. # This little hack guarantees that everything has a texture. white = loader.loadTexture("models/samples/fireflies/white.jpg") render.setTexture(white, 0) # Create two subroots, to help speed cull traversal. self.lightroot = NodePath(PandaNode("lightroot")) self.lightroot.reparentTo(render) self.modelroot = NodePath(PandaNode("modelroot")) self.modelroot.reparentTo(render) self.lightroot.hide(BitMask32(self.modelMask)) self.modelroot.hide(BitMask32(self.lightMask)) self.modelroot.hide(BitMask32(self.plainMask)) # Load the model of a forest. Make it visible to the model camera. self.forest = NodePath(PandaNode("Forest Root")) self.forest.reparentTo(render) loader.loadModel( \ "models/samples/fireflies/background").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage01").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage02").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage03").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage04").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage05").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage06").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage07").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage08").reparentTo(self.forest) loader.loadModel( \ "models/samples/fireflies/foliage09").reparentTo(self.forest) self.forest.hide(BitMask32(self.lightMask | self.plainMask)) # Cause the final results to be rendered into the main window on a card. cm = CardMaker("card") cm.setFrameFullscreenQuad() self.card = render2d.attachNewNode(cm.generate()) self.card.setTexture(self.texFinal) # Post the instructions. self.title = addTitle( "Panda3D: Tutorial - Fireflies using Deferred Shading") self.inst1 = addInstructions(0.95, "ESC: Quit") self.inst2 = addInstructions( 0.90, "Up/Down: More / Fewer Fireflies (Count: unknown)") self.inst3 = addInstructions( 0.85, "Right/Left: Bigger / Smaller Fireflies (Radius: unknown)") self.inst4 = addInstructions(0.80, "V: View the render-to-texture results") # Panda contains a built-in viewer that lets you view the results of # your render-to-texture operations. This code configures the viewer. base.bufferViewer.setPosition("llcorner") base.bufferViewer.setCardSize(0, 0.40) base.bufferViewer.setLayout("vline") self.toggleCards() self.toggleCards() # Firefly parameters self.fireflies = [] self.sequences = [] self.scaleseqs = [] self.glowspheres = [] self.fireflysize = 1.0 self.spheremodel = loader.loadModel("models/misc/sphere.flt") self.setFireflySize(25.0) while (len(self.fireflies) < 5): self.addFirefly() self.updateReadout() # these allow you to change parameters in realtime self.accept("escape", sys.exit, [0]) self.accept("arrow_up", self.incFireflyCount, [1.1111111]) self.accept("arrow_down", self.decFireflyCount, [0.9000000]) self.accept("arrow_right", self.setFireflySize, [1.1111111]) self.accept("arrow_left", self.setFireflySize, [0.9000000]) self.accept("v", self.toggleCards) self.accept("V", self.toggleCards) self.nextadd = 0 taskMgr.add(self.spawnTask, "spawner")
def reconfigure(self, fullrebuild, changed): """ Reconfigure is called whenever any configuration change is made. """ configuration = self.configuration if (fullrebuild): self.cleanup() if (len(configuration) == 0): return auxbits = 0 needtex = {} needtex["color"] = True if (configuration.has_key("CartoonInk")): needtex["aux"] = True auxbits |= AuxBitplaneAttrib.ABOAuxNormal if (configuration.has_key("Bloom")): needtex["bloom0"] = True needtex["bloom1"] = True needtex["bloom2"] = True needtex["bloom3"] = True auxbits |= AuxBitplaneAttrib.ABOGlow if (configuration.has_key("ViewGlow")): auxbits |= AuxBitplaneAttrib.ABOGlow for tex in needtex: self.textures[tex] = Texture("scene-"+tex) self.textures[tex].setWrapU(Texture.WMClamp) self.textures[tex].setWrapV(Texture.WMClamp) needtexpix = True self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits) if (self.finalQuad == None): self.cleanup() return False if (configuration.has_key("Bloom")): bloomconf = configuration["Bloom"] bloom0=self.textures["bloom0"] bloom1=self.textures["bloom1"] bloom2=self.textures["bloom2"] bloom3=self.textures["bloom3"] if (bloomconf.size == "large"): scale=8 downsampler="filter_down4.sha" elif (bloomconf.size == "medium"): scale=4 downsampler="filter_copy.sha" else: scale=2 downsampler="filter_copy.sha" self.bloom.append(self.manager.renderQuadInto(colortex=bloom0, div=2, align=scale)) self.bloom.append(self.manager.renderQuadInto(colortex=bloom1, div=scale, align=scale)) self.bloom.append(self.manager.renderQuadInto(colortex=bloom2, div=scale, align=scale)) self.bloom.append(self.manager.renderQuadInto(colortex=bloom3, div=scale, align=scale)) self.bloom[0].setShaderInput("src", self.textures["color"]) self.bloom[0].setShader(self.loadShader("filter_bloomi.sha")) self.bloom[1].setShaderInput("src", bloom0) self.bloom[1].setShader(self.loadShader(downsampler)) self.bloom[2].setShaderInput("src", bloom1) self.bloom[2].setShader(self.loadShader("filter_bloomx.sha")) self.bloom[3].setShaderInput("src", bloom2) self.bloom[3].setShader(self.loadShader("filter_bloomy.sha")) text = "//Cg\n" text += "void vshader(float4 vtx_position : POSITION,\n" text += " out float4 l_position : POSITION,\n" text += " uniform float4 texpad_txcolor,\n" text += " uniform float4 texpix_txcolor,\n" text += " out float4 l_texcoordC : TEXCOORD0,\n" if (configuration.has_key("CartoonInk")): text += " uniform float4 texpad_txaux,\n" text += " uniform float4 texpix_txaux,\n" text += " out float4 l_texcoordN : TEXCOORD1,\n" if (configuration.has_key("Bloom")): text += " uniform float4 texpad_txbloom3,\n" text += " out float4 l_texcoordB : TEXCOORD2,\n" text += " uniform float4x4 mat_modelproj)\n" text += "{\n" text += " l_position=mul(mat_modelproj, vtx_position);\n" text += " l_texcoordC=(vtx_position.xzxz * texpad_txcolor) + texpad_txcolor;\n" if (configuration.has_key("CartoonInk")): text += " l_texcoordN=(vtx_position.xzxz * texpad_txaux) + texpad_txaux;\n" if (configuration.has_key("Bloom")): text += " l_texcoordB=(vtx_position.xzxz * texpad_txbloom3) + texpad_txbloom3;\n" if (configuration.has_key("HalfPixelShift")): text += " l_texcoordC+=texpix_txcolor*0.5;\n" if (configuration.has_key("CartoonInk")): text += " l_texcoordN+=texpix_txaux*0.5;\n" text += "}\n" text += "void fshader(\n" text += "float4 l_texcoordC : TEXCOORD0,\n" text += "uniform float4 texpix_txcolor,\n" if (configuration.has_key("CartoonInk")): text += "float4 l_texcoordN : TEXCOORD1,\n" text += "uniform float4 texpix_txaux,\n" if (configuration.has_key("Bloom")): text += "float4 l_texcoordB : TEXCOORD2,\n" for key in self.textures: text += "uniform sampler2D k_tx" + key + ",\n" if (configuration.has_key("CartoonInk")): text += "uniform float4 k_cartoonseparation,\n" if (configuration.has_key("VolumetricLighting")): text += "uniform float4 k_casterpos,\n" text += "uniform float4 k_vlparams,\n" text += "out float4 o_color : COLOR)\n" text += "{\n" text += " o_color = tex2D(k_txcolor, l_texcoordC.xy);\n" if (configuration.has_key("CartoonInk")): text += CARTOON_BODY if (configuration.has_key("Bloom")): text += "o_color = saturate(o_color);\n"; text += "float4 bloom = 0.5*tex2D(k_txbloom3, l_texcoordB.xy);\n" text += "o_color = 1-((1-bloom)*(1-o_color));\n" if (configuration.has_key("ViewGlow")): text += "o_color.r = o_color.a;\n" if (configuration.has_key("VolumetricLighting")): text += "float decay = 1.0f;\n" text += "float2 curcoord = l_texcoordC.xy;\n" text += "float2 lightdir = curcoord - k_casterpos.xy;\n" text += "lightdir *= k_vlparams.y;\n" text += "half4 sample = tex2D(k_txcolor, curcoord);\n" text += "float3 vlcolor = sample.rgb * sample.a;\n" text += "for (int i = 0; i < k_vlparams.x; i++) {\n" text += " curcoord -= lightdir;\n" text += " sample = tex2D(k_txcolor, curcoord);\n" text += " sample *= sample.a * decay;//*weight\n" text += " vlcolor += sample.rgb;\n" text += " decay *= k_vlparams.z;\n" text += "}\n" text += "o_color += float4(vlcolor * k_vlparams.w, 1);\n" if (configuration.has_key("Inverted")): text += "o_color = float4(1, 1, 1, 1) - o_color;\n" text += "}\n" self.finalQuad.setShader(Shader.make(text)) for tex in self.textures: self.finalQuad.setShaderInput("tx"+tex, self.textures[tex]) if (changed == "CartoonInk") or fullrebuild: if (configuration.has_key("CartoonInk")): separation = configuration["CartoonInk"] self.finalQuad.setShaderInput("cartoonseparation", Vec4(separation,0,separation,0)) if (changed == "Bloom") or fullrebuild: if (configuration.has_key("Bloom")): bloomconf = configuration["Bloom"] intensity = bloomconf.intensity * 3.0 self.bloom[0].setShaderInput("blend", bloomconf.blendx, bloomconf.blendy, bloomconf.blendz, bloomconf.blendw * 2.0) self.bloom[0].setShaderInput("trigger", bloomconf.mintrigger, 1.0/(bloomconf.maxtrigger-bloomconf.mintrigger), 0.0, 0.0) self.bloom[0].setShaderInput("desat", bloomconf.desat) self.bloom[3].setShaderInput("intensity", intensity, intensity, intensity, intensity) if (changed == "VolumetricLighting") or fullrebuild: if (configuration.has_key("VolumetricLighting")): config = configuration["VolumetricLighting"] tcparam = config.density / float(config.numsamples) self.finalQuad.setShaderInput("vlparams", config.numsamples, tcparam, config.decay, config.exposure) self.update() return True