some shader issues

I run this script simulating water reflection, gathered from various samples on these forums:

from pandac.PandaModules import Vec4, TextureStage, ShaderAttrib, \
                TransparencyAttrib, Texture, InternalName, \
                loadPrcFileData, CardMaker, CullFaceAttrib, \
                BitMask32, LMatrix4f, ConfigVariableManager
from direct.actor.Actor import Actor
from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from direct.directutil import Mopath
from direct.interval.MopathInterval import MopathInterval
from direct.gui.DirectDialog import OkDialog

loadPrcFileData("", "model-path $MAIN_DIR/data")
loadPrcFileData("", "show-frame-rate-meter #t")
loadPrcFileData("", "win-size 1024 768")
loadPrcFileData("", "gl-debug #t")
#loadPrcFileData('', 'dump-generated-shaders #t')

if __name__ == '__main__':
    app = ShowBase()
    planeHeight = 2.0  
    transparencyAttrib = TransparencyAttrib.make(TransparencyAttrib.MAlpha)
    ###bufferToTexture
    reflBuf = app.win.makeTextureBuffer("reflection", 512, 512)
    reflTex = reflBuf.getTexture()           
    reflBuf.setClearColor(app.win.getClearColor() - Vec4(0.1, 0.1, 0.1, 0.0))
    reflCam = app.makeCamera(reflBuf)
    reflCam.node().getLens().setFov(app.camLens.getFov())
    reflCam.node().getLens().setNear(app.camLens.getNear())
    reflCam.node().getLens().setFar(app.camLens.getFar())
    reflCamMask = BitMask32(2) 
    reflCam.node().setCameraMask(reflCamMask)
    #reflCam render the (opposite wrt z) scene of render
    reflCam.reparentTo(app.cam)
    #what is rendered by reflCam should have these render attributes
    reflCullAttr = CullFaceAttrib.makeReverse()
    reflShaderAttr = ShaderAttrib.make()
    reflShaderAttr = reflShaderAttr.setShader(app.loader.loadShader('water_reflect.cg'))
    reflShaderAttr = reflShaderAttr.setShaderInput(InternalName.make('h'), planeHeight)
    #
    reflState = app.render.getState()
    reflState = reflState.addAttrib(reflCullAttr)
    reflState = reflState.addAttrib(reflShaderAttr)
    #reflState = reflState.addAttrib(transparencyAttrib)
    reflCam.node().setTagStateKey('reflCam')
    reflCam.node().setTagState('True', reflState) 
    #direct camera state
    dirCamMask = BitMask32(1) 
    app.cam.node().setCameraMask(dirCamMask) 
    app.cam.node().setTagStateKey('dirCam')
    #direct
    directShaderAttr = ShaderAttrib.make()
    directShaderAttr = directShaderAttr.setShader(app.loader.loadShader('water_direct.cg'))
    directState = app.render.getState()
    directState = directState.addAttrib(directShaderAttr)
    #directState = directState.addAttrib(transparencyAttrib)
    app.cam.node().setTagState('direct', directState)    
    ###environment
    # skybox
    skybox = app.loader.loadModel('skybox')
    # make big enough to cover whole terrain, else there'll be problems with the water reflections
    skybox.setZ(0)
    skybox.setScale(100)
    skybox.setBin('background', 1)
    skybox.setDepthWrite(0)
    skybox.setLightOff()
    skybox.reparentTo(app.render)
    #
    #plane
    cm = CardMaker("plane")
    cm.setFrame(-1, 1, -1, 1)
    plane = app.render.attachNewNode(cm.generate())
    plane.setP(-90.0)
    plane.setZ(planeHeight)
    plane.setScale(100.0)
    # reflection texture, created in realtime by the 'water camera'
    reflTex.setWrapU(Texture.WMClamp)
    reflTex.setWrapV(Texture.WMClamp)
    ts0 = TextureStage('reflection')
    plane.setTexture(ts0, reflTex)
    # distortion texture
    tex1 = app.loader.loadTexture('maps/water.png')
    ts1 = TextureStage('distortion')
    plane.setTexture(ts1, tex1)
    #set render attributes directly
    #set shader for plane
    plane.setShader(app.loader.loadShader('water_projective.cg'))
    # vx, vy, scale, skip
    plane.setShaderInput('wateranim', Vec4(0.03, -0.03, 24.0, 0))
    # offset, strength, refraction factor (0=perfect mirror, 1=total refraction), refractivity
    plane.setShaderInput('waterdistort', Vec4(0.0, 4.0, 0.4, 0.45))
    plane.setShaderInput('time', 0.0)
    
    def updateShadersInputs(task):
        plane.setShaderInput('time', task.time)
        return Task.cont
    
    app.taskMgr.add(updateShadersInputs, "updateShadersInputs")
    #set transparency for plane
    plane.setAttrib(transparencyAttrib)
    #hide plane during reflection pass
    plane.hide(reflCamMask)  
    #panda actor
    pathScale = 15.0
    pandaActor = Actor("panda", {"anim": "panda-walk"})
    pandaActor.setScale(0.5 / pathScale)
    pandaPlatform = app.render.attachNewNode("pandaPlatform")
    pandaActor.reparentTo(pandaPlatform)
    #
    motionPath = Mopath.Mopath()
    motionPath.loadFile("mopath")
    motionPath.fFaceForward = True
    pandaPlatform.setPos(0, 40, 0)
    pandaPlatform.setScale(pathScale)
    # panda animation
    pandaActor.loop("anim", restart=0)
    pandaInterval = MopathInterval(motionPath, pandaActor, name="pandaInterval")
    pandaInterval.loop(playRate= -0.01)
    #    
    app.render.setTag("reflCam", "True")
    app.camera.setPos(0.0, -60.0, 10.0)
    app.camera.lookAt(0.0, 20.0, 0.0)
    mat = LMatrix4f(app.camera.getTransform().getMat())
    mat.invertInPlace()
    app.mouseInterfaceNode.setMat(mat)
    #
    okDialog = OkDialog(text="Water reflection test", command=lambda(arg): okDialog.cleanup())
    #
    app.run()

But it gives repeatedly these warnings:

...
:display:gsg:glgsg(warning): Program undefined behavior warning: Sampler object 3 is bound to non-depth texture reflection, yet it is used with a program that uses a shadow sampler. This is undefined behavior.
:display:gsg:glgsg(warning): Program undefined behavior warning: Sampler object 4 is bound to non-depth texture water, yet it is used with a program that uses a shadow sampler. This is undefined behavior.
...

I tested it on linux debian 8 (jessie) with “GeForce GTX 970” and " GeForce GTX 770" gpus with NVIDIA proprietary driver (ver. 349.16 - GLX ver. 1.4, OpenGL 4.5.0).
I tried to compile the custom shaders with cgc reporting neither errors nor warnings.
I attached the complete sample.
water_reflection.zip (1.24 MB)

I think the warning comes from using tex2Dproj in the shaders. In Cg that’s the only function to do both texture projection and shadow lookup (if you give it a value to compare). On my ATI card I get no warnings, but then again my ATI card don’t seem to know anything about filtering shadows.

You could try replacing tex2Dproj(texture, coords) with tex2D(texture, coords.xy/coords.w), but I’m not 100% sure that will work.

It’s a Cg quirk. You have to use tex2Dproj with a float3 instead of a float4, otherwise it secretly switches to a version that does a shadow comparison even if you’re not actually passing a sampler2DShadow.

So, try passing l_texcoord1.xyz instead of l_texcoord1 to the tex2Dproj function.

Sheesh, NVIDIA.

Thanks.
I casted to float3 second argument of tex2Dproj and those warnings went away, but another one appears on startup:

:display:gsg:glgsg(warning): Program/shader state performance warning: Fragment Shader is going to be recompiled because the shader key based on GL state mismatches.

It isn’t really your fault; it has to do with the way the driver implements a certain feature.

It happens when a particular render state feature isn’t implemented in fixed-function by the driver, but it is implemented by injecting code into the active shader. This happens for instance when you have the same shader applied to an object without alpha testing, and one with alpha testing - the driver may implement alpha testing by injecting appropriate code into the active shader, and so it warns that it’s not optimally efficient because it has to compile the shader twice: one for the object with alpha testing, and one for the object without.

It’s usually nothing to worry about unless you get a lot of it.

Sorry (my fault) but I didn’t noticed that, by casting to float3 into shader water_projective.cg, waves disappeared while reflection was still present.
So, after reading tex2Dproj documentation (http.developer.nvidia.com/Cg/tex2Dproj.html), I tried to use swizzling by taking the first,second and fourth components (.rga or .xyw) of second argument of tex2Dproj, and this solved the problem.

Anyway thanks for explanation. The warning appears only once so it’d be harmless.

BTW I’m trying to run samples from the still worth (imho) demomaster app, I corrected some shader warns due to tex2Dproj.
But there are several demos having more severe issues, I think related to shaders:
demo_pool, for example, writes continuously this error

...
:display:gsg:glgsg(error): GL_INVALID_OPERATION error generated. Depth formats do not match.
...

with a black output window. I commented out the setBloomShader method call, having the scene shown but, obviously, without any bloom effect.
The same error and black window is shown by several other demos (and some of them have other types of errors/warnings printed out too).
The demomaster code i use is rather old (originally got from code.google.com/p/pandademomast … loads/list), but with older panda versions (and older gpus) it worked quite well.