Terrain Demo (update 1.12.12)


This is a small demo showing a character moving over uneven terrain. The terrain has 7 diffuse textures and 7 normal maps(more could be added, video memory is the only limit), there are soft shadows for the character (there would be also for some props… if I’d only put the props in the map), there’s a sort of fog and a sort of sky.

Apart from one tiny shader it all runs on the default shader generator.

The demo ships with a config.cfg file - all options valid for a prc config file should work. There are some custom settings be sure to change them if you’re getting poor framerate!

use-normal-mapping 1
Setting it to 0 will disable the normal mapping for terrain (will give a big boost)
soft-shadws 1
Setting it to 0 will disable the blur step for shadows (can give a bit of a boost)
use-shadows 1
Setting it to 0 will disable shadows (can give a nice boost)
shadow-map-size 512
The size of the shadow map, not much visual gain for bigger maps, not much speed gain from lower values (should be power-o-two)
terrain-texture-size 2048
The size of the terrain texture. Bigger values will NOT improve the texture look, smaller will give a performance boost at the cost of texture quality.

If You run the demo please tell me if it runs in the acceptable framerate on your hardware.

NEW Download link:

sendspace.com/file/cb18dr
t_demo3.rar (7.14MB)

Controls:
WSAD -to move
Mouse3 (right click) - start/stop camera rotation (based on pointer movement)

1 Like

Runs with 2-3 FPS on my laptop (dual core 2,2 GhZ, Intel onboard gfx). But it looks pretty cool. Especially the shadow looks great.

I was perhaps asking a bit much of my computer, but I gave it a shot anyway (a previous version of your terrain demo ran, but ran slowly); this new version is effectively non-functional on my computer.

To be specific, I got as far as the character standing against a blue sky (with no terrain yet evident) and a displayed frame-rate of 0.0 before I gave up.

My computer:
Gigabyte Q2005 (A netbook)
CPU: Intel Atom N550
Graphics: Intel GMA 3150 (This seems likely to me to be the main problem.)
Memory: 2GB
OS: Ubuntu 11.10

The shadows are made with Sothhs technique:
[Shader-less Shadows)
I take no credit for that (the only improvement I’ve made is to give it more blur and set a higher fov for the projection camera).

The default sizes for the buffers are kind of big 2x 2048x2048 for the terrain textures and a 1024x1024 for the shadows… the shadows go through common filters blur/sharpen, the diffuse texture through my tiny replace-alpha shader (this time via FilterManager) …I see no way this could work on a Intel GMA, maybe with the recent 3000HD.

Looks like I really need to write some fallback code.

Roaming Ralphette?

Looks really good - runs at 45-55 fps on my computer.

Windows 7 64
Q6600
4GB RAM
8800GT 512MB

Well I’ve named her Kasia, but Ralphette would be a good name since I tend to use her as a default placeholder actor -just as I did with the Ralph model.

I have A dual core AMD running Vista w/ ATI 3200 HD onboard video chip ( HP notebook ). A few polys of terrain visible but mostly not, Kasia though IS CUTE as heck and is the first Panda demo character to have a “fidgeting” standby animation rather than just standing stock still when not moving. COOL! Real game chars like in Runes do this. Also terrain goes away completely after moving around a bit and framerate skyrockets, indicates to me some sort of complete shader dropout. Wish I could see what sorta technique you are using but I’d have to set up pathe so I can open up the P3D with command line tools to see whats inside.

I don’t think you can get much from hacking my p3d file :smiley: some .pyc, some .bam, textures and a strange shader that only changes a alpha of a texture.

Code from a proof-o-concept version is here: www.sendspace.com/file/6lo1a5

I’ll make a version where you can disable soft shadows (skipping the BlureSharpen filter), just use ‘drop shadows’ (a splash of black under the PC) -that will cut the need for one extra camera and rendering the scene into one less buffer and finaly one less texture to project. I’ll also add a option to disable normal mapping for the terrain -that will free some video memory and cut one camera-buffer-projector trio.

Then with normal mapping or shadows disabled I could skip my mix-alpha-fog-texture-shader and just project a white texture with a transparent mask, since there will be a free TextureStage for that. That could work with a fix pipline.

Sorry for double post, but it’s kind of important for me that You people don’t mis this update :wink:

So, a bit of an update:
sendspace.com/file/cb18dr

For all the people that had sad-bad framerate:
Try this config setup:

win-size 800 600
fullscreen 0
load-display pandagl
basic-shaders-only 1
show-frame-rate-meter  1
sync-video 0
use-normal-mapping 0
soft-shadws 0
use-shadows 0
shadow-map-size 512
terrain-texture-size 1024
threading-model Cull/Draw 

This gives me 110-130fps, while with the default settings I get 20-45fps.

Feedback is priceless :smiley:

Ah, that is an improvement! On my computer (specs above, I believe), I seem to get a frame-rate hovering around 11 to 12 frames per second - slow, but playable.

By the way, I found that when looking down from a high angle, and especially, I think, when zoomed out, your sky effect seems to develop a sharp dividing line between the white and blue sections.

What versions of Makehuman and Blender did you use, I can’t get MH Alpha7 to export useable .mhx to Blender 2.65 for anything. My whole character creation has come to a total halt.

I didn’t use mhx or Blender. Exported the mesh from MH as a obj and rigged it the hard way.

Can export it as obj… but what did you use to rig it, probly somethin I aint got and can’t afford 2 buy

You can also try the collada exporter, it gives a rigged character. Anyway rigging in any software is much the same, you’ve got to add a weight to each and every vertex. I’ve yet to see a tool that is any help at all at rigging a character - for me it’s almost endless loop of setting a weight to a vert, moving a bone to see how it works then doing it again for the next vert.

…back on topic. The project know as ‘terrain demo’ is progressing nicely, a new version will be out in a week (or so), and them I’m off to the crowd-funding shack to turn it into a Real Game.
Sneak peek into the future:

Click the image for full size!

Is there any way that I can still get the code for this demo? All of the links now error out.

Thanks in advance!

Sorry, never did publish the source for this and now it seems I’ve lost most assets for this demo.

I do have a backup of the code, but I don’t think the ideas I had back then are actually any good, but well… here you go:

main.py

from panda3d.core import loadPrcFileData
from direct.showbase.AppRunnerGlobal import appRunner
if appRunner: 
    path=appRunner.p3dFilename.getDirname()+'/config.cfg'    
else:  #for testing  
    path='config.cfg'
try:    
    f = open(path, 'r')
    for line in f:
        if not line.startswith('#'):        
            loadPrcFileData('',line)
except IOError:
    print "No config file, using default" 
    
from panda3d.core import WindowProperties
from panda3d.core import ConfigVariableInt

cfg_win_size=ConfigVariableInt('win-size', '640 480')  
wp = WindowProperties.getDefault()         
wp.setSize(cfg_win_size.getWord(0),cfg_win_size.getWord(1))
wp.setTitle('wezu Terrain Demo v0.3') 
WindowProperties.setDefault(wp)

from panda3d.core import *
from direct.showbase.DirectObject import DirectObject
import direct.directbase.DirectStart
from direct.task import Task
from direct.actor.Actor import Actor
from CameraControll import CameraControll
from PlayerCharacter import PlayerCharacter
from PlayerControll import PlayerControll
from direct.filter.CommonFilters import CommonFilters
from direct.gui.OnscreenImage import OnscreenImage 
from direct.filter.FilterManager import FilterManager

class World(DirectObject):

    def __init__(self):
        render.setShaderAuto()
        base.setBackgroundColor(1, 1, 1) 
        base.camLens.setFar(35)       
        
        cfg_shadow_size=ConfigVariableInt('shadow-map-size', 1024)
        cfg_tex_size=ConfigVariableInt('terrain-texture-size', 2048)
        cfg_use_normal_map=ConfigVariableInt('use-normal-mapping', 1)    
        self.useNormal=cfg_use_normal_map #hack ;/
        cfg_soft_shadows=ConfigVariableInt('soft-shadws', 1)  
        cfg_use_shadows=ConfigVariableInt('use-shadows', 1)  
        self.useShadow=cfg_use_shadows #hack ;/
        
        maker = CardMaker( 'sky_card' )
        maker.setFrame( -15, 15, -10, 22 )
        self.sky = render.attachNewNode(maker.generate())
        sky_texture=loader.loadTexture('sky.png')
        sky_texture.setWrapV(Texture.WMClamp )
        self.sky.setTexture(TextureStage('ts2'), sky_texture )
        self.sky.setBin('background', 1) 
        self.sky.setDepthWrite(0)         
        self.sky.setBillboardPointWorld()
        self.sky.setLightOff()
        self.sky.hide(BitMask32.bit(1))
        
        self.player=PlayerCharacter("kasia_model", "kasia_run", "kasia_idle", 0.06)  
        PlayerControll(self.player, 50)  
        self.terrain=loader.loadModel("terrain1")
        #self.terrain=loader.loadModel("plane")
        self.terrain.reparentTo(render)        
        self.terrain.setTransparency(TransparencyAttrib.MAlpha )
        self.terrain.hide(BitMask32.bit(1))
        
        taskMgr.add(self.update, 'updateTask',sort=2)
        
        fbprops = FrameBufferProperties()
        fbprops.setColorBits(1)
        fbprops.setAlphaBits(0)
        fbprops.setDepthBits(0)
        fbprops.setStencilBits(0) 
        fbprops.setAccumBits(0)
        fbprops.setBackBuffers(0) 
        
        colorTexture=Texture()
        normalTexture=Texture()
        shadowTexture=Texture()
        
        
        altRender=NodePath("bufferRender")
        altRenderN=NodePath("bufferRenderN")
        #make the buffer
        mainWindow=base.win
        
        altBuffer=mainWindow.makeTextureBuffer("modulate_tex_buffer", cfg_tex_size, cfg_tex_size, colorTexture,False, fbprops)
        self.altCam=base.makeCamera(win=altBuffer)        
        self.altCam.reparentTo(altRender)          
        self.altCam.setPos(0,0,2)                
        self.altCam.setP(-90)                   
        self.lens = OrthographicLens()
        self.lens.setFilmSize(8, 8)  
        self.altCam.node().setLens(self.lens)        
        #self.altCam.node().showFrustum()        
        colorTexture.setWrapU(Texture.WMBorderColor  )
        colorTexture.setWrapV(Texture.WMBorderColor  )
        colorTexture.setBorderColor(Vec4(1,1,1,0))  
        
        #print cfg_use_normal_map
        
        if(cfg_use_normal_map.getValue ()==1):
            altBufferN=mainWindow.makeTextureBuffer("normal_tex_buffer", cfg_tex_size, cfg_tex_size,normalTexture, False, fbprops)
            self.altCamN=base.makeCamera(altBufferN)
            self.altCamN.reparentTo(altRenderN) 
            self.altCamN.setPos(0,0,2) 
            self.altCamN.setP(-90)     
            self.altCamN.node().setLens(self.lens)
            #altBuffer.getTexture().setAlphaFilename('mask4.png')
            normalTexture.setWrapU(Texture.WMBorderColor  )
            normalTexture.setWrapV(Texture.WMBorderColor  )
            normalTexture.setBorderColor(Vec4(.5, .5, 1, 1))  
        
        #view the buffer
        #base.bufferViewer.toggleEnable()
        #base.bufferViewer.setPosition("llcorner")
        #base.bufferViewer.setCardSize(.5, 0.0)  
        
        #texture
        self.grass1=loader.loadModel("grass1_plane")
        self.grass1.reparentTo(altRender)

        self.grass2=loader.loadModel("grass2_plane")
        self.grass2.reparentTo(altRender)

        self.rock1=loader.loadModel("rock1_plane")
        self.rock1.reparentTo(altRender)

        self.rock2=loader.loadModel("rock2_plane")
        self.rock2.reparentTo(altRender)
     
        self.road1=loader.loadModel("road1_plane")
        self.road1.reparentTo(altRender)  
     
        self.road2=loader.loadModel("road2_plane")
        self.road2.reparentTo(altRender)
      
        self.snow=loader.loadModel("snow_plane")
        self.snow.reparentTo(altRender) 
 
        
        #normal texture
        if(cfg_use_normal_map.getValue ()==1):
            self.grass1N=loader.loadModel("grass1_plane")
            self.grass1N.setTexture(self.grass1N.findTextureStage('Tex20'),loader.loadTexture('grass_normal.jpg'),1)
            self.grass1N.reparentTo(altRenderN)        
            self.grass2N=loader.loadModel("grass2_plane")
            self.grass2N.setTexture(self.grass2N.findTextureStage('Tex20'),loader.loadTexture('grass2_normal.jpg'),1)
            self.grass2N.reparentTo(altRenderN)
            self.rock1N=loader.loadModel("rock1_plane")
            self.rock1N.setTexture(self.rock1N.findTextureStage('Tex20'),loader.loadTexture('rock_normal.jpg'),1)
            self.rock1N.reparentTo(altRenderN)
            self.rock2N=loader.loadModel("rock2_plane")
            self.rock2N.setTexture(self.rock2N.findTextureStage('Tex20'),loader.loadTexture('rock2_normal.jpg'),1)
            self.rock2N.reparentTo(altRenderN)
            self.road1N=loader.loadModel("road1_plane")
            self.road1N.setTexture(self.road1N.findTextureStage('Tex20'),loader.loadTexture('sand_normal.jpg'),1)
            self.road1N.reparentTo(altRenderN)
            self.road2N=loader.loadModel("road2_plane")
            self.road2N.setTexture(self.road2N.findTextureStage('Tex20'),loader.loadTexture('coble_normal.jpg'),1)
            self.road2N.reparentTo(altRenderN)
            self.snowN=loader.loadModel("snow_plane")
            self.snowN.setTexture(self.snowN.findTextureStage('Tex20'),loader.loadTexture('snow_normal.jpg'),1)
            self.snowN.reparentTo(altRenderN)        
        
        #Create a buffer for storing the shadow texture,
        #the higher the buffer size the better quality the shadow.
        if(cfg_use_shadows.getValue ()==1):
            self.shadowBuffer = base.win.makeTextureBuffer("Shadow Buffer",cfg_shadow_size, cfg_shadow_size,shadowTexture, False, fbprops)
            self.shadowBuffer.setClearColorActive(True)
            self.shadowBuffer.setClearColor((0,0,0,1))
            self.shadowCamera = base.makeCamera(self.shadowBuffer)
            self.shadowCamera.reparentTo(render)
            self.shadow_lens = PerspectiveLens()
            self.shadow_lens.setFov(100)
            self.shadow_lens.setNearFar(1,6) 
            self.shadowCamera.node().setLens(self.shadow_lens)
            self.shadowCamera.node().setCameraMask(BitMask32.bit(1)) 
            #Make everything rendered by the shadow camera grey:
            self.initial = NodePath('initial')
            self.initial.setColor(.75,.75,.75,1,1)
            self.initial.setTextureOff(2)
            self.initial.setMaterialOff(2)
            self.initial.setLightOff(2)
            self.shadowCamera.node().setInitialState(self.initial.getState())        
            self.shadowCamera.setP(-90) 
            #self.shadowCamera.node().showFrustum()                   
            
        if(cfg_soft_shadows.getValue()==1):
            self.filters = CommonFilters(self.shadowBuffer,self.shadowCamera)
            self.filters.setBlurSharpen(.2)
            
        if(cfg_use_shadows.getValue ()==1):
            shadowTexture.setWrapU(Texture.WMBorderColor  )
            shadowTexture.setWrapV(Texture.WMBorderColor  )
            shadowTexture.setBorderColor(Vec4(0,0,0,1))                  
            shadow_ts=TextureStage('shadow')
            shadow_ts.setMode(TextureStage.MBlend) 
            self.terrain.projectTexture(shadow_ts , shadowTexture, self.shadowCamera)
        
        if(cfg_use_normal_map.getValue ()==1):
            normal_ts = TextureStage('ts')   
            normal_ts.setMode(TextureStage.MNormal) 
            self.terrain.projectTexture(normal_ts , normalTexture, self.altCam)        
            
        color_ts=TextureStage('color')
        color_ts.setMode(TextureStage.MModulate) 
        self.terrain.projectTexture(color_ts , colorTexture, self.altCam)
        
         
        #fog
        fog=loader.loadTexture('mask7.png')
        fog.setBorderColor(Vec4(1, 1, 1, 0))          
        fog.setWrapU(Texture.WMBorderColor)
        fog.setWrapV(Texture.WMBorderColor)
        fog_ts=TextureStage('ts')
        fog_ts.setMode(TextureStage.MModulate) 
        #self.terrain.projectTexture(fog_ts, fog, self.altCam)    
        
        #light             
        alight = AmbientLight('alight')        
        alnp = render.attachNewNode(alight)
        alight.setColor(Vec4(.3, .3, .35, 1))
        render.setLight(alnp)               
        self.pLight = PointLight('plight')
        self.pLight.setColor(VBase4(.6, .6, .6, 1))
        self.pLight.setAttenuation(Point3(0, 0.1, 0.08))        
        self.pLightNode = self.player.PC.attachNewNode(self.pLight)        
        self.pLightNode.setPos(0,-15,50)
        render.setLight(self.pLightNode)  
        
        #self.spot=Spotlight('spot')        
        #self.spot.setColor(VBase4(.8, .8, .8, 1))
        #self.spot= self.player.PC.attachNewNode(self.spot)
        #self.spot.setP(-90)  
        #self.spot.setPos(0,0,120)        
        #self.spot.node().getLens().setNearFar(100,180)        
        #self.spot.node().getLens().setFov(60)
        #self.spot.node().setShadowCaster(True,1024,1024)    
        #self.spot.node().showFrustum()      
        #render.setLight(self.spot)
        #self.player.PC.setLightOff(self.spot)
        dlight = DirectionalLight('dlight') 
        dlight.setColor(VBase4(.8, .8, .8, 1))        
        dlnp = render.attachNewNode(dlight)
        dlnp.setHpr(0, -90, 0)         
        render.setLight(dlnp)
        
        #collisions
        self.picker = CollisionTraverser()            
        self.pq     = CollisionHandlerQueue()        
        self.pointerGroundRay = CollisionRay()
        self.pointerGroundRay.setOrigin(0,0,1000)
        self.pointerGroundRay.setDirection(0,0,-1)
        self.pointerGroundCol = CollisionNode('pointerRay')
        self.pointerGroundCol.addSolid(self.pointerGroundRay)
        self.pointerGroundCol.setIntoCollideMask(BitMask32(0))
        self.pointerGroundColNp = self.player.PC.attachNewNode(self.pointerGroundCol)                
        self.picker.addCollider(self.pointerGroundColNp, self.pq)
        
        CameraControll(self.player,20, -1, self.lens)
        
        #print "Buffer properties", altBuffer.getFbProperties() 
        #print isinstance(altBuffer, ParasiteBuffer)
        #self.accept('x', altBuffer.saveScreenshot, ['test2.png'])
        
        manager = FilterManager(altBuffer, self.altCam)
        tex = Texture()
        quad = manager.renderSceneInto(colortex=tex)
        quad.setShader(Shader.load("myfilter.sha"))
        quad.setShaderInput("tex", tex)
        quad.setShaderInput("mask", fog)
        
    def update(self, task):
        z=0
        self.picker.traverse(render) 
        if self.pq.getNumEntries() > 0:        
            self.pq.sortEntries()                        
            z=self.pq.getEntry(0).getSurfacePoint(render).getZ()  
        
        x = self.player.getX()
        y = self.player.getY()   
        self.altCam.setPos(x,y,2) 
        
        if(self.useNormal.getValue()==1):    
            self.altCamN.setPos(x,y,2) 
            
        self.player.updateZ(z) 
        self.sky.setPos(x,y,base.camera.getZ(render))
        
        if(self.useShadow.getValue ()==1):
            self.shadowCamera.setPos(x,y-1,z+5)
        
        return task.cont
        
w = World()
run()     

PlayerControll.py

from panda3d.core import *
from direct.showbase.DirectObject import DirectObject
from direct.task import Task



class  PlayerControll(DirectObject): 
    def __init__(self, player,moveSpeed=10, turnSpeed=100, forward_key="w", back_key="s", left_key="a", right_key="d"):
        self.keyMap = {"left":0, "right":0, "forward":0, "back":0}
        self.accept(left_key, self.setKey, ["left",1])
        self.accept(right_key, self.setKey, ["right",1])
        self.accept(forward_key, self.setKey, ["forward",1])
        self.accept(back_key, self.setKey, ["back",1])
        self.accept(left_key+"-up", self.setKey, ["left",0])
        self.accept(right_key+"-up", self.setKey, ["right",0])
        self.accept(forward_key+"-up", self.setKey, ["forward",0])
        self.accept(back_key+"-up", self.setKey, ["back",0])
        self.moveSpeed=moveSpeed
        self.turnSpeed=turnSpeed
        self.player=player
        self.isMoving=False
        taskMgr.add(self.moveTask, 'moveTask',sort=-101)
        
    def setKey(self, key, value):
        self.keyMap[key] = value 
        if(self.keyMap["forward"]+self.keyMap["back"]==0):
            self.player.stop()
            
    
    def moveTask(self, task):
        if (self.keyMap["left"]!=0):
            self.player.turn(globalClock.getDt()*self.turnSpeed)                       
        if (self.keyMap["right"]!=0):
            self.player.turn(-globalClock.getDt()*self.turnSpeed)            
        if (self.keyMap["forward"]!=0):
            self.player.move(globalClock.getDt()*self.moveSpeed)              
        if (self.keyMap["back"]!=0):
            self.player.move(-globalClock.getDt()*self.moveSpeed)              
        return task.cont

PlayerCharacter.py

from panda3d.core import *
from direct.actor.Actor import Actor

class PlayerCharacter():
    def __init__(self, model_name, walk_anim, idle_anim, scale=1, pos=(0, 0, 0)):
        self.PC = Actor(model_name,{"walk": walk_anim, "idle": idle_anim}) 
        self.PC.setBlend(frameBlend = True)        
        self.PC.setPos(pos)
        self.PC.setScale(scale)
        self.PC.reparentTo(render)
        self.PC.loop("idle")                 
    
    def move(self, how_far):
        self.PC.setY(self.PC, -how_far)
        rate=1
        if(how_far<0):
            rate=-1
        self.PC.setPlayRate(rate, "walk")        
        if(self.PC.getCurrentAnim()!="walk"):
            self.PC.loop("walk")
        
    def stop(self):
        self.PC.loop("idle")
        
    def turn(self, how_much):    
        self.PC.setH(self.PC.getH()+ how_much)
        
    def updateZ(self, z):
        self.PC.setZ(z)
    
    def getPos(self):
        return self.PC.getPos()
        
    def getX(self):
        return self.PC.getX()
        
    def getY(self):    
        return self.PC.getY()        
        
    def getZ(self):
        return self.PC.getZ() 

CameraControll.py

from panda3d.core import *
from direct.showbase.DirectObject import DirectObject
from direct.task import Task


    
class  CameraControll(DirectObject):  
    def __init__(self, parent, max_zoom=90, min_zoom=2, terrain_lens=None, offset=(0, -5, .6), speed=200, main_key="mouse3", zoom_in="wheel_up", zoom_out="wheel_down"):
        base.disableMouse()
        base.camera.setPos(offset)
        self.cameraNode = NodePath(PandaNode("cameraNode"))        
        self.cameraNode.reparentTo(render)
        base.camera.reparentTo(self.cameraNode)
        self.parent=parent
        self.isIdle=True
        self.speed=speed
        self.zoomfactor=base.camera.getY()
        self.maxZoom=max_zoom
        self.minZoom=min_zoom
        self.terrain_lens=terrain_lens
        
        self.accept(zoom_in, self.zoom, [1])
        self.accept(zoom_out, self.zoom, [-1])
        self.accept(main_key, self.rotateCamera)
        taskMgr.add(self.cameraTask, 'cameraTask')
    
    def rotateCamera(self):
        if (self.isIdle):            
            centerx =  base.win.getProperties().getXSize()/2
            centery =  base.win.getProperties().getYSize()/2
            base.win.movePointer(0,centerx,centery)
            self.isIdle=False
        else:
            self.isIdle=True
    
    def zoom(self, out):
        self.zoomfactor=self.zoomfactor+out
        if self.zoomfactor<self.minZoom and self.zoomfactor>-self.maxZoom:
            base.camera.setY(base.camera, out)
            if not(self.terrain_lens==None):
                size=-base.camera.getY()
                if(size<6):
                    size=6
                #print size                
                self.terrain_lens.setFilmSize(size, size)
        else:
            self.zoomfactor=self.zoomfactor-out
    
    def cameraTask(self, task):        
        if base.mouseWatcherNode.hasMouse():            
            mpos = base.mouseWatcherNode.getMouse()                              
            if (not self.isIdle):
                self.cameraNode.setH(self.cameraNode.getH()+mpos.getX()*globalClock.getDt()*-self.speed)   
                self.cameraNode.setP(self.cameraNode.getP()+mpos.getY()*globalClock.getDt()*self.speed)
                if self.cameraNode.getP()>40:
                    self.cameraNode.setP(40)
                if self.cameraNode.getP()<-80:
                    self.cameraNode.setP(-80)  
        self.cameraNode.setPos(self.parent.getPos())        
        return task.cont

myfilter.sha

//Cg
 
void vshader(
    float4 vtx_position : POSITION,
    float2 vtx_texcoord0 : TEXCOORD0,
    out float4 l_position : POSITION,
    out float2 l_texcoord0 : TEXCOORD0,
    uniform float4 texpad_tex,
    uniform float4x4 mat_modelproj)
{
    l_position=mul(mat_modelproj, vtx_position);
    l_texcoord0 = vtx_position.xz * texpad_tex.xy + texpad_tex.xy;
}
 
void fshader(float2 l_texcoord0 : TEXCOORD0,
             out float4 o_color : COLOR,
             uniform sampler2D k_tex : TEXUNIT0,
             uniform sampler2D k_mask : TEXUNIT1)
{
    float4 c = tex2D(k_tex, l_texcoord0);
    float4 a = tex2D(k_mask, l_texcoord0);
    
    o_color = float4(c.x, c.y, c.z, a.a);
}

Thanks! you rock!!!